From 4ccac59932f2ca3ebc9ba30fb0bc0aa8aac0d630 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 8 Nov 2016 21:31:34 +0100 Subject: [PATCH 001/180] debian: update changelog --- debian/changelog | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3c88a21e..2efd65e8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,14 @@ -i3-wm (4.12.1-1) unstable; urgency=medium +i3-wm (4.13.1-1) unstable; urgency=medium * UNRELEASED - -- Michael Stapelberg Fri, 01 Apr 2016 16:34:35 +0200 + -- Michael Stapelberg Tue, 08 Nov 2016 21:31:13 +0100 + +i3-wm (4.13-1) unstable; urgency=medium + + * New upstream release. + + -- Michael Stapelberg Tue, 08 Nov 2016 19:02:16 +0100 i3-wm (4.12-2) unstable; urgency=medium From fff3f79da9a87a1f790c6328f6615422f2b69b47 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 8 Nov 2016 13:46:43 -0800 Subject: [PATCH 002/180] switch to clang-format-3.8 (#2547) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://llvm.org/bugs/show_bug.cgi?id=30353 was filed for the unintended line break between in e.g. “TAILQ_ENTRY(foo)\nbar;”. Until that’s fixed or a workaround is known, we’ll live with line breaks. To make it a bit easier for readers to see what’s going on, I added extra line breaks around each such struct member/variable definition, so that they at least visually are a single unit. fixes #2174 --- .clang-format | 1 + i3-input/keysym2ucs.c | 1548 +++++++++++----------- i3bar/include/common.h | 6 +- i3bar/include/configuration.h | 16 +- i3bar/include/outputs.h | 3 +- i3bar/include/trayclients.h | 3 +- i3bar/include/workspaces.h | 3 +- include/configuration.h | 21 +- include/data.h | 70 +- include/ipc.h | 3 +- include/queue.h | 5 +- src/commands.c | 4 +- src/con.c | 7 +- src/config_parser.c | 2 +- src/ipc.c | 3 +- src/load_layout.c | 4 +- src/match.c | 4 +- src/restore_layout.c | 3 +- src/x.c | 20 +- travis/check-formatting.sh | 2 +- travis/travis-base-386.Dockerfile | 4 +- travis/travis-base-ubuntu-386.Dockerfile | 4 +- travis/travis-base-ubuntu.Dockerfile | 4 +- travis/travis-base.Dockerfile | 4 +- 24 files changed, 907 insertions(+), 837 deletions(-) diff --git a/.clang-format b/.clang-format index 1d840132..6e49d835 100644 --- a/.clang-format +++ b/.clang-format @@ -8,3 +8,4 @@ IndentWidth: 4 PointerBindsToType: false ColumnLimit: 0 SpaceBeforeParens: ControlStatements +SortIncludes: false diff --git a/i3-input/keysym2ucs.c b/i3-input/keysym2ucs.c index b8e45a14..52bdc044 100644 --- a/i3-input/keysym2ucs.c +++ b/i3-input/keysym2ucs.c @@ -38,780 +38,780 @@ struct codepair { unsigned short keysym; unsigned short ucs; } keysymtab[] = { - {0x01a1, 0x0104}, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ - {0x01a2, 0x02d8}, /* breve ˘ BREVE */ - {0x01a3, 0x0141}, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ - {0x01a5, 0x013d}, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ - {0x01a6, 0x015a}, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ - {0x01a9, 0x0160}, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ - {0x01aa, 0x015e}, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ - {0x01ab, 0x0164}, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ - {0x01ac, 0x0179}, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ - {0x01ae, 0x017d}, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ - {0x01af, 0x017b}, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ - {0x01b1, 0x0105}, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ - {0x01b2, 0x02db}, /* ogonek ˛ OGONEK */ - {0x01b3, 0x0142}, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ - {0x01b5, 0x013e}, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ - {0x01b6, 0x015b}, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ - {0x01b7, 0x02c7}, /* caron ˇ CARON */ - {0x01b9, 0x0161}, /* scaron š LATIN SMALL LETTER S WITH CARON */ - {0x01ba, 0x015f}, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ - {0x01bb, 0x0165}, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ - {0x01bc, 0x017a}, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ - {0x01bd, 0x02dd}, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ - {0x01be, 0x017e}, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ - {0x01bf, 0x017c}, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ - {0x01c0, 0x0154}, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ - {0x01c3, 0x0102}, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ - {0x01c5, 0x0139}, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ - {0x01c6, 0x0106}, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ - {0x01c8, 0x010c}, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ - {0x01ca, 0x0118}, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ - {0x01cc, 0x011a}, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ - {0x01cf, 0x010e}, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ - {0x01d0, 0x0110}, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ - {0x01d1, 0x0143}, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ - {0x01d2, 0x0147}, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ - {0x01d5, 0x0150}, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ - {0x01d8, 0x0158}, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ - {0x01d9, 0x016e}, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ - {0x01db, 0x0170}, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ - {0x01de, 0x0162}, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ - {0x01e0, 0x0155}, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ - {0x01e3, 0x0103}, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ - {0x01e5, 0x013a}, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ - {0x01e6, 0x0107}, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ - {0x01e8, 0x010d}, /* ccaron č LATIN SMALL LETTER C WITH CARON */ - {0x01ea, 0x0119}, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ - {0x01ec, 0x011b}, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ - {0x01ef, 0x010f}, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ - {0x01f0, 0x0111}, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ - {0x01f1, 0x0144}, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ - {0x01f2, 0x0148}, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ - {0x01f5, 0x0151}, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ - {0x01f8, 0x0159}, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ - {0x01f9, 0x016f}, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ - {0x01fb, 0x0171}, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ - {0x01fe, 0x0163}, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ - {0x01ff, 0x02d9}, /* abovedot ˙ DOT ABOVE */ - {0x02a1, 0x0126}, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ - {0x02a6, 0x0124}, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ - {0x02a9, 0x0130}, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ - {0x02ab, 0x011e}, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ - {0x02ac, 0x0134}, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ - {0x02b1, 0x0127}, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ - {0x02b6, 0x0125}, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ - {0x02b9, 0x0131}, /* idotless ı LATIN SMALL LETTER DOTLESS I */ - {0x02bb, 0x011f}, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ - {0x02bc, 0x0135}, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ - {0x02c5, 0x010a}, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ - {0x02c6, 0x0108}, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ - {0x02d5, 0x0120}, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ - {0x02d8, 0x011c}, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ - {0x02dd, 0x016c}, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ - {0x02de, 0x015c}, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ - {0x02e5, 0x010b}, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ - {0x02e6, 0x0109}, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ - {0x02f5, 0x0121}, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ - {0x02f8, 0x011d}, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ - {0x02fd, 0x016d}, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ - {0x02fe, 0x015d}, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ - {0x03a2, 0x0138}, /* kra ĸ LATIN SMALL LETTER KRA */ - {0x03a3, 0x0156}, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ - {0x03a5, 0x0128}, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ - {0x03a6, 0x013b}, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ - {0x03aa, 0x0112}, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ - {0x03ab, 0x0122}, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ - {0x03ac, 0x0166}, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ - {0x03b3, 0x0157}, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ - {0x03b5, 0x0129}, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ - {0x03b6, 0x013c}, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ - {0x03ba, 0x0113}, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ - {0x03bb, 0x0123}, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ - {0x03bc, 0x0167}, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ - {0x03bd, 0x014a}, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ - {0x03bf, 0x014b}, /* eng ŋ LATIN SMALL LETTER ENG */ - {0x03c0, 0x0100}, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ - {0x03c7, 0x012e}, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ - {0x03cc, 0x0116}, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ - {0x03cf, 0x012a}, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ - {0x03d1, 0x0145}, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ - {0x03d2, 0x014c}, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ - {0x03d3, 0x0136}, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ - {0x03d9, 0x0172}, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ - {0x03dd, 0x0168}, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ - {0x03de, 0x016a}, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ - {0x03e0, 0x0101}, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ - {0x03e7, 0x012f}, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ - {0x03ec, 0x0117}, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ - {0x03ef, 0x012b}, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ - {0x03f1, 0x0146}, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ - {0x03f2, 0x014d}, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ - {0x03f3, 0x0137}, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ - {0x03f9, 0x0173}, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ - {0x03fd, 0x0169}, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ - {0x03fe, 0x016b}, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ - {0x047e, 0x203e}, /* overline ‾ OVERLINE */ - {0x04a1, 0x3002}, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ - {0x04a2, 0x300c}, /* kana_openingbracket 「 LEFT CORNER BRACKET */ - {0x04a3, 0x300d}, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ - {0x04a4, 0x3001}, /* kana_comma 、 IDEOGRAPHIC COMMA */ - {0x04a5, 0x30fb}, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ - {0x04a6, 0x30f2}, /* kana_WO ヲ KATAKANA LETTER WO */ - {0x04a7, 0x30a1}, /* kana_a ァ KATAKANA LETTER SMALL A */ - {0x04a8, 0x30a3}, /* kana_i ィ KATAKANA LETTER SMALL I */ - {0x04a9, 0x30a5}, /* kana_u ゥ KATAKANA LETTER SMALL U */ - {0x04aa, 0x30a7}, /* kana_e ェ KATAKANA LETTER SMALL E */ - {0x04ab, 0x30a9}, /* kana_o ォ KATAKANA LETTER SMALL O */ - {0x04ac, 0x30e3}, /* kana_ya ャ KATAKANA LETTER SMALL YA */ - {0x04ad, 0x30e5}, /* kana_yu ュ KATAKANA LETTER SMALL YU */ - {0x04ae, 0x30e7}, /* kana_yo ョ KATAKANA LETTER SMALL YO */ - {0x04af, 0x30c3}, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ - {0x04b0, 0x30fc}, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - {0x04b1, 0x30a2}, /* kana_A ア KATAKANA LETTER A */ - {0x04b2, 0x30a4}, /* kana_I イ KATAKANA LETTER I */ - {0x04b3, 0x30a6}, /* kana_U ウ KATAKANA LETTER U */ - {0x04b4, 0x30a8}, /* kana_E エ KATAKANA LETTER E */ - {0x04b5, 0x30aa}, /* kana_O オ KATAKANA LETTER O */ - {0x04b6, 0x30ab}, /* kana_KA カ KATAKANA LETTER KA */ - {0x04b7, 0x30ad}, /* kana_KI キ KATAKANA LETTER KI */ - {0x04b8, 0x30af}, /* kana_KU ク KATAKANA LETTER KU */ - {0x04b9, 0x30b1}, /* kana_KE ケ KATAKANA LETTER KE */ - {0x04ba, 0x30b3}, /* kana_KO コ KATAKANA LETTER KO */ - {0x04bb, 0x30b5}, /* kana_SA サ KATAKANA LETTER SA */ - {0x04bc, 0x30b7}, /* kana_SHI シ KATAKANA LETTER SI */ - {0x04bd, 0x30b9}, /* kana_SU ス KATAKANA LETTER SU */ - {0x04be, 0x30bb}, /* kana_SE セ KATAKANA LETTER SE */ - {0x04bf, 0x30bd}, /* kana_SO ソ KATAKANA LETTER SO */ - {0x04c0, 0x30bf}, /* kana_TA タ KATAKANA LETTER TA */ - {0x04c1, 0x30c1}, /* kana_CHI チ KATAKANA LETTER TI */ - {0x04c2, 0x30c4}, /* kana_TSU ツ KATAKANA LETTER TU */ - {0x04c3, 0x30c6}, /* kana_TE テ KATAKANA LETTER TE */ - {0x04c4, 0x30c8}, /* kana_TO ト KATAKANA LETTER TO */ - {0x04c5, 0x30ca}, /* kana_NA ナ KATAKANA LETTER NA */ - {0x04c6, 0x30cb}, /* kana_NI ニ KATAKANA LETTER NI */ - {0x04c7, 0x30cc}, /* kana_NU ヌ KATAKANA LETTER NU */ - {0x04c8, 0x30cd}, /* kana_NE ネ KATAKANA LETTER NE */ - {0x04c9, 0x30ce}, /* kana_NO ノ KATAKANA LETTER NO */ - {0x04ca, 0x30cf}, /* kana_HA ハ KATAKANA LETTER HA */ - {0x04cb, 0x30d2}, /* kana_HI ヒ KATAKANA LETTER HI */ - {0x04cc, 0x30d5}, /* kana_FU フ KATAKANA LETTER HU */ - {0x04cd, 0x30d8}, /* kana_HE ヘ KATAKANA LETTER HE */ - {0x04ce, 0x30db}, /* kana_HO ホ KATAKANA LETTER HO */ - {0x04cf, 0x30de}, /* kana_MA マ KATAKANA LETTER MA */ - {0x04d0, 0x30df}, /* kana_MI ミ KATAKANA LETTER MI */ - {0x04d1, 0x30e0}, /* kana_MU ム KATAKANA LETTER MU */ - {0x04d2, 0x30e1}, /* kana_ME メ KATAKANA LETTER ME */ - {0x04d3, 0x30e2}, /* kana_MO モ KATAKANA LETTER MO */ - {0x04d4, 0x30e4}, /* kana_YA ヤ KATAKANA LETTER YA */ - {0x04d5, 0x30e6}, /* kana_YU ユ KATAKANA LETTER YU */ - {0x04d6, 0x30e8}, /* kana_YO ヨ KATAKANA LETTER YO */ - {0x04d7, 0x30e9}, /* kana_RA ラ KATAKANA LETTER RA */ - {0x04d8, 0x30ea}, /* kana_RI リ KATAKANA LETTER RI */ - {0x04d9, 0x30eb}, /* kana_RU ル KATAKANA LETTER RU */ - {0x04da, 0x30ec}, /* kana_RE レ KATAKANA LETTER RE */ - {0x04db, 0x30ed}, /* kana_RO ロ KATAKANA LETTER RO */ - {0x04dc, 0x30ef}, /* kana_WA ワ KATAKANA LETTER WA */ - {0x04dd, 0x30f3}, /* kana_N ン KATAKANA LETTER N */ - {0x04de, 0x309b}, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ - {0x04df, 0x309c}, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - {0x05ac, 0x060c}, /* Arabic_comma ، ARABIC COMMA */ - {0x05bb, 0x061b}, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ - {0x05bf, 0x061f}, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ - {0x05c1, 0x0621}, /* Arabic_hamza ء ARABIC LETTER HAMZA */ - {0x05c2, 0x0622}, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ - {0x05c3, 0x0623}, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ - {0x05c4, 0x0624}, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ - {0x05c5, 0x0625}, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ - {0x05c6, 0x0626}, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ - {0x05c7, 0x0627}, /* Arabic_alef ا ARABIC LETTER ALEF */ - {0x05c8, 0x0628}, /* Arabic_beh ب ARABIC LETTER BEH */ - {0x05c9, 0x0629}, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ - {0x05ca, 0x062a}, /* Arabic_teh ت ARABIC LETTER TEH */ - {0x05cb, 0x062b}, /* Arabic_theh ث ARABIC LETTER THEH */ - {0x05cc, 0x062c}, /* Arabic_jeem ج ARABIC LETTER JEEM */ - {0x05cd, 0x062d}, /* Arabic_hah ح ARABIC LETTER HAH */ - {0x05ce, 0x062e}, /* Arabic_khah خ ARABIC LETTER KHAH */ - {0x05cf, 0x062f}, /* Arabic_dal د ARABIC LETTER DAL */ - {0x05d0, 0x0630}, /* Arabic_thal ذ ARABIC LETTER THAL */ - {0x05d1, 0x0631}, /* Arabic_ra ر ARABIC LETTER REH */ - {0x05d2, 0x0632}, /* Arabic_zain ز ARABIC LETTER ZAIN */ - {0x05d3, 0x0633}, /* Arabic_seen س ARABIC LETTER SEEN */ - {0x05d4, 0x0634}, /* Arabic_sheen ش ARABIC LETTER SHEEN */ - {0x05d5, 0x0635}, /* Arabic_sad ص ARABIC LETTER SAD */ - {0x05d6, 0x0636}, /* Arabic_dad ض ARABIC LETTER DAD */ - {0x05d7, 0x0637}, /* Arabic_tah ط ARABIC LETTER TAH */ - {0x05d8, 0x0638}, /* Arabic_zah ظ ARABIC LETTER ZAH */ - {0x05d9, 0x0639}, /* Arabic_ain ع ARABIC LETTER AIN */ - {0x05da, 0x063a}, /* Arabic_ghain غ ARABIC LETTER GHAIN */ - {0x05e0, 0x0640}, /* Arabic_tatweel ـ ARABIC TATWEEL */ - {0x05e1, 0x0641}, /* Arabic_feh ف ARABIC LETTER FEH */ - {0x05e2, 0x0642}, /* Arabic_qaf ق ARABIC LETTER QAF */ - {0x05e3, 0x0643}, /* Arabic_kaf ك ARABIC LETTER KAF */ - {0x05e4, 0x0644}, /* Arabic_lam ل ARABIC LETTER LAM */ - {0x05e5, 0x0645}, /* Arabic_meem م ARABIC LETTER MEEM */ - {0x05e6, 0x0646}, /* Arabic_noon ن ARABIC LETTER NOON */ - {0x05e7, 0x0647}, /* Arabic_ha ه ARABIC LETTER HEH */ - {0x05e8, 0x0648}, /* Arabic_waw و ARABIC LETTER WAW */ - {0x05e9, 0x0649}, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ - {0x05ea, 0x064a}, /* Arabic_yeh ي ARABIC LETTER YEH */ - {0x05eb, 0x064b}, /* Arabic_fathatan ً ARABIC FATHATAN */ - {0x05ec, 0x064c}, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ - {0x05ed, 0x064d}, /* Arabic_kasratan ٍ ARABIC KASRATAN */ - {0x05ee, 0x064e}, /* Arabic_fatha َ ARABIC FATHA */ - {0x05ef, 0x064f}, /* Arabic_damma ُ ARABIC DAMMA */ - {0x05f0, 0x0650}, /* Arabic_kasra ِ ARABIC KASRA */ - {0x05f1, 0x0651}, /* Arabic_shadda ّ ARABIC SHADDA */ - {0x05f2, 0x0652}, /* Arabic_sukun ْ ARABIC SUKUN */ - {0x06a1, 0x0452}, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ - {0x06a2, 0x0453}, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ - {0x06a3, 0x0451}, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ - {0x06a4, 0x0454}, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ - {0x06a5, 0x0455}, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ - {0x06a6, 0x0456}, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ - {0x06a7, 0x0457}, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ - {0x06a8, 0x0458}, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ - {0x06a9, 0x0459}, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ - {0x06aa, 0x045a}, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ - {0x06ab, 0x045b}, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ - {0x06ac, 0x045c}, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ - /* 0x06ad Ukrainian_ghe_with_upturn ? ??? */ - {0x06ae, 0x045e}, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ - {0x06af, 0x045f}, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ - {0x06b0, 0x2116}, /* numerosign № NUMERO SIGN */ - {0x06b1, 0x0402}, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ - {0x06b2, 0x0403}, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ - {0x06b3, 0x0401}, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ - {0x06b4, 0x0404}, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ - {0x06b5, 0x0405}, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ - {0x06b6, 0x0406}, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ - {0x06b7, 0x0407}, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ - {0x06b8, 0x0408}, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ - {0x06b9, 0x0409}, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ - {0x06ba, 0x040a}, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ - {0x06bb, 0x040b}, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ - {0x06bc, 0x040c}, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ - /* 0x06bd Ukrainian_GHE_WITH_UPTURN ? ??? */ - {0x06be, 0x040e}, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ - {0x06bf, 0x040f}, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ - {0x06c0, 0x044e}, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ - {0x06c1, 0x0430}, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ - {0x06c2, 0x0431}, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ - {0x06c3, 0x0446}, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ - {0x06c4, 0x0434}, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ - {0x06c5, 0x0435}, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ - {0x06c6, 0x0444}, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ - {0x06c7, 0x0433}, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ - {0x06c8, 0x0445}, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ - {0x06c9, 0x0438}, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ - {0x06ca, 0x0439}, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ - {0x06cb, 0x043a}, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ - {0x06cc, 0x043b}, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ - {0x06cd, 0x043c}, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ - {0x06ce, 0x043d}, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ - {0x06cf, 0x043e}, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ - {0x06d0, 0x043f}, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ - {0x06d1, 0x044f}, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ - {0x06d2, 0x0440}, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ - {0x06d3, 0x0441}, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ - {0x06d4, 0x0442}, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ - {0x06d5, 0x0443}, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ - {0x06d6, 0x0436}, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ - {0x06d7, 0x0432}, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ - {0x06d8, 0x044c}, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ - {0x06d9, 0x044b}, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ - {0x06da, 0x0437}, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ - {0x06db, 0x0448}, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ - {0x06dc, 0x044d}, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ - {0x06dd, 0x0449}, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ - {0x06de, 0x0447}, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ - {0x06df, 0x044a}, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ - {0x06e0, 0x042e}, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ - {0x06e1, 0x0410}, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ - {0x06e2, 0x0411}, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ - {0x06e3, 0x0426}, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ - {0x06e4, 0x0414}, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ - {0x06e5, 0x0415}, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ - {0x06e6, 0x0424}, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ - {0x06e7, 0x0413}, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ - {0x06e8, 0x0425}, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ - {0x06e9, 0x0418}, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ - {0x06ea, 0x0419}, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ - {0x06eb, 0x041a}, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ - {0x06ec, 0x041b}, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ - {0x06ed, 0x041c}, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ - {0x06ee, 0x041d}, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ - {0x06ef, 0x041e}, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ - {0x06f0, 0x041f}, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ - {0x06f1, 0x042f}, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ - {0x06f2, 0x0420}, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ - {0x06f3, 0x0421}, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ - {0x06f4, 0x0422}, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ - {0x06f5, 0x0423}, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ - {0x06f6, 0x0416}, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ - {0x06f7, 0x0412}, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ - {0x06f8, 0x042c}, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ - {0x06f9, 0x042b}, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ - {0x06fa, 0x0417}, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ - {0x06fb, 0x0428}, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ - {0x06fc, 0x042d}, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ - {0x06fd, 0x0429}, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ - {0x06fe, 0x0427}, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ - {0x06ff, 0x042a}, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ - {0x07a1, 0x0386}, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ - {0x07a2, 0x0388}, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ - {0x07a3, 0x0389}, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ - {0x07a4, 0x038a}, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ - {0x07a5, 0x03aa}, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ - {0x07a7, 0x038c}, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ - {0x07a8, 0x038e}, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ - {0x07a9, 0x03ab}, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ - {0x07ab, 0x038f}, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ - {0x07ae, 0x0385}, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ - {0x07af, 0x2015}, /* Greek_horizbar ― HORIZONTAL BAR */ - {0x07b1, 0x03ac}, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ - {0x07b2, 0x03ad}, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ - {0x07b3, 0x03ae}, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ - {0x07b4, 0x03af}, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ - {0x07b5, 0x03ca}, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ - {0x07b6, 0x0390}, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ - {0x07b7, 0x03cc}, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ - {0x07b8, 0x03cd}, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ - {0x07b9, 0x03cb}, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ - {0x07ba, 0x03b0}, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ - {0x07bb, 0x03ce}, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ - {0x07c1, 0x0391}, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ - {0x07c2, 0x0392}, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ - {0x07c3, 0x0393}, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ - {0x07c4, 0x0394}, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ - {0x07c5, 0x0395}, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ - {0x07c6, 0x0396}, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ - {0x07c7, 0x0397}, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ - {0x07c8, 0x0398}, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ - {0x07c9, 0x0399}, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ - {0x07ca, 0x039a}, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ - {0x07cb, 0x039b}, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ - {0x07cc, 0x039c}, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ - {0x07cd, 0x039d}, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ - {0x07ce, 0x039e}, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ - {0x07cf, 0x039f}, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ - {0x07d0, 0x03a0}, /* Greek_PI Π GREEK CAPITAL LETTER PI */ - {0x07d1, 0x03a1}, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ - {0x07d2, 0x03a3}, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ - {0x07d4, 0x03a4}, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ - {0x07d5, 0x03a5}, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ - {0x07d6, 0x03a6}, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ - {0x07d7, 0x03a7}, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ - {0x07d8, 0x03a8}, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ - {0x07d9, 0x03a9}, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ - {0x07e1, 0x03b1}, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ - {0x07e2, 0x03b2}, /* Greek_beta β GREEK SMALL LETTER BETA */ - {0x07e3, 0x03b3}, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ - {0x07e4, 0x03b4}, /* Greek_delta δ GREEK SMALL LETTER DELTA */ - {0x07e5, 0x03b5}, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ - {0x07e6, 0x03b6}, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ - {0x07e7, 0x03b7}, /* Greek_eta η GREEK SMALL LETTER ETA */ - {0x07e8, 0x03b8}, /* Greek_theta θ GREEK SMALL LETTER THETA */ - {0x07e9, 0x03b9}, /* Greek_iota ι GREEK SMALL LETTER IOTA */ - {0x07ea, 0x03ba}, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ - {0x07eb, 0x03bb}, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ - {0x07ec, 0x03bc}, /* Greek_mu μ GREEK SMALL LETTER MU */ - {0x07ed, 0x03bd}, /* Greek_nu ν GREEK SMALL LETTER NU */ - {0x07ee, 0x03be}, /* Greek_xi ξ GREEK SMALL LETTER XI */ - {0x07ef, 0x03bf}, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ - {0x07f0, 0x03c0}, /* Greek_pi π GREEK SMALL LETTER PI */ - {0x07f1, 0x03c1}, /* Greek_rho ρ GREEK SMALL LETTER RHO */ - {0x07f2, 0x03c3}, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ - {0x07f3, 0x03c2}, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ - {0x07f4, 0x03c4}, /* Greek_tau τ GREEK SMALL LETTER TAU */ - {0x07f5, 0x03c5}, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ - {0x07f6, 0x03c6}, /* Greek_phi φ GREEK SMALL LETTER PHI */ - {0x07f7, 0x03c7}, /* Greek_chi χ GREEK SMALL LETTER CHI */ - {0x07f8, 0x03c8}, /* Greek_psi ψ GREEK SMALL LETTER PSI */ - {0x07f9, 0x03c9}, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ - /* 0x08a1 leftradical ? ??? */ - /* 0x08a2 topleftradical ? ??? */ - /* 0x08a3 horizconnector ? ??? */ - {0x08a4, 0x2320}, /* topintegral ⌠ TOP HALF INTEGRAL */ - {0x08a5, 0x2321}, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ - {0x08a6, 0x2502}, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ - /* 0x08a7 topleftsqbracket ? ??? */ - /* 0x08a8 botleftsqbracket ? ??? */ - /* 0x08a9 toprightsqbracket ? ??? */ - /* 0x08aa botrightsqbracket ? ??? */ - /* 0x08ab topleftparens ? ??? */ - /* 0x08ac botleftparens ? ??? */ - /* 0x08ad toprightparens ? ??? */ - /* 0x08ae botrightparens ? ??? */ - /* 0x08af leftmiddlecurlybrace ? ??? */ - /* 0x08b0 rightmiddlecurlybrace ? ??? */ - /* 0x08b1 topleftsummation ? ??? */ - /* 0x08b2 botleftsummation ? ??? */ - /* 0x08b3 topvertsummationconnector ? ??? */ - /* 0x08b4 botvertsummationconnector ? ??? */ - /* 0x08b5 toprightsummation ? ??? */ - /* 0x08b6 botrightsummation ? ??? */ - /* 0x08b7 rightmiddlesummation ? ??? */ - {0x08bc, 0x2264}, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ - {0x08bd, 0x2260}, /* notequal ≠ NOT EQUAL TO */ - {0x08be, 0x2265}, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ - {0x08bf, 0x222b}, /* integral ∫ INTEGRAL */ - {0x08c0, 0x2234}, /* therefore ∴ THEREFORE */ - {0x08c1, 0x221d}, /* variation ∝ PROPORTIONAL TO */ - {0x08c2, 0x221e}, /* infinity ∞ INFINITY */ - {0x08c5, 0x2207}, /* nabla ∇ NABLA */ - {0x08c8, 0x2245}, /* approximate ≅ APPROXIMATELY EQUAL TO */ - /* 0x08c9 similarequal ? ??? */ - {0x08cd, 0x21d4}, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ - {0x08ce, 0x21d2}, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ - {0x08cf, 0x2261}, /* identical ≡ IDENTICAL TO */ - {0x08d6, 0x221a}, /* radical √ SQUARE ROOT */ - {0x08da, 0x2282}, /* includedin ⊂ SUBSET OF */ - {0x08db, 0x2283}, /* includes ⊃ SUPERSET OF */ - {0x08dc, 0x2229}, /* intersection ∩ INTERSECTION */ - {0x08dd, 0x222a}, /* union ∪ UNION */ - {0x08de, 0x2227}, /* logicaland ∧ LOGICAL AND */ - {0x08df, 0x2228}, /* logicalor ∨ LOGICAL OR */ - {0x08ef, 0x2202}, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ - {0x08f6, 0x0192}, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ - {0x08fb, 0x2190}, /* leftarrow ← LEFTWARDS ARROW */ - {0x08fc, 0x2191}, /* uparrow ↑ UPWARDS ARROW */ - {0x08fd, 0x2192}, /* rightarrow → RIGHTWARDS ARROW */ - {0x08fe, 0x2193}, /* downarrow ↓ DOWNWARDS ARROW */ - {0x09df, 0x2422}, /* blank ␢ BLANK SYMBOL */ - {0x09e0, 0x25c6}, /* soliddiamond ◆ BLACK DIAMOND */ - {0x09e1, 0x2592}, /* checkerboard ▒ MEDIUM SHADE */ - {0x09e2, 0x2409}, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ - {0x09e3, 0x240c}, /* ff ␌ SYMBOL FOR FORM FEED */ - {0x09e4, 0x240d}, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ - {0x09e5, 0x240a}, /* lf ␊ SYMBOL FOR LINE FEED */ - {0x09e8, 0x2424}, /* nl ␤ SYMBOL FOR NEWLINE */ - {0x09e9, 0x240b}, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ - {0x09ea, 0x2518}, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ - {0x09eb, 0x2510}, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ - {0x09ec, 0x250c}, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ - {0x09ed, 0x2514}, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ - {0x09ee, 0x253c}, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ - /* 0x09ef horizlinescan1 ? ??? */ - /* 0x09f0 horizlinescan3 ? ??? */ - {0x09f1, 0x2500}, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ - /* 0x09f2 horizlinescan7 ? ??? */ - /* 0x09f3 horizlinescan9 ? ??? */ - {0x09f4, 0x251c}, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ - {0x09f5, 0x2524}, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ - {0x09f6, 0x2534}, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ - {0x09f7, 0x252c}, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ - {0x09f8, 0x2502}, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ - {0x0aa1, 0x2003}, /* emspace   EM SPACE */ - {0x0aa2, 0x2002}, /* enspace   EN SPACE */ - {0x0aa3, 0x2004}, /* em3space   THREE-PER-EM SPACE */ - {0x0aa4, 0x2005}, /* em4space   FOUR-PER-EM SPACE */ - {0x0aa5, 0x2007}, /* digitspace   FIGURE SPACE */ - {0x0aa6, 0x2008}, /* punctspace   PUNCTUATION SPACE */ - {0x0aa7, 0x2009}, /* thinspace   THIN SPACE */ - {0x0aa8, 0x200a}, /* hairspace   HAIR SPACE */ - {0x0aa9, 0x2014}, /* emdash — EM DASH */ - {0x0aaa, 0x2013}, /* endash – EN DASH */ - /* 0x0aac signifblank ? ??? */ - {0x0aae, 0x2026}, /* ellipsis … HORIZONTAL ELLIPSIS */ - /* 0x0aaf doubbaselinedot ? ??? */ - {0x0ab0, 0x2153}, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ - {0x0ab1, 0x2154}, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ - {0x0ab2, 0x2155}, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ - {0x0ab3, 0x2156}, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ - {0x0ab4, 0x2157}, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ - {0x0ab5, 0x2158}, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ - {0x0ab6, 0x2159}, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ - {0x0ab7, 0x215a}, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ - {0x0ab8, 0x2105}, /* careof ℅ CARE OF */ - {0x0abb, 0x2012}, /* figdash ‒ FIGURE DASH */ - {0x0abc, 0x2329}, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ - {0x0abd, 0x002e}, /* decimalpoint . FULL STOP */ - {0x0abe, 0x232a}, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ - /* 0x0abf marker ? ??? */ - {0x0ac3, 0x215b}, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ - {0x0ac4, 0x215c}, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ - {0x0ac5, 0x215d}, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ - {0x0ac6, 0x215e}, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ - {0x0ac9, 0x2122}, /* trademark ™ TRADE MARK SIGN */ - {0x0aca, 0x2613}, /* signaturemark ☓ SALTIRE */ - /* 0x0acb trademarkincircle ? ??? */ - {0x0acc, 0x25c1}, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ - {0x0acd, 0x25b7}, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ - {0x0ace, 0x25cb}, /* emopencircle ○ WHITE CIRCLE */ - {0x0acf, 0x25a1}, /* emopenrectangle □ WHITE SQUARE */ - {0x0ad0, 0x2018}, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ - {0x0ad1, 0x2019}, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ - {0x0ad2, 0x201c}, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ - {0x0ad3, 0x201d}, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ - {0x0ad4, 0x211e}, /* prescription ℞ PRESCRIPTION TAKE */ - {0x0ad6, 0x2032}, /* minutes ′ PRIME */ - {0x0ad7, 0x2033}, /* seconds ″ DOUBLE PRIME */ - {0x0ad9, 0x271d}, /* latincross ✝ LATIN CROSS */ - /* 0x0ada hexagram ? ??? */ - {0x0adb, 0x25ac}, /* filledrectbullet ▬ BLACK RECTANGLE */ - {0x0adc, 0x25c0}, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ - {0x0add, 0x25b6}, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ - {0x0ade, 0x25cf}, /* emfilledcircle ● BLACK CIRCLE */ - {0x0adf, 0x25a0}, /* emfilledrect ■ BLACK SQUARE */ - {0x0ae0, 0x25e6}, /* enopencircbullet ◦ WHITE BULLET */ - {0x0ae1, 0x25ab}, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ - {0x0ae2, 0x25ad}, /* openrectbullet ▭ WHITE RECTANGLE */ - {0x0ae3, 0x25b3}, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ - {0x0ae4, 0x25bd}, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ - {0x0ae5, 0x2606}, /* openstar ☆ WHITE STAR */ - {0x0ae6, 0x2022}, /* enfilledcircbullet • BULLET */ - {0x0ae7, 0x25aa}, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ - {0x0ae8, 0x25b2}, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ - {0x0ae9, 0x25bc}, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ - {0x0aea, 0x261c}, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ - {0x0aeb, 0x261e}, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ - {0x0aec, 0x2663}, /* club ♣ BLACK CLUB SUIT */ - {0x0aed, 0x2666}, /* diamond ♦ BLACK DIAMOND SUIT */ - {0x0aee, 0x2665}, /* heart ♥ BLACK HEART SUIT */ - {0x0af0, 0x2720}, /* maltesecross ✠ MALTESE CROSS */ - {0x0af1, 0x2020}, /* dagger † DAGGER */ - {0x0af2, 0x2021}, /* doubledagger ‡ DOUBLE DAGGER */ - {0x0af3, 0x2713}, /* checkmark ✓ CHECK MARK */ - {0x0af4, 0x2717}, /* ballotcross ✗ BALLOT X */ - {0x0af5, 0x266f}, /* musicalsharp ♯ MUSIC SHARP SIGN */ - {0x0af6, 0x266d}, /* musicalflat ♭ MUSIC FLAT SIGN */ - {0x0af7, 0x2642}, /* malesymbol ♂ MALE SIGN */ - {0x0af8, 0x2640}, /* femalesymbol ♀ FEMALE SIGN */ - {0x0af9, 0x260e}, /* telephone ☎ BLACK TELEPHONE */ - {0x0afa, 0x2315}, /* telephonerecorder ⌕ TELEPHONE RECORDER */ - {0x0afb, 0x2117}, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ - {0x0afc, 0x2038}, /* caret ‸ CARET */ - {0x0afd, 0x201a}, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ - {0x0afe, 0x201e}, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ - /* 0x0aff cursor ? ??? */ - {0x0ba3, 0x003c}, /* leftcaret < LESS-THAN SIGN */ - {0x0ba6, 0x003e}, /* rightcaret > GREATER-THAN SIGN */ - {0x0ba8, 0x2228}, /* downcaret ∨ LOGICAL OR */ - {0x0ba9, 0x2227}, /* upcaret ∧ LOGICAL AND */ - {0x0bc0, 0x00af}, /* overbar ¯ MACRON */ - {0x0bc2, 0x22a4}, /* downtack ⊤ DOWN TACK */ - {0x0bc3, 0x2229}, /* upshoe ∩ INTERSECTION */ - {0x0bc4, 0x230a}, /* downstile ⌊ LEFT FLOOR */ - {0x0bc6, 0x005f}, /* underbar _ LOW LINE */ - {0x0bca, 0x2218}, /* jot ∘ RING OPERATOR */ - {0x0bcc, 0x2395}, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ - {0x0bce, 0x22a5}, /* uptack ⊥ UP TACK */ - {0x0bcf, 0x25cb}, /* circle ○ WHITE CIRCLE */ - {0x0bd3, 0x2308}, /* upstile ⌈ LEFT CEILING */ - {0x0bd6, 0x222a}, /* downshoe ∪ UNION */ - {0x0bd8, 0x2283}, /* rightshoe ⊃ SUPERSET OF */ - {0x0bda, 0x2282}, /* leftshoe ⊂ SUBSET OF */ - {0x0bdc, 0x22a3}, /* lefttack ⊣ LEFT TACK */ - {0x0bfc, 0x22a2}, /* righttack ⊢ RIGHT TACK */ - {0x0cdf, 0x2017}, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ - {0x0ce0, 0x05d0}, /* hebrew_aleph א HEBREW LETTER ALEF */ - {0x0ce1, 0x05d1}, /* hebrew_bet ב HEBREW LETTER BET */ - {0x0ce2, 0x05d2}, /* hebrew_gimel ג HEBREW LETTER GIMEL */ - {0x0ce3, 0x05d3}, /* hebrew_dalet ד HEBREW LETTER DALET */ - {0x0ce4, 0x05d4}, /* hebrew_he ה HEBREW LETTER HE */ - {0x0ce5, 0x05d5}, /* hebrew_waw ו HEBREW LETTER VAV */ - {0x0ce6, 0x05d6}, /* hebrew_zain ז HEBREW LETTER ZAYIN */ - {0x0ce7, 0x05d7}, /* hebrew_chet ח HEBREW LETTER HET */ - {0x0ce8, 0x05d8}, /* hebrew_tet ט HEBREW LETTER TET */ - {0x0ce9, 0x05d9}, /* hebrew_yod י HEBREW LETTER YOD */ - {0x0cea, 0x05da}, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ - {0x0ceb, 0x05db}, /* hebrew_kaph כ HEBREW LETTER KAF */ - {0x0cec, 0x05dc}, /* hebrew_lamed ל HEBREW LETTER LAMED */ - {0x0ced, 0x05dd}, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ - {0x0cee, 0x05de}, /* hebrew_mem מ HEBREW LETTER MEM */ - {0x0cef, 0x05df}, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ - {0x0cf0, 0x05e0}, /* hebrew_nun נ HEBREW LETTER NUN */ - {0x0cf1, 0x05e1}, /* hebrew_samech ס HEBREW LETTER SAMEKH */ - {0x0cf2, 0x05e2}, /* hebrew_ayin ע HEBREW LETTER AYIN */ - {0x0cf3, 0x05e3}, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ - {0x0cf4, 0x05e4}, /* hebrew_pe פ HEBREW LETTER PE */ - {0x0cf5, 0x05e5}, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ - {0x0cf6, 0x05e6}, /* hebrew_zade צ HEBREW LETTER TSADI */ - {0x0cf7, 0x05e7}, /* hebrew_qoph ק HEBREW LETTER QOF */ - {0x0cf8, 0x05e8}, /* hebrew_resh ר HEBREW LETTER RESH */ - {0x0cf9, 0x05e9}, /* hebrew_shin ש HEBREW LETTER SHIN */ - {0x0cfa, 0x05ea}, /* hebrew_taw ת HEBREW LETTER TAV */ - {0x0da1, 0x0e01}, /* Thai_kokai ก THAI CHARACTER KO KAI */ - {0x0da2, 0x0e02}, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ - {0x0da3, 0x0e03}, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ - {0x0da4, 0x0e04}, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ - {0x0da5, 0x0e05}, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ - {0x0da6, 0x0e06}, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ - {0x0da7, 0x0e07}, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ - {0x0da8, 0x0e08}, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ - {0x0da9, 0x0e09}, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ - {0x0daa, 0x0e0a}, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ - {0x0dab, 0x0e0b}, /* Thai_soso ซ THAI CHARACTER SO SO */ - {0x0dac, 0x0e0c}, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ - {0x0dad, 0x0e0d}, /* Thai_yoying ญ THAI CHARACTER YO YING */ - {0x0dae, 0x0e0e}, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ - {0x0daf, 0x0e0f}, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ - {0x0db0, 0x0e10}, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ - {0x0db1, 0x0e11}, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ - {0x0db2, 0x0e12}, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ - {0x0db3, 0x0e13}, /* Thai_nonen ณ THAI CHARACTER NO NEN */ - {0x0db4, 0x0e14}, /* Thai_dodek ด THAI CHARACTER DO DEK */ - {0x0db5, 0x0e15}, /* Thai_totao ต THAI CHARACTER TO TAO */ - {0x0db6, 0x0e16}, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ - {0x0db7, 0x0e17}, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ - {0x0db8, 0x0e18}, /* Thai_thothong ธ THAI CHARACTER THO THONG */ - {0x0db9, 0x0e19}, /* Thai_nonu น THAI CHARACTER NO NU */ - {0x0dba, 0x0e1a}, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ - {0x0dbb, 0x0e1b}, /* Thai_popla ป THAI CHARACTER PO PLA */ - {0x0dbc, 0x0e1c}, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ - {0x0dbd, 0x0e1d}, /* Thai_fofa ฝ THAI CHARACTER FO FA */ - {0x0dbe, 0x0e1e}, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ - {0x0dbf, 0x0e1f}, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ - {0x0dc0, 0x0e20}, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ - {0x0dc1, 0x0e21}, /* Thai_moma ม THAI CHARACTER MO MA */ - {0x0dc2, 0x0e22}, /* Thai_yoyak ย THAI CHARACTER YO YAK */ - {0x0dc3, 0x0e23}, /* Thai_rorua ร THAI CHARACTER RO RUA */ - {0x0dc4, 0x0e24}, /* Thai_ru ฤ THAI CHARACTER RU */ - {0x0dc5, 0x0e25}, /* Thai_loling ล THAI CHARACTER LO LING */ - {0x0dc6, 0x0e26}, /* Thai_lu ฦ THAI CHARACTER LU */ - {0x0dc7, 0x0e27}, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ - {0x0dc8, 0x0e28}, /* Thai_sosala ศ THAI CHARACTER SO SALA */ - {0x0dc9, 0x0e29}, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ - {0x0dca, 0x0e2a}, /* Thai_sosua ส THAI CHARACTER SO SUA */ - {0x0dcb, 0x0e2b}, /* Thai_hohip ห THAI CHARACTER HO HIP */ - {0x0dcc, 0x0e2c}, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ - {0x0dcd, 0x0e2d}, /* Thai_oang อ THAI CHARACTER O ANG */ - {0x0dce, 0x0e2e}, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ - {0x0dcf, 0x0e2f}, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ - {0x0dd0, 0x0e30}, /* Thai_saraa ะ THAI CHARACTER SARA A */ - {0x0dd1, 0x0e31}, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ - {0x0dd2, 0x0e32}, /* Thai_saraaa า THAI CHARACTER SARA AA */ - {0x0dd3, 0x0e33}, /* Thai_saraam ำ THAI CHARACTER SARA AM */ - {0x0dd4, 0x0e34}, /* Thai_sarai ิ THAI CHARACTER SARA I */ - {0x0dd5, 0x0e35}, /* Thai_saraii ี THAI CHARACTER SARA II */ - {0x0dd6, 0x0e36}, /* Thai_saraue ึ THAI CHARACTER SARA UE */ - {0x0dd7, 0x0e37}, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ - {0x0dd8, 0x0e38}, /* Thai_sarau ุ THAI CHARACTER SARA U */ - {0x0dd9, 0x0e39}, /* Thai_sarauu ู THAI CHARACTER SARA UU */ - {0x0dda, 0x0e3a}, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ - {0x0dde, 0x0e3e}, /* Thai_maihanakat_maitho ฾ ??? */ - {0x0ddf, 0x0e3f}, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ - {0x0de0, 0x0e40}, /* Thai_sarae เ THAI CHARACTER SARA E */ - {0x0de1, 0x0e41}, /* Thai_saraae แ THAI CHARACTER SARA AE */ - {0x0de2, 0x0e42}, /* Thai_sarao โ THAI CHARACTER SARA O */ - {0x0de3, 0x0e43}, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ - {0x0de4, 0x0e44}, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ - {0x0de5, 0x0e45}, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ - {0x0de6, 0x0e46}, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ - {0x0de7, 0x0e47}, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ - {0x0de8, 0x0e48}, /* Thai_maiek ่ THAI CHARACTER MAI EK */ - {0x0de9, 0x0e49}, /* Thai_maitho ้ THAI CHARACTER MAI THO */ - {0x0dea, 0x0e4a}, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ - {0x0deb, 0x0e4b}, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ - {0x0dec, 0x0e4c}, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ - {0x0ded, 0x0e4d}, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ - {0x0df0, 0x0e50}, /* Thai_leksun ๐ THAI DIGIT ZERO */ - {0x0df1, 0x0e51}, /* Thai_leknung ๑ THAI DIGIT ONE */ - {0x0df2, 0x0e52}, /* Thai_leksong ๒ THAI DIGIT TWO */ - {0x0df3, 0x0e53}, /* Thai_leksam ๓ THAI DIGIT THREE */ - {0x0df4, 0x0e54}, /* Thai_leksi ๔ THAI DIGIT FOUR */ - {0x0df5, 0x0e55}, /* Thai_lekha ๕ THAI DIGIT FIVE */ - {0x0df6, 0x0e56}, /* Thai_lekhok ๖ THAI DIGIT SIX */ - {0x0df7, 0x0e57}, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ - {0x0df8, 0x0e58}, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ - {0x0df9, 0x0e59}, /* Thai_lekkao ๙ THAI DIGIT NINE */ - {0x0ea1, 0x3131}, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ - {0x0ea2, 0x3132}, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ - {0x0ea3, 0x3133}, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ - {0x0ea4, 0x3134}, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ - {0x0ea5, 0x3135}, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ - {0x0ea6, 0x3136}, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ - {0x0ea7, 0x3137}, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ - {0x0ea8, 0x3138}, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ - {0x0ea9, 0x3139}, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ - {0x0eaa, 0x313a}, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ - {0x0eab, 0x313b}, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ - {0x0eac, 0x313c}, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ - {0x0ead, 0x313d}, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ - {0x0eae, 0x313e}, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ - {0x0eaf, 0x313f}, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ - {0x0eb0, 0x3140}, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ - {0x0eb1, 0x3141}, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ - {0x0eb2, 0x3142}, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ - {0x0eb3, 0x3143}, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ - {0x0eb4, 0x3144}, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ - {0x0eb5, 0x3145}, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ - {0x0eb6, 0x3146}, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ - {0x0eb7, 0x3147}, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ - {0x0eb8, 0x3148}, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ - {0x0eb9, 0x3149}, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ - {0x0eba, 0x314a}, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ - {0x0ebb, 0x314b}, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ - {0x0ebc, 0x314c}, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ - {0x0ebd, 0x314d}, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ - {0x0ebe, 0x314e}, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ - {0x0ebf, 0x314f}, /* Hangul_A ㅏ HANGUL LETTER A */ - {0x0ec0, 0x3150}, /* Hangul_AE ㅐ HANGUL LETTER AE */ - {0x0ec1, 0x3151}, /* Hangul_YA ㅑ HANGUL LETTER YA */ - {0x0ec2, 0x3152}, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ - {0x0ec3, 0x3153}, /* Hangul_EO ㅓ HANGUL LETTER EO */ - {0x0ec4, 0x3154}, /* Hangul_E ㅔ HANGUL LETTER E */ - {0x0ec5, 0x3155}, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ - {0x0ec6, 0x3156}, /* Hangul_YE ㅖ HANGUL LETTER YE */ - {0x0ec7, 0x3157}, /* Hangul_O ㅗ HANGUL LETTER O */ - {0x0ec8, 0x3158}, /* Hangul_WA ㅘ HANGUL LETTER WA */ - {0x0ec9, 0x3159}, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ - {0x0eca, 0x315a}, /* Hangul_OE ㅚ HANGUL LETTER OE */ - {0x0ecb, 0x315b}, /* Hangul_YO ㅛ HANGUL LETTER YO */ - {0x0ecc, 0x315c}, /* Hangul_U ㅜ HANGUL LETTER U */ - {0x0ecd, 0x315d}, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ - {0x0ece, 0x315e}, /* Hangul_WE ㅞ HANGUL LETTER WE */ - {0x0ecf, 0x315f}, /* Hangul_WI ㅟ HANGUL LETTER WI */ - {0x0ed0, 0x3160}, /* Hangul_YU ㅠ HANGUL LETTER YU */ - {0x0ed1, 0x3161}, /* Hangul_EU ㅡ HANGUL LETTER EU */ - {0x0ed2, 0x3162}, /* Hangul_YI ㅢ HANGUL LETTER YI */ - {0x0ed3, 0x3163}, /* Hangul_I ㅣ HANGUL LETTER I */ - {0x0ed4, 0x11a8}, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ - {0x0ed5, 0x11a9}, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ - {0x0ed6, 0x11aa}, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ - {0x0ed7, 0x11ab}, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ - {0x0ed8, 0x11ac}, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ - {0x0ed9, 0x11ad}, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ - {0x0eda, 0x11ae}, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ - {0x0edb, 0x11af}, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ - {0x0edc, 0x11b0}, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ - {0x0edd, 0x11b1}, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ - {0x0ede, 0x11b2}, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ - {0x0edf, 0x11b3}, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ - {0x0ee0, 0x11b4}, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ - {0x0ee1, 0x11b5}, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ - {0x0ee2, 0x11b6}, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ - {0x0ee3, 0x11b7}, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ - {0x0ee4, 0x11b8}, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ - {0x0ee5, 0x11b9}, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ - {0x0ee6, 0x11ba}, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ - {0x0ee7, 0x11bb}, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ - {0x0ee8, 0x11bc}, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ - {0x0ee9, 0x11bd}, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ - {0x0eea, 0x11be}, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ - {0x0eeb, 0x11bf}, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ - {0x0eec, 0x11c0}, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ - {0x0eed, 0x11c1}, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ - {0x0eee, 0x11c2}, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ - {0x0eef, 0x316d}, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ - {0x0ef0, 0x3171}, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ - {0x0ef1, 0x3178}, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ - {0x0ef2, 0x317f}, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ - /* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */ - {0x0ef4, 0x3184}, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ - {0x0ef5, 0x3186}, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ - {0x0ef6, 0x318d}, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ - {0x0ef7, 0x318e}, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ - {0x0ef8, 0x11eb}, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ - /* 0x0ef9 Hangul_J_KkogjiDalrinIeung ? ??? */ - {0x0efa, 0x11f9}, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ - {0x0eff, 0x20a9}, /* Korean_Won ₩ WON SIGN */ - {0x13bc, 0x0152}, /* OE Œ LATIN CAPITAL LIGATURE OE */ - {0x13bd, 0x0153}, /* oe œ LATIN SMALL LIGATURE OE */ - {0x13be, 0x0178}, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ - {0x20ac, 0x20ac}, /* EuroSign € EURO SIGN */ + {0x01a1, 0x0104}, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ + {0x01a2, 0x02d8}, /* breve ˘ BREVE */ + {0x01a3, 0x0141}, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ + {0x01a5, 0x013d}, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ + {0x01a6, 0x015a}, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ + {0x01a9, 0x0160}, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ + {0x01aa, 0x015e}, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ + {0x01ab, 0x0164}, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ + {0x01ac, 0x0179}, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ + {0x01ae, 0x017d}, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ + {0x01af, 0x017b}, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + {0x01b1, 0x0105}, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ + {0x01b2, 0x02db}, /* ogonek ˛ OGONEK */ + {0x01b3, 0x0142}, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ + {0x01b5, 0x013e}, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ + {0x01b6, 0x015b}, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ + {0x01b7, 0x02c7}, /* caron ˇ CARON */ + {0x01b9, 0x0161}, /* scaron š LATIN SMALL LETTER S WITH CARON */ + {0x01ba, 0x015f}, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ + {0x01bb, 0x0165}, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ + {0x01bc, 0x017a}, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ + {0x01bd, 0x02dd}, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ + {0x01be, 0x017e}, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ + {0x01bf, 0x017c}, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ + {0x01c0, 0x0154}, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ + {0x01c3, 0x0102}, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ + {0x01c5, 0x0139}, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ + {0x01c6, 0x0106}, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ + {0x01c8, 0x010c}, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ + {0x01ca, 0x0118}, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ + {0x01cc, 0x011a}, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ + {0x01cf, 0x010e}, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ + {0x01d0, 0x0110}, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ + {0x01d1, 0x0143}, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ + {0x01d2, 0x0147}, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ + {0x01d5, 0x0150}, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + {0x01d8, 0x0158}, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ + {0x01d9, 0x016e}, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ + {0x01db, 0x0170}, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + {0x01de, 0x0162}, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ + {0x01e0, 0x0155}, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ + {0x01e3, 0x0103}, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ + {0x01e5, 0x013a}, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ + {0x01e6, 0x0107}, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ + {0x01e8, 0x010d}, /* ccaron č LATIN SMALL LETTER C WITH CARON */ + {0x01ea, 0x0119}, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ + {0x01ec, 0x011b}, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ + {0x01ef, 0x010f}, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ + {0x01f0, 0x0111}, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ + {0x01f1, 0x0144}, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ + {0x01f2, 0x0148}, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ + {0x01f5, 0x0151}, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + {0x01f8, 0x0159}, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ + {0x01f9, 0x016f}, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ + {0x01fb, 0x0171}, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + {0x01fe, 0x0163}, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ + {0x01ff, 0x02d9}, /* abovedot ˙ DOT ABOVE */ + {0x02a1, 0x0126}, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ + {0x02a6, 0x0124}, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + {0x02a9, 0x0130}, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {0x02ab, 0x011e}, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ + {0x02ac, 0x0134}, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + {0x02b1, 0x0127}, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ + {0x02b6, 0x0125}, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ + {0x02b9, 0x0131}, /* idotless ı LATIN SMALL LETTER DOTLESS I */ + {0x02bb, 0x011f}, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ + {0x02bc, 0x0135}, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ + {0x02c5, 0x010a}, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ + {0x02c6, 0x0108}, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + {0x02d5, 0x0120}, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ + {0x02d8, 0x011c}, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + {0x02dd, 0x016c}, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ + {0x02de, 0x015c}, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + {0x02e5, 0x010b}, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ + {0x02e6, 0x0109}, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ + {0x02f5, 0x0121}, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ + {0x02f8, 0x011d}, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ + {0x02fd, 0x016d}, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ + {0x02fe, 0x015d}, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ + {0x03a2, 0x0138}, /* kra ĸ LATIN SMALL LETTER KRA */ + {0x03a3, 0x0156}, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ + {0x03a5, 0x0128}, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ + {0x03a6, 0x013b}, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ + {0x03aa, 0x0112}, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ + {0x03ab, 0x0122}, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ + {0x03ac, 0x0166}, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ + {0x03b3, 0x0157}, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ + {0x03b5, 0x0129}, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ + {0x03b6, 0x013c}, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ + {0x03ba, 0x0113}, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ + {0x03bb, 0x0123}, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ + {0x03bc, 0x0167}, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ + {0x03bd, 0x014a}, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ + {0x03bf, 0x014b}, /* eng ŋ LATIN SMALL LETTER ENG */ + {0x03c0, 0x0100}, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ + {0x03c7, 0x012e}, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ + {0x03cc, 0x0116}, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ + {0x03cf, 0x012a}, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ + {0x03d1, 0x0145}, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ + {0x03d2, 0x014c}, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ + {0x03d3, 0x0136}, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ + {0x03d9, 0x0172}, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ + {0x03dd, 0x0168}, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ + {0x03de, 0x016a}, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ + {0x03e0, 0x0101}, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ + {0x03e7, 0x012f}, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ + {0x03ec, 0x0117}, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ + {0x03ef, 0x012b}, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ + {0x03f1, 0x0146}, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ + {0x03f2, 0x014d}, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ + {0x03f3, 0x0137}, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ + {0x03f9, 0x0173}, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ + {0x03fd, 0x0169}, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ + {0x03fe, 0x016b}, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ + {0x047e, 0x203e}, /* overline ‾ OVERLINE */ + {0x04a1, 0x3002}, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ + {0x04a2, 0x300c}, /* kana_openingbracket 「 LEFT CORNER BRACKET */ + {0x04a3, 0x300d}, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ + {0x04a4, 0x3001}, /* kana_comma 、 IDEOGRAPHIC COMMA */ + {0x04a5, 0x30fb}, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ + {0x04a6, 0x30f2}, /* kana_WO ヲ KATAKANA LETTER WO */ + {0x04a7, 0x30a1}, /* kana_a ァ KATAKANA LETTER SMALL A */ + {0x04a8, 0x30a3}, /* kana_i ィ KATAKANA LETTER SMALL I */ + {0x04a9, 0x30a5}, /* kana_u ゥ KATAKANA LETTER SMALL U */ + {0x04aa, 0x30a7}, /* kana_e ェ KATAKANA LETTER SMALL E */ + {0x04ab, 0x30a9}, /* kana_o ォ KATAKANA LETTER SMALL O */ + {0x04ac, 0x30e3}, /* kana_ya ャ KATAKANA LETTER SMALL YA */ + {0x04ad, 0x30e5}, /* kana_yu ュ KATAKANA LETTER SMALL YU */ + {0x04ae, 0x30e7}, /* kana_yo ョ KATAKANA LETTER SMALL YO */ + {0x04af, 0x30c3}, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ + {0x04b0, 0x30fc}, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {0x04b1, 0x30a2}, /* kana_A ア KATAKANA LETTER A */ + {0x04b2, 0x30a4}, /* kana_I イ KATAKANA LETTER I */ + {0x04b3, 0x30a6}, /* kana_U ウ KATAKANA LETTER U */ + {0x04b4, 0x30a8}, /* kana_E エ KATAKANA LETTER E */ + {0x04b5, 0x30aa}, /* kana_O オ KATAKANA LETTER O */ + {0x04b6, 0x30ab}, /* kana_KA カ KATAKANA LETTER KA */ + {0x04b7, 0x30ad}, /* kana_KI キ KATAKANA LETTER KI */ + {0x04b8, 0x30af}, /* kana_KU ク KATAKANA LETTER KU */ + {0x04b9, 0x30b1}, /* kana_KE ケ KATAKANA LETTER KE */ + {0x04ba, 0x30b3}, /* kana_KO コ KATAKANA LETTER KO */ + {0x04bb, 0x30b5}, /* kana_SA サ KATAKANA LETTER SA */ + {0x04bc, 0x30b7}, /* kana_SHI シ KATAKANA LETTER SI */ + {0x04bd, 0x30b9}, /* kana_SU ス KATAKANA LETTER SU */ + {0x04be, 0x30bb}, /* kana_SE セ KATAKANA LETTER SE */ + {0x04bf, 0x30bd}, /* kana_SO ソ KATAKANA LETTER SO */ + {0x04c0, 0x30bf}, /* kana_TA タ KATAKANA LETTER TA */ + {0x04c1, 0x30c1}, /* kana_CHI チ KATAKANA LETTER TI */ + {0x04c2, 0x30c4}, /* kana_TSU ツ KATAKANA LETTER TU */ + {0x04c3, 0x30c6}, /* kana_TE テ KATAKANA LETTER TE */ + {0x04c4, 0x30c8}, /* kana_TO ト KATAKANA LETTER TO */ + {0x04c5, 0x30ca}, /* kana_NA ナ KATAKANA LETTER NA */ + {0x04c6, 0x30cb}, /* kana_NI ニ KATAKANA LETTER NI */ + {0x04c7, 0x30cc}, /* kana_NU ヌ KATAKANA LETTER NU */ + {0x04c8, 0x30cd}, /* kana_NE ネ KATAKANA LETTER NE */ + {0x04c9, 0x30ce}, /* kana_NO ノ KATAKANA LETTER NO */ + {0x04ca, 0x30cf}, /* kana_HA ハ KATAKANA LETTER HA */ + {0x04cb, 0x30d2}, /* kana_HI ヒ KATAKANA LETTER HI */ + {0x04cc, 0x30d5}, /* kana_FU フ KATAKANA LETTER HU */ + {0x04cd, 0x30d8}, /* kana_HE ヘ KATAKANA LETTER HE */ + {0x04ce, 0x30db}, /* kana_HO ホ KATAKANA LETTER HO */ + {0x04cf, 0x30de}, /* kana_MA マ KATAKANA LETTER MA */ + {0x04d0, 0x30df}, /* kana_MI ミ KATAKANA LETTER MI */ + {0x04d1, 0x30e0}, /* kana_MU ム KATAKANA LETTER MU */ + {0x04d2, 0x30e1}, /* kana_ME メ KATAKANA LETTER ME */ + {0x04d3, 0x30e2}, /* kana_MO モ KATAKANA LETTER MO */ + {0x04d4, 0x30e4}, /* kana_YA ヤ KATAKANA LETTER YA */ + {0x04d5, 0x30e6}, /* kana_YU ユ KATAKANA LETTER YU */ + {0x04d6, 0x30e8}, /* kana_YO ヨ KATAKANA LETTER YO */ + {0x04d7, 0x30e9}, /* kana_RA ラ KATAKANA LETTER RA */ + {0x04d8, 0x30ea}, /* kana_RI リ KATAKANA LETTER RI */ + {0x04d9, 0x30eb}, /* kana_RU ル KATAKANA LETTER RU */ + {0x04da, 0x30ec}, /* kana_RE レ KATAKANA LETTER RE */ + {0x04db, 0x30ed}, /* kana_RO ロ KATAKANA LETTER RO */ + {0x04dc, 0x30ef}, /* kana_WA ワ KATAKANA LETTER WA */ + {0x04dd, 0x30f3}, /* kana_N ン KATAKANA LETTER N */ + {0x04de, 0x309b}, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ + {0x04df, 0x309c}, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + {0x05ac, 0x060c}, /* Arabic_comma ، ARABIC COMMA */ + {0x05bb, 0x061b}, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ + {0x05bf, 0x061f}, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ + {0x05c1, 0x0621}, /* Arabic_hamza ء ARABIC LETTER HAMZA */ + {0x05c2, 0x0622}, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ + {0x05c3, 0x0623}, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ + {0x05c4, 0x0624}, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ + {0x05c5, 0x0625}, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ + {0x05c6, 0x0626}, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ + {0x05c7, 0x0627}, /* Arabic_alef ا ARABIC LETTER ALEF */ + {0x05c8, 0x0628}, /* Arabic_beh ب ARABIC LETTER BEH */ + {0x05c9, 0x0629}, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ + {0x05ca, 0x062a}, /* Arabic_teh ت ARABIC LETTER TEH */ + {0x05cb, 0x062b}, /* Arabic_theh ث ARABIC LETTER THEH */ + {0x05cc, 0x062c}, /* Arabic_jeem ج ARABIC LETTER JEEM */ + {0x05cd, 0x062d}, /* Arabic_hah ح ARABIC LETTER HAH */ + {0x05ce, 0x062e}, /* Arabic_khah خ ARABIC LETTER KHAH */ + {0x05cf, 0x062f}, /* Arabic_dal د ARABIC LETTER DAL */ + {0x05d0, 0x0630}, /* Arabic_thal ذ ARABIC LETTER THAL */ + {0x05d1, 0x0631}, /* Arabic_ra ر ARABIC LETTER REH */ + {0x05d2, 0x0632}, /* Arabic_zain ز ARABIC LETTER ZAIN */ + {0x05d3, 0x0633}, /* Arabic_seen س ARABIC LETTER SEEN */ + {0x05d4, 0x0634}, /* Arabic_sheen ش ARABIC LETTER SHEEN */ + {0x05d5, 0x0635}, /* Arabic_sad ص ARABIC LETTER SAD */ + {0x05d6, 0x0636}, /* Arabic_dad ض ARABIC LETTER DAD */ + {0x05d7, 0x0637}, /* Arabic_tah ط ARABIC LETTER TAH */ + {0x05d8, 0x0638}, /* Arabic_zah ظ ARABIC LETTER ZAH */ + {0x05d9, 0x0639}, /* Arabic_ain ع ARABIC LETTER AIN */ + {0x05da, 0x063a}, /* Arabic_ghain غ ARABIC LETTER GHAIN */ + {0x05e0, 0x0640}, /* Arabic_tatweel ـ ARABIC TATWEEL */ + {0x05e1, 0x0641}, /* Arabic_feh ف ARABIC LETTER FEH */ + {0x05e2, 0x0642}, /* Arabic_qaf ق ARABIC LETTER QAF */ + {0x05e3, 0x0643}, /* Arabic_kaf ك ARABIC LETTER KAF */ + {0x05e4, 0x0644}, /* Arabic_lam ل ARABIC LETTER LAM */ + {0x05e5, 0x0645}, /* Arabic_meem م ARABIC LETTER MEEM */ + {0x05e6, 0x0646}, /* Arabic_noon ن ARABIC LETTER NOON */ + {0x05e7, 0x0647}, /* Arabic_ha ه ARABIC LETTER HEH */ + {0x05e8, 0x0648}, /* Arabic_waw و ARABIC LETTER WAW */ + {0x05e9, 0x0649}, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ + {0x05ea, 0x064a}, /* Arabic_yeh ي ARABIC LETTER YEH */ + {0x05eb, 0x064b}, /* Arabic_fathatan ً ARABIC FATHATAN */ + {0x05ec, 0x064c}, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ + {0x05ed, 0x064d}, /* Arabic_kasratan ٍ ARABIC KASRATAN */ + {0x05ee, 0x064e}, /* Arabic_fatha َ ARABIC FATHA */ + {0x05ef, 0x064f}, /* Arabic_damma ُ ARABIC DAMMA */ + {0x05f0, 0x0650}, /* Arabic_kasra ِ ARABIC KASRA */ + {0x05f1, 0x0651}, /* Arabic_shadda ّ ARABIC SHADDA */ + {0x05f2, 0x0652}, /* Arabic_sukun ْ ARABIC SUKUN */ + {0x06a1, 0x0452}, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ + {0x06a2, 0x0453}, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ + {0x06a3, 0x0451}, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ + {0x06a4, 0x0454}, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ + {0x06a5, 0x0455}, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ + {0x06a6, 0x0456}, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + {0x06a7, 0x0457}, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ + {0x06a8, 0x0458}, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ + {0x06a9, 0x0459}, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ + {0x06aa, 0x045a}, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ + {0x06ab, 0x045b}, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ + {0x06ac, 0x045c}, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ + /* 0x06ad Ukrainian_ghe_with_upturn ? ??? */ + {0x06ae, 0x045e}, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ + {0x06af, 0x045f}, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ + {0x06b0, 0x2116}, /* numerosign № NUMERO SIGN */ + {0x06b1, 0x0402}, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ + {0x06b2, 0x0403}, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ + {0x06b3, 0x0401}, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ + {0x06b4, 0x0404}, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + {0x06b5, 0x0405}, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ + {0x06b6, 0x0406}, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + {0x06b7, 0x0407}, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ + {0x06b8, 0x0408}, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ + {0x06b9, 0x0409}, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ + {0x06ba, 0x040a}, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ + {0x06bb, 0x040b}, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ + {0x06bc, 0x040c}, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ + /* 0x06bd Ukrainian_GHE_WITH_UPTURN ? ??? */ + {0x06be, 0x040e}, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ + {0x06bf, 0x040f}, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ + {0x06c0, 0x044e}, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ + {0x06c1, 0x0430}, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ + {0x06c2, 0x0431}, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ + {0x06c3, 0x0446}, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ + {0x06c4, 0x0434}, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ + {0x06c5, 0x0435}, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ + {0x06c6, 0x0444}, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ + {0x06c7, 0x0433}, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ + {0x06c8, 0x0445}, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ + {0x06c9, 0x0438}, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ + {0x06ca, 0x0439}, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ + {0x06cb, 0x043a}, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ + {0x06cc, 0x043b}, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ + {0x06cd, 0x043c}, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ + {0x06ce, 0x043d}, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ + {0x06cf, 0x043e}, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ + {0x06d0, 0x043f}, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ + {0x06d1, 0x044f}, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ + {0x06d2, 0x0440}, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ + {0x06d3, 0x0441}, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ + {0x06d4, 0x0442}, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ + {0x06d5, 0x0443}, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ + {0x06d6, 0x0436}, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ + {0x06d7, 0x0432}, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ + {0x06d8, 0x044c}, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ + {0x06d9, 0x044b}, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ + {0x06da, 0x0437}, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ + {0x06db, 0x0448}, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ + {0x06dc, 0x044d}, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ + {0x06dd, 0x0449}, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ + {0x06de, 0x0447}, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ + {0x06df, 0x044a}, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ + {0x06e0, 0x042e}, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ + {0x06e1, 0x0410}, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ + {0x06e2, 0x0411}, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ + {0x06e3, 0x0426}, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ + {0x06e4, 0x0414}, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ + {0x06e5, 0x0415}, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ + {0x06e6, 0x0424}, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ + {0x06e7, 0x0413}, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ + {0x06e8, 0x0425}, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ + {0x06e9, 0x0418}, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ + {0x06ea, 0x0419}, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ + {0x06eb, 0x041a}, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ + {0x06ec, 0x041b}, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ + {0x06ed, 0x041c}, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ + {0x06ee, 0x041d}, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ + {0x06ef, 0x041e}, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ + {0x06f0, 0x041f}, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ + {0x06f1, 0x042f}, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ + {0x06f2, 0x0420}, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ + {0x06f3, 0x0421}, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ + {0x06f4, 0x0422}, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ + {0x06f5, 0x0423}, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ + {0x06f6, 0x0416}, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ + {0x06f7, 0x0412}, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ + {0x06f8, 0x042c}, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ + {0x06f9, 0x042b}, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ + {0x06fa, 0x0417}, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ + {0x06fb, 0x0428}, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ + {0x06fc, 0x042d}, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ + {0x06fd, 0x0429}, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ + {0x06fe, 0x0427}, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ + {0x06ff, 0x042a}, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ + {0x07a1, 0x0386}, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ + {0x07a2, 0x0388}, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ + {0x07a3, 0x0389}, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ + {0x07a4, 0x038a}, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ + {0x07a5, 0x03aa}, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + {0x07a7, 0x038c}, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ + {0x07a8, 0x038e}, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ + {0x07a9, 0x03ab}, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + {0x07ab, 0x038f}, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ + {0x07ae, 0x0385}, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ + {0x07af, 0x2015}, /* Greek_horizbar ― HORIZONTAL BAR */ + {0x07b1, 0x03ac}, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ + {0x07b2, 0x03ad}, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ + {0x07b3, 0x03ae}, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ + {0x07b4, 0x03af}, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ + {0x07b5, 0x03ca}, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + {0x07b6, 0x0390}, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + {0x07b7, 0x03cc}, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ + {0x07b8, 0x03cd}, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ + {0x07b9, 0x03cb}, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + {0x07ba, 0x03b0}, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + {0x07bb, 0x03ce}, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ + {0x07c1, 0x0391}, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ + {0x07c2, 0x0392}, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ + {0x07c3, 0x0393}, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ + {0x07c4, 0x0394}, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ + {0x07c5, 0x0395}, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ + {0x07c6, 0x0396}, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ + {0x07c7, 0x0397}, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ + {0x07c8, 0x0398}, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ + {0x07c9, 0x0399}, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ + {0x07ca, 0x039a}, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ + {0x07cb, 0x039b}, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ + {0x07cc, 0x039c}, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ + {0x07cd, 0x039d}, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ + {0x07ce, 0x039e}, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ + {0x07cf, 0x039f}, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ + {0x07d0, 0x03a0}, /* Greek_PI Π GREEK CAPITAL LETTER PI */ + {0x07d1, 0x03a1}, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ + {0x07d2, 0x03a3}, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ + {0x07d4, 0x03a4}, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ + {0x07d5, 0x03a5}, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ + {0x07d6, 0x03a6}, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ + {0x07d7, 0x03a7}, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ + {0x07d8, 0x03a8}, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ + {0x07d9, 0x03a9}, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ + {0x07e1, 0x03b1}, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ + {0x07e2, 0x03b2}, /* Greek_beta β GREEK SMALL LETTER BETA */ + {0x07e3, 0x03b3}, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ + {0x07e4, 0x03b4}, /* Greek_delta δ GREEK SMALL LETTER DELTA */ + {0x07e5, 0x03b5}, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ + {0x07e6, 0x03b6}, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ + {0x07e7, 0x03b7}, /* Greek_eta η GREEK SMALL LETTER ETA */ + {0x07e8, 0x03b8}, /* Greek_theta θ GREEK SMALL LETTER THETA */ + {0x07e9, 0x03b9}, /* Greek_iota ι GREEK SMALL LETTER IOTA */ + {0x07ea, 0x03ba}, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ + {0x07eb, 0x03bb}, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ + {0x07ec, 0x03bc}, /* Greek_mu μ GREEK SMALL LETTER MU */ + {0x07ed, 0x03bd}, /* Greek_nu ν GREEK SMALL LETTER NU */ + {0x07ee, 0x03be}, /* Greek_xi ξ GREEK SMALL LETTER XI */ + {0x07ef, 0x03bf}, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ + {0x07f0, 0x03c0}, /* Greek_pi π GREEK SMALL LETTER PI */ + {0x07f1, 0x03c1}, /* Greek_rho ρ GREEK SMALL LETTER RHO */ + {0x07f2, 0x03c3}, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ + {0x07f3, 0x03c2}, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ + {0x07f4, 0x03c4}, /* Greek_tau τ GREEK SMALL LETTER TAU */ + {0x07f5, 0x03c5}, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ + {0x07f6, 0x03c6}, /* Greek_phi φ GREEK SMALL LETTER PHI */ + {0x07f7, 0x03c7}, /* Greek_chi χ GREEK SMALL LETTER CHI */ + {0x07f8, 0x03c8}, /* Greek_psi ψ GREEK SMALL LETTER PSI */ + {0x07f9, 0x03c9}, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ + /* 0x08a1 leftradical ? ??? */ + /* 0x08a2 topleftradical ? ??? */ + /* 0x08a3 horizconnector ? ??? */ + {0x08a4, 0x2320}, /* topintegral ⌠ TOP HALF INTEGRAL */ + {0x08a5, 0x2321}, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ + {0x08a6, 0x2502}, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ + /* 0x08a7 topleftsqbracket ? ??? */ + /* 0x08a8 botleftsqbracket ? ??? */ + /* 0x08a9 toprightsqbracket ? ??? */ + /* 0x08aa botrightsqbracket ? ??? */ + /* 0x08ab topleftparens ? ??? */ + /* 0x08ac botleftparens ? ??? */ + /* 0x08ad toprightparens ? ??? */ + /* 0x08ae botrightparens ? ??? */ + /* 0x08af leftmiddlecurlybrace ? ??? */ + /* 0x08b0 rightmiddlecurlybrace ? ??? */ + /* 0x08b1 topleftsummation ? ??? */ + /* 0x08b2 botleftsummation ? ??? */ + /* 0x08b3 topvertsummationconnector ? ??? */ + /* 0x08b4 botvertsummationconnector ? ??? */ + /* 0x08b5 toprightsummation ? ??? */ + /* 0x08b6 botrightsummation ? ??? */ + /* 0x08b7 rightmiddlesummation ? ??? */ + {0x08bc, 0x2264}, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ + {0x08bd, 0x2260}, /* notequal ≠ NOT EQUAL TO */ + {0x08be, 0x2265}, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ + {0x08bf, 0x222b}, /* integral ∫ INTEGRAL */ + {0x08c0, 0x2234}, /* therefore ∴ THEREFORE */ + {0x08c1, 0x221d}, /* variation ∝ PROPORTIONAL TO */ + {0x08c2, 0x221e}, /* infinity ∞ INFINITY */ + {0x08c5, 0x2207}, /* nabla ∇ NABLA */ + {0x08c8, 0x2245}, /* approximate ≅ APPROXIMATELY EQUAL TO */ + /* 0x08c9 similarequal ? ??? */ + {0x08cd, 0x21d4}, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ + {0x08ce, 0x21d2}, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ + {0x08cf, 0x2261}, /* identical ≡ IDENTICAL TO */ + {0x08d6, 0x221a}, /* radical √ SQUARE ROOT */ + {0x08da, 0x2282}, /* includedin ⊂ SUBSET OF */ + {0x08db, 0x2283}, /* includes ⊃ SUPERSET OF */ + {0x08dc, 0x2229}, /* intersection ∩ INTERSECTION */ + {0x08dd, 0x222a}, /* union ∪ UNION */ + {0x08de, 0x2227}, /* logicaland ∧ LOGICAL AND */ + {0x08df, 0x2228}, /* logicalor ∨ LOGICAL OR */ + {0x08ef, 0x2202}, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ + {0x08f6, 0x0192}, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ + {0x08fb, 0x2190}, /* leftarrow ← LEFTWARDS ARROW */ + {0x08fc, 0x2191}, /* uparrow ↑ UPWARDS ARROW */ + {0x08fd, 0x2192}, /* rightarrow → RIGHTWARDS ARROW */ + {0x08fe, 0x2193}, /* downarrow ↓ DOWNWARDS ARROW */ + {0x09df, 0x2422}, /* blank ␢ BLANK SYMBOL */ + {0x09e0, 0x25c6}, /* soliddiamond ◆ BLACK DIAMOND */ + {0x09e1, 0x2592}, /* checkerboard ▒ MEDIUM SHADE */ + {0x09e2, 0x2409}, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ + {0x09e3, 0x240c}, /* ff ␌ SYMBOL FOR FORM FEED */ + {0x09e4, 0x240d}, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ + {0x09e5, 0x240a}, /* lf ␊ SYMBOL FOR LINE FEED */ + {0x09e8, 0x2424}, /* nl ␤ SYMBOL FOR NEWLINE */ + {0x09e9, 0x240b}, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ + {0x09ea, 0x2518}, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ + {0x09eb, 0x2510}, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ + {0x09ec, 0x250c}, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ + {0x09ed, 0x2514}, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ + {0x09ee, 0x253c}, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + /* 0x09ef horizlinescan1 ? ??? */ + /* 0x09f0 horizlinescan3 ? ??? */ + {0x09f1, 0x2500}, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ + /* 0x09f2 horizlinescan7 ? ??? */ + /* 0x09f3 horizlinescan9 ? ??? */ + {0x09f4, 0x251c}, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + {0x09f5, 0x2524}, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + {0x09f6, 0x2534}, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + {0x09f7, 0x252c}, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + {0x09f8, 0x2502}, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ + {0x0aa1, 0x2003}, /* emspace   EM SPACE */ + {0x0aa2, 0x2002}, /* enspace   EN SPACE */ + {0x0aa3, 0x2004}, /* em3space   THREE-PER-EM SPACE */ + {0x0aa4, 0x2005}, /* em4space   FOUR-PER-EM SPACE */ + {0x0aa5, 0x2007}, /* digitspace   FIGURE SPACE */ + {0x0aa6, 0x2008}, /* punctspace   PUNCTUATION SPACE */ + {0x0aa7, 0x2009}, /* thinspace   THIN SPACE */ + {0x0aa8, 0x200a}, /* hairspace   HAIR SPACE */ + {0x0aa9, 0x2014}, /* emdash — EM DASH */ + {0x0aaa, 0x2013}, /* endash – EN DASH */ + /* 0x0aac signifblank ? ??? */ + {0x0aae, 0x2026}, /* ellipsis … HORIZONTAL ELLIPSIS */ + /* 0x0aaf doubbaselinedot ? ??? */ + {0x0ab0, 0x2153}, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ + {0x0ab1, 0x2154}, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ + {0x0ab2, 0x2155}, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ + {0x0ab3, 0x2156}, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ + {0x0ab4, 0x2157}, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ + {0x0ab5, 0x2158}, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ + {0x0ab6, 0x2159}, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ + {0x0ab7, 0x215a}, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ + {0x0ab8, 0x2105}, /* careof ℅ CARE OF */ + {0x0abb, 0x2012}, /* figdash ‒ FIGURE DASH */ + {0x0abc, 0x2329}, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ + {0x0abd, 0x002e}, /* decimalpoint . FULL STOP */ + {0x0abe, 0x232a}, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ + /* 0x0abf marker ? ??? */ + {0x0ac3, 0x215b}, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ + {0x0ac4, 0x215c}, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ + {0x0ac5, 0x215d}, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ + {0x0ac6, 0x215e}, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ + {0x0ac9, 0x2122}, /* trademark ™ TRADE MARK SIGN */ + {0x0aca, 0x2613}, /* signaturemark ☓ SALTIRE */ + /* 0x0acb trademarkincircle ? ??? */ + {0x0acc, 0x25c1}, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ + {0x0acd, 0x25b7}, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ + {0x0ace, 0x25cb}, /* emopencircle ○ WHITE CIRCLE */ + {0x0acf, 0x25a1}, /* emopenrectangle □ WHITE SQUARE */ + {0x0ad0, 0x2018}, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ + {0x0ad1, 0x2019}, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ + {0x0ad2, 0x201c}, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ + {0x0ad3, 0x201d}, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ + {0x0ad4, 0x211e}, /* prescription ℞ PRESCRIPTION TAKE */ + {0x0ad6, 0x2032}, /* minutes ′ PRIME */ + {0x0ad7, 0x2033}, /* seconds ″ DOUBLE PRIME */ + {0x0ad9, 0x271d}, /* latincross ✝ LATIN CROSS */ + /* 0x0ada hexagram ? ??? */ + {0x0adb, 0x25ac}, /* filledrectbullet ▬ BLACK RECTANGLE */ + {0x0adc, 0x25c0}, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ + {0x0add, 0x25b6}, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ + {0x0ade, 0x25cf}, /* emfilledcircle ● BLACK CIRCLE */ + {0x0adf, 0x25a0}, /* emfilledrect ■ BLACK SQUARE */ + {0x0ae0, 0x25e6}, /* enopencircbullet ◦ WHITE BULLET */ + {0x0ae1, 0x25ab}, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ + {0x0ae2, 0x25ad}, /* openrectbullet ▭ WHITE RECTANGLE */ + {0x0ae3, 0x25b3}, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ + {0x0ae4, 0x25bd}, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ + {0x0ae5, 0x2606}, /* openstar ☆ WHITE STAR */ + {0x0ae6, 0x2022}, /* enfilledcircbullet • BULLET */ + {0x0ae7, 0x25aa}, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ + {0x0ae8, 0x25b2}, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ + {0x0ae9, 0x25bc}, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ + {0x0aea, 0x261c}, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ + {0x0aeb, 0x261e}, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ + {0x0aec, 0x2663}, /* club ♣ BLACK CLUB SUIT */ + {0x0aed, 0x2666}, /* diamond ♦ BLACK DIAMOND SUIT */ + {0x0aee, 0x2665}, /* heart ♥ BLACK HEART SUIT */ + {0x0af0, 0x2720}, /* maltesecross ✠ MALTESE CROSS */ + {0x0af1, 0x2020}, /* dagger † DAGGER */ + {0x0af2, 0x2021}, /* doubledagger ‡ DOUBLE DAGGER */ + {0x0af3, 0x2713}, /* checkmark ✓ CHECK MARK */ + {0x0af4, 0x2717}, /* ballotcross ✗ BALLOT X */ + {0x0af5, 0x266f}, /* musicalsharp ♯ MUSIC SHARP SIGN */ + {0x0af6, 0x266d}, /* musicalflat ♭ MUSIC FLAT SIGN */ + {0x0af7, 0x2642}, /* malesymbol ♂ MALE SIGN */ + {0x0af8, 0x2640}, /* femalesymbol ♀ FEMALE SIGN */ + {0x0af9, 0x260e}, /* telephone ☎ BLACK TELEPHONE */ + {0x0afa, 0x2315}, /* telephonerecorder ⌕ TELEPHONE RECORDER */ + {0x0afb, 0x2117}, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ + {0x0afc, 0x2038}, /* caret ‸ CARET */ + {0x0afd, 0x201a}, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ + {0x0afe, 0x201e}, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ + /* 0x0aff cursor ? ??? */ + {0x0ba3, 0x003c}, /* leftcaret < LESS-THAN SIGN */ + {0x0ba6, 0x003e}, /* rightcaret > GREATER-THAN SIGN */ + {0x0ba8, 0x2228}, /* downcaret ∨ LOGICAL OR */ + {0x0ba9, 0x2227}, /* upcaret ∧ LOGICAL AND */ + {0x0bc0, 0x00af}, /* overbar ¯ MACRON */ + {0x0bc2, 0x22a4}, /* downtack ⊤ DOWN TACK */ + {0x0bc3, 0x2229}, /* upshoe ∩ INTERSECTION */ + {0x0bc4, 0x230a}, /* downstile ⌊ LEFT FLOOR */ + {0x0bc6, 0x005f}, /* underbar _ LOW LINE */ + {0x0bca, 0x2218}, /* jot ∘ RING OPERATOR */ + {0x0bcc, 0x2395}, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ + {0x0bce, 0x22a5}, /* uptack ⊥ UP TACK */ + {0x0bcf, 0x25cb}, /* circle ○ WHITE CIRCLE */ + {0x0bd3, 0x2308}, /* upstile ⌈ LEFT CEILING */ + {0x0bd6, 0x222a}, /* downshoe ∪ UNION */ + {0x0bd8, 0x2283}, /* rightshoe ⊃ SUPERSET OF */ + {0x0bda, 0x2282}, /* leftshoe ⊂ SUBSET OF */ + {0x0bdc, 0x22a3}, /* lefttack ⊣ LEFT TACK */ + {0x0bfc, 0x22a2}, /* righttack ⊢ RIGHT TACK */ + {0x0cdf, 0x2017}, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ + {0x0ce0, 0x05d0}, /* hebrew_aleph א HEBREW LETTER ALEF */ + {0x0ce1, 0x05d1}, /* hebrew_bet ב HEBREW LETTER BET */ + {0x0ce2, 0x05d2}, /* hebrew_gimel ג HEBREW LETTER GIMEL */ + {0x0ce3, 0x05d3}, /* hebrew_dalet ד HEBREW LETTER DALET */ + {0x0ce4, 0x05d4}, /* hebrew_he ה HEBREW LETTER HE */ + {0x0ce5, 0x05d5}, /* hebrew_waw ו HEBREW LETTER VAV */ + {0x0ce6, 0x05d6}, /* hebrew_zain ז HEBREW LETTER ZAYIN */ + {0x0ce7, 0x05d7}, /* hebrew_chet ח HEBREW LETTER HET */ + {0x0ce8, 0x05d8}, /* hebrew_tet ט HEBREW LETTER TET */ + {0x0ce9, 0x05d9}, /* hebrew_yod י HEBREW LETTER YOD */ + {0x0cea, 0x05da}, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ + {0x0ceb, 0x05db}, /* hebrew_kaph כ HEBREW LETTER KAF */ + {0x0cec, 0x05dc}, /* hebrew_lamed ל HEBREW LETTER LAMED */ + {0x0ced, 0x05dd}, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ + {0x0cee, 0x05de}, /* hebrew_mem מ HEBREW LETTER MEM */ + {0x0cef, 0x05df}, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ + {0x0cf0, 0x05e0}, /* hebrew_nun נ HEBREW LETTER NUN */ + {0x0cf1, 0x05e1}, /* hebrew_samech ס HEBREW LETTER SAMEKH */ + {0x0cf2, 0x05e2}, /* hebrew_ayin ע HEBREW LETTER AYIN */ + {0x0cf3, 0x05e3}, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ + {0x0cf4, 0x05e4}, /* hebrew_pe פ HEBREW LETTER PE */ + {0x0cf5, 0x05e5}, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ + {0x0cf6, 0x05e6}, /* hebrew_zade צ HEBREW LETTER TSADI */ + {0x0cf7, 0x05e7}, /* hebrew_qoph ק HEBREW LETTER QOF */ + {0x0cf8, 0x05e8}, /* hebrew_resh ר HEBREW LETTER RESH */ + {0x0cf9, 0x05e9}, /* hebrew_shin ש HEBREW LETTER SHIN */ + {0x0cfa, 0x05ea}, /* hebrew_taw ת HEBREW LETTER TAV */ + {0x0da1, 0x0e01}, /* Thai_kokai ก THAI CHARACTER KO KAI */ + {0x0da2, 0x0e02}, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ + {0x0da3, 0x0e03}, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ + {0x0da4, 0x0e04}, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ + {0x0da5, 0x0e05}, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ + {0x0da6, 0x0e06}, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ + {0x0da7, 0x0e07}, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ + {0x0da8, 0x0e08}, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ + {0x0da9, 0x0e09}, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ + {0x0daa, 0x0e0a}, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ + {0x0dab, 0x0e0b}, /* Thai_soso ซ THAI CHARACTER SO SO */ + {0x0dac, 0x0e0c}, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ + {0x0dad, 0x0e0d}, /* Thai_yoying ญ THAI CHARACTER YO YING */ + {0x0dae, 0x0e0e}, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ + {0x0daf, 0x0e0f}, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ + {0x0db0, 0x0e10}, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ + {0x0db1, 0x0e11}, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ + {0x0db2, 0x0e12}, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ + {0x0db3, 0x0e13}, /* Thai_nonen ณ THAI CHARACTER NO NEN */ + {0x0db4, 0x0e14}, /* Thai_dodek ด THAI CHARACTER DO DEK */ + {0x0db5, 0x0e15}, /* Thai_totao ต THAI CHARACTER TO TAO */ + {0x0db6, 0x0e16}, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ + {0x0db7, 0x0e17}, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ + {0x0db8, 0x0e18}, /* Thai_thothong ธ THAI CHARACTER THO THONG */ + {0x0db9, 0x0e19}, /* Thai_nonu น THAI CHARACTER NO NU */ + {0x0dba, 0x0e1a}, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ + {0x0dbb, 0x0e1b}, /* Thai_popla ป THAI CHARACTER PO PLA */ + {0x0dbc, 0x0e1c}, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ + {0x0dbd, 0x0e1d}, /* Thai_fofa ฝ THAI CHARACTER FO FA */ + {0x0dbe, 0x0e1e}, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ + {0x0dbf, 0x0e1f}, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ + {0x0dc0, 0x0e20}, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ + {0x0dc1, 0x0e21}, /* Thai_moma ม THAI CHARACTER MO MA */ + {0x0dc2, 0x0e22}, /* Thai_yoyak ย THAI CHARACTER YO YAK */ + {0x0dc3, 0x0e23}, /* Thai_rorua ร THAI CHARACTER RO RUA */ + {0x0dc4, 0x0e24}, /* Thai_ru ฤ THAI CHARACTER RU */ + {0x0dc5, 0x0e25}, /* Thai_loling ล THAI CHARACTER LO LING */ + {0x0dc6, 0x0e26}, /* Thai_lu ฦ THAI CHARACTER LU */ + {0x0dc7, 0x0e27}, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ + {0x0dc8, 0x0e28}, /* Thai_sosala ศ THAI CHARACTER SO SALA */ + {0x0dc9, 0x0e29}, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ + {0x0dca, 0x0e2a}, /* Thai_sosua ส THAI CHARACTER SO SUA */ + {0x0dcb, 0x0e2b}, /* Thai_hohip ห THAI CHARACTER HO HIP */ + {0x0dcc, 0x0e2c}, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ + {0x0dcd, 0x0e2d}, /* Thai_oang อ THAI CHARACTER O ANG */ + {0x0dce, 0x0e2e}, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ + {0x0dcf, 0x0e2f}, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ + {0x0dd0, 0x0e30}, /* Thai_saraa ะ THAI CHARACTER SARA A */ + {0x0dd1, 0x0e31}, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ + {0x0dd2, 0x0e32}, /* Thai_saraaa า THAI CHARACTER SARA AA */ + {0x0dd3, 0x0e33}, /* Thai_saraam ำ THAI CHARACTER SARA AM */ + {0x0dd4, 0x0e34}, /* Thai_sarai ิ THAI CHARACTER SARA I */ + {0x0dd5, 0x0e35}, /* Thai_saraii ี THAI CHARACTER SARA II */ + {0x0dd6, 0x0e36}, /* Thai_saraue ึ THAI CHARACTER SARA UE */ + {0x0dd7, 0x0e37}, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ + {0x0dd8, 0x0e38}, /* Thai_sarau ุ THAI CHARACTER SARA U */ + {0x0dd9, 0x0e39}, /* Thai_sarauu ู THAI CHARACTER SARA UU */ + {0x0dda, 0x0e3a}, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ + {0x0dde, 0x0e3e}, /* Thai_maihanakat_maitho ฾ ??? */ + {0x0ddf, 0x0e3f}, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ + {0x0de0, 0x0e40}, /* Thai_sarae เ THAI CHARACTER SARA E */ + {0x0de1, 0x0e41}, /* Thai_saraae แ THAI CHARACTER SARA AE */ + {0x0de2, 0x0e42}, /* Thai_sarao โ THAI CHARACTER SARA O */ + {0x0de3, 0x0e43}, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ + {0x0de4, 0x0e44}, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ + {0x0de5, 0x0e45}, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ + {0x0de6, 0x0e46}, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ + {0x0de7, 0x0e47}, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ + {0x0de8, 0x0e48}, /* Thai_maiek ่ THAI CHARACTER MAI EK */ + {0x0de9, 0x0e49}, /* Thai_maitho ้ THAI CHARACTER MAI THO */ + {0x0dea, 0x0e4a}, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ + {0x0deb, 0x0e4b}, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ + {0x0dec, 0x0e4c}, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ + {0x0ded, 0x0e4d}, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ + {0x0df0, 0x0e50}, /* Thai_leksun ๐ THAI DIGIT ZERO */ + {0x0df1, 0x0e51}, /* Thai_leknung ๑ THAI DIGIT ONE */ + {0x0df2, 0x0e52}, /* Thai_leksong ๒ THAI DIGIT TWO */ + {0x0df3, 0x0e53}, /* Thai_leksam ๓ THAI DIGIT THREE */ + {0x0df4, 0x0e54}, /* Thai_leksi ๔ THAI DIGIT FOUR */ + {0x0df5, 0x0e55}, /* Thai_lekha ๕ THAI DIGIT FIVE */ + {0x0df6, 0x0e56}, /* Thai_lekhok ๖ THAI DIGIT SIX */ + {0x0df7, 0x0e57}, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ + {0x0df8, 0x0e58}, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ + {0x0df9, 0x0e59}, /* Thai_lekkao ๙ THAI DIGIT NINE */ + {0x0ea1, 0x3131}, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ + {0x0ea2, 0x3132}, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ + {0x0ea3, 0x3133}, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ + {0x0ea4, 0x3134}, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ + {0x0ea5, 0x3135}, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ + {0x0ea6, 0x3136}, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ + {0x0ea7, 0x3137}, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ + {0x0ea8, 0x3138}, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ + {0x0ea9, 0x3139}, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ + {0x0eaa, 0x313a}, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ + {0x0eab, 0x313b}, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ + {0x0eac, 0x313c}, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ + {0x0ead, 0x313d}, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ + {0x0eae, 0x313e}, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ + {0x0eaf, 0x313f}, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ + {0x0eb0, 0x3140}, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ + {0x0eb1, 0x3141}, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ + {0x0eb2, 0x3142}, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ + {0x0eb3, 0x3143}, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ + {0x0eb4, 0x3144}, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ + {0x0eb5, 0x3145}, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ + {0x0eb6, 0x3146}, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ + {0x0eb7, 0x3147}, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ + {0x0eb8, 0x3148}, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ + {0x0eb9, 0x3149}, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ + {0x0eba, 0x314a}, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ + {0x0ebb, 0x314b}, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ + {0x0ebc, 0x314c}, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ + {0x0ebd, 0x314d}, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ + {0x0ebe, 0x314e}, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ + {0x0ebf, 0x314f}, /* Hangul_A ㅏ HANGUL LETTER A */ + {0x0ec0, 0x3150}, /* Hangul_AE ㅐ HANGUL LETTER AE */ + {0x0ec1, 0x3151}, /* Hangul_YA ㅑ HANGUL LETTER YA */ + {0x0ec2, 0x3152}, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ + {0x0ec3, 0x3153}, /* Hangul_EO ㅓ HANGUL LETTER EO */ + {0x0ec4, 0x3154}, /* Hangul_E ㅔ HANGUL LETTER E */ + {0x0ec5, 0x3155}, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ + {0x0ec6, 0x3156}, /* Hangul_YE ㅖ HANGUL LETTER YE */ + {0x0ec7, 0x3157}, /* Hangul_O ㅗ HANGUL LETTER O */ + {0x0ec8, 0x3158}, /* Hangul_WA ㅘ HANGUL LETTER WA */ + {0x0ec9, 0x3159}, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ + {0x0eca, 0x315a}, /* Hangul_OE ㅚ HANGUL LETTER OE */ + {0x0ecb, 0x315b}, /* Hangul_YO ㅛ HANGUL LETTER YO */ + {0x0ecc, 0x315c}, /* Hangul_U ㅜ HANGUL LETTER U */ + {0x0ecd, 0x315d}, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ + {0x0ece, 0x315e}, /* Hangul_WE ㅞ HANGUL LETTER WE */ + {0x0ecf, 0x315f}, /* Hangul_WI ㅟ HANGUL LETTER WI */ + {0x0ed0, 0x3160}, /* Hangul_YU ㅠ HANGUL LETTER YU */ + {0x0ed1, 0x3161}, /* Hangul_EU ㅡ HANGUL LETTER EU */ + {0x0ed2, 0x3162}, /* Hangul_YI ㅢ HANGUL LETTER YI */ + {0x0ed3, 0x3163}, /* Hangul_I ㅣ HANGUL LETTER I */ + {0x0ed4, 0x11a8}, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ + {0x0ed5, 0x11a9}, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ + {0x0ed6, 0x11aa}, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ + {0x0ed7, 0x11ab}, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ + {0x0ed8, 0x11ac}, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ + {0x0ed9, 0x11ad}, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ + {0x0eda, 0x11ae}, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ + {0x0edb, 0x11af}, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ + {0x0edc, 0x11b0}, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ + {0x0edd, 0x11b1}, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ + {0x0ede, 0x11b2}, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ + {0x0edf, 0x11b3}, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ + {0x0ee0, 0x11b4}, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ + {0x0ee1, 0x11b5}, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ + {0x0ee2, 0x11b6}, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ + {0x0ee3, 0x11b7}, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ + {0x0ee4, 0x11b8}, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ + {0x0ee5, 0x11b9}, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ + {0x0ee6, 0x11ba}, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ + {0x0ee7, 0x11bb}, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ + {0x0ee8, 0x11bc}, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ + {0x0ee9, 0x11bd}, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ + {0x0eea, 0x11be}, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ + {0x0eeb, 0x11bf}, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ + {0x0eec, 0x11c0}, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ + {0x0eed, 0x11c1}, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ + {0x0eee, 0x11c2}, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ + {0x0eef, 0x316d}, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ + {0x0ef0, 0x3171}, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ + {0x0ef1, 0x3178}, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ + {0x0ef2, 0x317f}, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ + /* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */ + {0x0ef4, 0x3184}, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ + {0x0ef5, 0x3186}, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ + {0x0ef6, 0x318d}, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ + {0x0ef7, 0x318e}, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ + {0x0ef8, 0x11eb}, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ + /* 0x0ef9 Hangul_J_KkogjiDalrinIeung ? ??? */ + {0x0efa, 0x11f9}, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ + {0x0eff, 0x20a9}, /* Korean_Won ₩ WON SIGN */ + {0x13bc, 0x0152}, /* OE Œ LATIN CAPITAL LIGATURE OE */ + {0x13bd, 0x0153}, /* oe œ LATIN SMALL LIGATURE OE */ + {0x13be, 0x0178}, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ + {0x20ac, 0x20ac}, /* EuroSign € EURO SIGN */ }; long keysym2ucs(xcb_keysym_t keysym) { diff --git a/i3bar/include/common.h b/i3bar/include/common.h index 0929e408..77be3182 100644 --- a/i3bar/include/common.h +++ b/i3bar/include/common.h @@ -74,10 +74,12 @@ struct status_block { char *name; char *instance; - TAILQ_ENTRY(status_block) blocks; + TAILQ_ENTRY(status_block) + blocks; }; -TAILQ_HEAD(statusline_head, status_block) statusline_head; +TAILQ_HEAD(statusline_head, status_block) +statusline_head; #include "child.h" #include "ipc.h" diff --git a/i3bar/include/configuration.h b/i3bar/include/configuration.h index c7c1f5e2..e77e891b 100644 --- a/i3bar/include/configuration.h +++ b/i3bar/include/configuration.h @@ -28,18 +28,23 @@ typedef struct binding_t { int input_code; char *command; - TAILQ_ENTRY(binding_t) bindings; + TAILQ_ENTRY(binding_t) + bindings; } binding_t; typedef struct tray_output_t { char *output; - TAILQ_ENTRY(tray_output_t) tray_outputs; + TAILQ_ENTRY(tray_output_t) + tray_outputs; } tray_output_t; typedef struct config_t { int modifier; - TAILQ_HEAD(bindings_head, binding_t) bindings; + + TAILQ_HEAD(bindings_head, binding_t) + bindings; + position_t position; int verbose; struct xcb_color_strings_t colors; @@ -50,7 +55,10 @@ typedef struct config_t { char *command; char *fontname; i3String *separator_symbol; - TAILQ_HEAD(tray_outputs_head, tray_output_t) tray_outputs; + + TAILQ_HEAD(tray_outputs_head, tray_output_t) + tray_outputs; + int tray_padding; int num_outputs; char **outputs; diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index 3067581d..de960270 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -67,5 +67,6 @@ struct i3_output { struct ws_head* workspaces; /* The workspaces on this output */ struct tc_head* trayclients; /* The tray clients on this output */ - SLIST_ENTRY(i3_output) slist; /* Pointer for the SLIST-Macro */ + SLIST_ENTRY(i3_output) + slist; /* Pointer for the SLIST-Macro */ }; diff --git a/i3bar/include/trayclients.h b/i3bar/include/trayclients.h index 694faa48..db954bb1 100644 --- a/i3bar/include/trayclients.h +++ b/i3bar/include/trayclients.h @@ -18,5 +18,6 @@ struct trayclient { bool mapped; /* Whether this window is mapped */ int xe_version; /* The XEMBED version supported by the client */ - TAILQ_ENTRY(trayclient) tailq; /* Pointer for the TAILQ-Macro */ + TAILQ_ENTRY(trayclient) + tailq; /* Pointer for the TAILQ-Macro */ }; diff --git a/i3bar/include/workspaces.h b/i3bar/include/workspaces.h index dde8b6e1..e1f9e887 100644 --- a/i3bar/include/workspaces.h +++ b/i3bar/include/workspaces.h @@ -40,5 +40,6 @@ struct i3_ws { rect rect; /* The rect of the ws (not used (yet)) */ struct i3_output *output; /* The current output of the ws */ - TAILQ_ENTRY(i3_ws) tailq; /* Pointer for the TAILQ-Macro */ + TAILQ_ENTRY(i3_ws) + tailq; /* Pointer for the TAILQ-Macro */ }; diff --git a/include/configuration.h b/include/configuration.h index b7cdc804..f93afde7 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -68,7 +68,8 @@ struct Variable { char *value; char *next_match; - SLIST_ENTRY(Variable) variables; + SLIST_ENTRY(Variable) + variables; }; /** @@ -82,7 +83,8 @@ struct Mode { bool pango_markup; struct bindings_head *bindings; - SLIST_ENTRY(Mode) modes; + SLIST_ENTRY(Mode) + modes; }; /** @@ -253,7 +255,8 @@ struct Barconfig { /* List of outputs on which the tray is allowed to be shown, in order. * The special value "none" disables it (per default, it will be shown) and * the special value "primary" enabled it on the primary output. */ - TAILQ_HEAD(tray_outputs_head, tray_output_t) tray_outputs; + TAILQ_HEAD(tray_outputs_head, tray_output_t) + tray_outputs; /* Padding around the tray icons. */ int tray_padding; @@ -284,7 +287,8 @@ struct Barconfig { M_MOD5 = 7 } modifier; - TAILQ_HEAD(bar_bindings_head, Barbinding) bar_bindings; + TAILQ_HEAD(bar_bindings_head, Barbinding) + bar_bindings; /** Bar position (bottom by default). */ enum { P_BOTTOM = 0, @@ -351,7 +355,8 @@ struct Barconfig { char *binding_mode_text; } colors; - TAILQ_ENTRY(Barconfig) configs; + TAILQ_ENTRY(Barconfig) + configs; }; /** @@ -366,13 +371,15 @@ struct Barbinding { /** The command which is to be executed for this button. */ char *command; - TAILQ_ENTRY(Barbinding) bindings; + TAILQ_ENTRY(Barbinding) + bindings; }; struct tray_output_t { char *output; - TAILQ_ENTRY(tray_output_t) tray_outputs; + TAILQ_ENTRY(tray_output_t) + tray_outputs; }; /** diff --git a/include/data.h b/include/data.h index a729b21e..410f2e0d 100644 --- a/include/data.h +++ b/include/data.h @@ -199,7 +199,8 @@ struct Workspace_Assignment { char *name; char *output; - TAILQ_ENTRY(Workspace_Assignment) ws_assignments; + TAILQ_ENTRY(Workspace_Assignment) + ws_assignments; }; struct Ignore_Event { @@ -207,7 +208,8 @@ struct Ignore_Event { int response_type; time_t added; - SLIST_ENTRY(Ignore_Event) ignore_events; + SLIST_ENTRY(Ignore_Event) + ignore_events; }; /** @@ -226,7 +228,8 @@ struct Startup_Sequence { * completed) */ time_t delete_at; - TAILQ_ENTRY(Startup_Sequence) sequences; + TAILQ_ENTRY(Startup_Sequence) + sequences; }; /** @@ -252,7 +255,9 @@ struct regex { struct Binding_Keycode { xcb_keycode_t keycode; i3_event_state_mask_t modifiers; - TAILQ_ENTRY(Binding_Keycode) keycodes; + + TAILQ_ENTRY(Binding_Keycode) + keycodes; }; /****************************************************************************** @@ -309,12 +314,14 @@ struct Binding { /** Only in use if symbol != NULL. Contains keycodes which generate the * specified symbol. Useful for unbinding and checking which binding was * used when a key press event comes in. */ - TAILQ_HEAD(keycodes_head, Binding_Keycode) keycodes_head; + TAILQ_HEAD(keycodes_head, Binding_Keycode) + keycodes_head; /** Command, like in command mode */ char *command; - TAILQ_ENTRY(Binding) bindings; + TAILQ_ENTRY(Binding) + bindings; }; /** @@ -330,8 +337,12 @@ struct Autostart { /** no_startup_id flag for start_application(). Determines whether a * startup notification context/ID should be created. */ bool no_startup_id; - TAILQ_ENTRY(Autostart) autostarts; - TAILQ_ENTRY(Autostart) autostarts_always; + + TAILQ_ENTRY(Autostart) + autostarts; + + TAILQ_ENTRY(Autostart) + autostarts_always; }; /** @@ -364,7 +375,8 @@ struct xoutput { /** x, y, width, height */ Rect rect; - TAILQ_ENTRY(xoutput) outputs; + TAILQ_ENTRY(xoutput) + outputs; }; /** @@ -493,7 +505,8 @@ struct Match { M_ASSIGN_WS, M_BELOW } insert_where; - TAILQ_ENTRY(Match) matches; + TAILQ_ENTRY(Match) + matches; /* Whether this match was generated when restarting i3 inplace. * Leads to not setting focus when managing a new window, because the old @@ -537,7 +550,8 @@ struct Assignment { char *workspace; } dest; - TAILQ_ENTRY(Assignment) assignments; + TAILQ_ENTRY(Assignment) + assignments; }; /** Fullscreen modes. Used by Con.fullscreen_mode. */ @@ -548,7 +562,8 @@ typedef enum { CF_NONE = 0, struct mark_t { char *name; - TAILQ_ENTRY(mark_t) marks; + TAILQ_ENTRY(mark_t) + marks; }; /** @@ -612,7 +627,8 @@ struct Con { char *sticky_group; /* user-definable marks to jump to this container later */ - TAILQ_HEAD(marks_head, mark_t) marks_head; + TAILQ_HEAD(marks_head, mark_t) + marks_head; /* cached to decide whether a redraw is needed */ bool mark_changed; @@ -631,12 +647,17 @@ struct Con { struct deco_render_params *deco_render_params; /* Only workspace-containers can have floating clients */ - TAILQ_HEAD(floating_head, Con) floating_head; + TAILQ_HEAD(floating_head, Con) + floating_head; - TAILQ_HEAD(nodes_head, Con) nodes_head; - TAILQ_HEAD(focus_head, Con) focus_head; + TAILQ_HEAD(nodes_head, Con) + nodes_head; - TAILQ_HEAD(swallow_head, Match) swallow_head; + TAILQ_HEAD(focus_head, Con) + focus_head; + + TAILQ_HEAD(swallow_head, Match) + swallow_head; fullscreen_mode_t fullscreen_mode; @@ -674,10 +695,17 @@ struct Con { FLOATING_USER_ON = 3 } floating; - TAILQ_ENTRY(Con) nodes; - TAILQ_ENTRY(Con) focused; - TAILQ_ENTRY(Con) all_cons; - TAILQ_ENTRY(Con) floating_windows; + TAILQ_ENTRY(Con) + nodes; + + TAILQ_ENTRY(Con) + focused; + + TAILQ_ENTRY(Con) + all_cons; + + TAILQ_ENTRY(Con) + floating_windows; /** callbacks */ void (*on_remove_child)(Con *); diff --git a/include/ipc.h b/include/ipc.h index 5c528a6d..7ff4704c 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -31,7 +31,8 @@ typedef struct ipc_client { int num_events; char **events; - TAILQ_ENTRY(ipc_client) clients; + TAILQ_ENTRY(ipc_client) + clients; } ipc_client; /* diff --git a/include/queue.h b/include/queue.h index 9fb9ba5e..9b410449 100644 --- a/include/queue.h +++ b/include/queue.h @@ -446,7 +446,10 @@ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + { \ + CIRCLEQ_END(&head) \ + , CIRCLEQ_END(&head) \ + } #define CIRCLEQ_ENTRY(type) \ struct { \ diff --git a/src/commands.c b/src/commands.c index b91c71a4..70622b7d 100644 --- a/src/commands.c +++ b/src/commands.c @@ -142,7 +142,9 @@ static Con *maybe_auto_back_and_forth_workspace(Con *workspace) { */ typedef struct owindow { Con *con; - TAILQ_ENTRY(owindow) owindows; + + TAILQ_ENTRY(owindow) + owindows; } owindow; typedef TAILQ_HEAD(owindows_head, owindow) owindows_head; diff --git a/src/con.c b/src/con.c index 36225415..40924a73 100644 --- a/src/con.c +++ b/src/con.c @@ -410,7 +410,8 @@ Con *con_parent_with_orientation(Con *con, orientation_t orientation) { struct bfs_entry { Con *con; - TAILQ_ENTRY(bfs_entry) entries; + TAILQ_ENTRY(bfs_entry) + entries; }; /* @@ -422,7 +423,9 @@ Con *con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode) { /* TODO: is breadth-first-search really appropriate? (check as soon as * fullscreen levels and fullscreen for containers is implemented) */ - TAILQ_HEAD(bfs_head, bfs_entry) bfs_head = TAILQ_HEAD_INITIALIZER(bfs_head); + TAILQ_HEAD(bfs_head, bfs_entry) + bfs_head = TAILQ_HEAD_INITIALIZER(bfs_head); + struct bfs_entry *entry = smalloc(sizeof(struct bfs_entry)); entry->con = con; TAILQ_INSERT_TAIL(&bfs_head, entry, entries); diff --git a/src/config_parser.c b/src/config_parser.c index a8265869..60b27815 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -1002,7 +1002,7 @@ bool parse_file(const char *f, bool use_nagbar) { char *next; for (next = bufcopy; next < (bufcopy + stbuf.st_size) && - (next = strcasestr(next, current->key)) != NULL; + (next = strcasestr(next, current->key)) != NULL; next += strlen(current->key)) { *next = '_'; extra_bytes += extra; diff --git a/src/ipc.c b/src/ipc.c index c0dfb1ec..db2fa362 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -22,7 +22,8 @@ char *current_socketpath = NULL; -TAILQ_HEAD(ipc_client_head, ipc_client) all_clients = TAILQ_HEAD_INITIALIZER(all_clients); +TAILQ_HEAD(ipc_client_head, ipc_client) +all_clients = TAILQ_HEAD_INITIALIZER(all_clients); /* * Puts the given socket file descriptor into non-blocking mode or dies if diff --git a/src/load_layout.c b/src/load_layout.c index 7004a859..f6f045d2 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -34,7 +34,9 @@ static bool swallow_is_empty; * array. */ struct focus_mapping { int old_id; - TAILQ_ENTRY(focus_mapping) focus_mappings; + + TAILQ_ENTRY(focus_mapping) + focus_mappings; }; static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings = diff --git a/src/match.c b/src/match.c index 4d87c560..9185537b 100644 --- a/src/match.c +++ b/src/match.c @@ -167,7 +167,7 @@ bool match_matches_window(Match *match, i3Window *window) { /* if we find a window that is newer than this one, bail */ TAILQ_FOREACH(con, &all_cons, all_cons) { if ((con->window != NULL) && - _i3_timercmp(con->window->urgent, window->urgent, > )) { + _i3_timercmp(con->window->urgent, window->urgent, >)) { return false; } } @@ -183,7 +183,7 @@ bool match_matches_window(Match *match, i3Window *window) { TAILQ_FOREACH(con, &all_cons, all_cons) { if ((con->window != NULL) && (con->window->urgent.tv_sec != 0) && - _i3_timercmp(con->window->urgent, window->urgent, < )) { + _i3_timercmp(con->window->urgent, window->urgent, <)) { return false; } } diff --git a/src/restore_layout.c b/src/restore_layout.c index 131196e9..d48e5c6e 100644 --- a/src/restore_layout.c +++ b/src/restore_layout.c @@ -29,7 +29,8 @@ typedef struct placeholder_state { /** The graphics context for “pixmap”. */ xcb_gcontext_t gc; - TAILQ_ENTRY(placeholder_state) state; + TAILQ_ENTRY(placeholder_state) + state; } placeholder_state; static TAILQ_HEAD(state_head, placeholder_state) state_head = diff --git a/src/x.c b/src/x.c index 8d7d3dd8..c2153d5c 100644 --- a/src/x.c +++ b/src/x.c @@ -58,18 +58,26 @@ typedef struct con_state { char *name; - CIRCLEQ_ENTRY(con_state) state; - CIRCLEQ_ENTRY(con_state) old_state; - TAILQ_ENTRY(con_state) initial_mapping_order; + CIRCLEQ_ENTRY(con_state) + state; + + CIRCLEQ_ENTRY(con_state) + old_state; + + TAILQ_ENTRY(con_state) + initial_mapping_order; } con_state; -CIRCLEQ_HEAD(state_head, con_state) state_head = +CIRCLEQ_HEAD(state_head, con_state) +state_head = CIRCLEQ_HEAD_INITIALIZER(state_head); -CIRCLEQ_HEAD(old_state_head, con_state) old_state_head = +CIRCLEQ_HEAD(old_state_head, con_state) +old_state_head = CIRCLEQ_HEAD_INITIALIZER(old_state_head); -TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head = +TAILQ_HEAD(initial_mapping_head, con_state) +initial_mapping_head = TAILQ_HEAD_INITIALIZER(initial_mapping_head); /* diff --git a/travis/check-formatting.sh b/travis/check-formatting.sh index ead25157..ff406bea 100755 --- a/travis/check-formatting.sh +++ b/travis/check-formatting.sh @@ -3,4 +3,4 @@ set -e set -x -clang-format-3.5 -i $(find . -name "*.[ch]" | tr '\n' ' ') && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) +clang-format-3.8 -i $(find . -name "*.[ch]" | tr '\n' ' ') && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) diff --git a/travis/travis-base-386.Dockerfile b/travis/travis-base-386.Dockerfile index 9f2b8129..ddb3874e 100644 --- a/travis/travis-base-386.Dockerfile +++ b/travis/travis-base-386.Dockerfile @@ -13,12 +13,12 @@ RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry # (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. # Install mk-build-deps (for installing the i3 build dependencies), -# clang and clang-format-3.5 (for checking formatting and building with clang), +# clang and clang-format-3.8 (for checking formatting and building with clang), # lintian (for checking spelling errors), RUN linux32 apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ dpkg-dev devscripts git equivs \ - clang clang-format-3.5 \ + clang clang-format-3.8 \ lintian && \ rm -rf /var/lib/apt/lists/* diff --git a/travis/travis-base-ubuntu-386.Dockerfile b/travis/travis-base-ubuntu-386.Dockerfile index 65f123c8..1014407a 100644 --- a/travis/travis-base-ubuntu-386.Dockerfile +++ b/travis/travis-base-ubuntu-386.Dockerfile @@ -13,12 +13,12 @@ RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry # (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. # Install mk-build-deps (for installing the i3 build dependencies), -# clang and clang-format-3.5 (for checking formatting and building with clang), +# clang and clang-format-3.8 (for checking formatting and building with clang), # lintian (for checking spelling errors), RUN linux32 apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ dpkg-dev devscripts git equivs \ - clang clang-format-3.5 \ + clang clang-format-3.8 \ lintian && \ rm -rf /var/lib/apt/lists/* diff --git a/travis/travis-base-ubuntu.Dockerfile b/travis/travis-base-ubuntu.Dockerfile index ab474691..0b4ec206 100644 --- a/travis/travis-base-ubuntu.Dockerfile +++ b/travis/travis-base-ubuntu.Dockerfile @@ -13,13 +13,13 @@ RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry # (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. # Install mk-build-deps (for installing the i3 build dependencies), -# clang and clang-format-3.5 (for checking formatting and building with clang), +# clang and clang-format-3.8 (for checking formatting and building with clang), # lintian (for checking spelling errors), # test suite dependencies (for running tests) RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ dpkg-dev devscripts git equivs \ - clang clang-format-3.5 \ + clang clang-format-3.8 \ lintian && \ rm -rf /var/lib/apt/lists/* diff --git a/travis/travis-base.Dockerfile b/travis/travis-base.Dockerfile index 85fa2752..a415f549 100644 --- a/travis/travis-base.Dockerfile +++ b/travis/travis-base.Dockerfile @@ -11,13 +11,13 @@ RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry # (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. # Install mk-build-deps (for installing the i3 build dependencies), -# clang and clang-format-3.5 (for checking formatting and building with clang), +# clang and clang-format-3.8 (for checking formatting and building with clang), # lintian (for checking spelling errors), # test suite dependencies (for running tests) RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ dpkg-dev devscripts git equivs \ - clang clang-format-3.5 \ + clang clang-format-3.8 \ lintian \ libanyevent-perl libanyevent-i3-perl libextutils-pkgconfig-perl xcb-proto cpanminus xvfb xserver-xephyr xauth libinline-perl libinline-c-perl libxml-simple-perl libmouse-perl libmousex-nativetraits-perl libextutils-depends-perl perl libtest-deep-perl libtest-exception-perl libxml-parser-perl libtest-simple-perl libtest-fatal-perl libdata-dump-perl libtest-differences-perl libxml-tokeparser-perl libipc-run-perl libxcb-xtest0-dev libx11-xcb-perl libanyevent-i3-perl && \ rm -rf /var/lib/apt/lists/* From 86ad867277b0de63537720ec49ca6523707660cb Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 8 Nov 2016 14:04:46 -0800 Subject: [PATCH 003/180] travis: switch to container-based trusty (#2550) fixes #2546 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f9744335..63f69ac8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -sudo: required +sudo: false dist: trusty services: - docker From c602ec7cc2203c03c62439bb3f35a3acfe9e2ed8 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Wed, 9 Nov 2016 22:34:39 +0100 Subject: [PATCH 004/180] Respect SYSCONFDIR when looking for defaut 'xdg' directory --- libi3/get_config_path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi3/get_config_path.c b/libi3/get_config_path.c index c47e6dd8..efece5cd 100644 --- a/libi3/get_config_path.c +++ b/libi3/get_config_path.c @@ -71,7 +71,7 @@ char *get_config_path(const char *override_configpath, bool use_system_paths) { /* 4: check for $XDG_CONFIG_DIRS/i3/config */ if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL) - xdg_config_dirs = "/etc/xdg"; + xdg_config_dirs = SYSCONFDIR "/xdg"; char *buf = sstrdup(xdg_config_dirs); char *tok = strtok(buf, ":"); From b494d27848beb166fae6503813ed1593f02e6f1e Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Wed, 9 Nov 2016 22:37:21 +0100 Subject: [PATCH 005/180] Accept calling absolute path when building outsource --- m4/ax_extend_srcdir.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m4/ax_extend_srcdir.m4 b/m4/ax_extend_srcdir.m4 index a308d67d..40f37878 100644 --- a/m4/ax_extend_srcdir.m4 +++ b/m4/ax_extend_srcdir.m4 @@ -74,7 +74,7 @@ AC_DEFUN([AX_EXTEND_SRCDIR], [dnl AS_CASE([$srcdir], - [.|.*], + [.|.*|/*], [ # pwd -P is specified in IEEE 1003.1 from 2004 as_dir=`cd "$srcdir" && pwd -P` From 6e519e18e14b5509ad4bcd28d7b41e6d3350f782 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 10 Nov 2016 00:25:30 -0800 Subject: [PATCH 006/180] release.sh: add reminder to announce on reddit (#2553) --- release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/release.sh b/release.sh index 9101332c..33cb4f53 100755 --- a/release.sh +++ b/release.sh @@ -236,3 +236,4 @@ echo "Announce on:" echo " twitter" echo " google+" echo " #i3 topic" +echo " reddit /r/i3wm" From ad7dec31d5785ce9006bbb8498529bead652d19c Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Sat, 12 Nov 2016 16:34:54 +0200 Subject: [PATCH 007/180] Use the DPI setting within the i3bar (#2556) --- i3bar/src/main.c | 2 ++ include/libi3.h | 6 ++++++ libi3/dpi.c | 8 ++++++++ libi3/font.c | 14 +------------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/i3bar/src/main.c b/i3bar/src/main.c index be684fc5..910e9524 100644 --- a/i3bar/src/main.c +++ b/i3bar/src/main.c @@ -149,6 +149,8 @@ int main(int argc, char **argv) { socket_path = expand_path(i3_default_sock_path); } + init_dpi(); + init_outputs(); if (init_connection(socket_path)) { /* Request the bar configuration. When it arrives, we fill the config array. */ diff --git a/include/libi3.h b/include/libi3.h index 11ca3127..94e1d78b 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -473,6 +473,12 @@ char *get_exe_path(const char *argv0); */ void init_dpi(void); +/** + * This function returns the value of the DPI setting. + * + */ +long get_dpi_value(void); + /** * Convert a logical amount of pixels (e.g. 2 pixels on a “standard” 96 DPI * screen) to a corresponding amount of physical pixels on a standard or retina diff --git a/libi3/dpi.c b/libi3/dpi.c index a832a689..d0d1bc68 100644 --- a/libi3/dpi.c +++ b/libi3/dpi.c @@ -64,6 +64,14 @@ init_dpi_end: } } +/* + * This function returns the value of the DPI setting. + * + */ +long get_dpi_value(void) { + return dpi; +} + /* * Convert a logical amount of pixels (e.g. 2 pixels on a “standard” 96 DPI * screen) to a corresponding amount of physical pixels on a standard or retina diff --git a/libi3/font.c b/libi3/font.c index fa848481..81091ea7 100644 --- a/libi3/font.c +++ b/libi3/font.c @@ -24,24 +24,12 @@ static double pango_font_red; static double pango_font_green; static double pango_font_blue; -/* Necessary to track whether the dpi changes and trigger a LOG() message, - * which is more easily visible to users. */ -static double logged_dpi = 0.0; - static PangoLayout *create_layout_with_dpi(cairo_t *cr) { PangoLayout *layout; PangoContext *context; context = pango_cairo_create_context(cr); - const double dpi = (double)root_screen->height_in_pixels * 25.4 / - (double)root_screen->height_in_millimeters; - if (logged_dpi != dpi) { - logged_dpi = dpi; - LOG("X11 root window dictates %f DPI\n", dpi); - } else { - DLOG("X11 root window dictates %f DPI\n", dpi); - } - pango_cairo_context_set_resolution(context, dpi); + pango_cairo_context_set_resolution(context, get_dpi_value()); layout = pango_layout_new(context); g_object_unref(context); From 9108f3214ce18b82ed3d21cee49adb48354360c6 Mon Sep 17 00:00:00 2001 From: Chih-Chyuan Hwang Date: Mon, 14 Nov 2016 02:45:39 +0800 Subject: [PATCH 008/180] Fix memory leaks (#2560) Fix memory leaks when executing 'i3 --moreversion'. ================================================================= ==14852==ERROR: LeakSanitizer: detected memory leaks Direct leak of 159 byte(s) in 1 object(s) allocated from: #0 0x7fea40855602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #1 0x4c4c4a in smalloc ../../i3/libi3/safewrappers.c:24 #2 0x4c3aee in ipc_recv_message ../../i3/libi3/ipc_recv_message.c:61 #3 0x44dc2e in display_running_version ../../i3/src/display_version.c:94 #4 0x472947 in main ../../i3/src/main.c:269 #5 0x7fea3d0c982f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) Direct leak of 39 byte(s) in 2 object(s) allocated from: #0 0x7fea40855602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #1 0x7fea3d11f7d7 in vasprintf (/lib/x86_64-linux-gnu/libc.so.6+0x767d7) SUMMARY: AddressSanitizer: 198 byte(s) leaked in 3 allocation(s). --- src/display_version.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/display_version.c b/src/display_version.c index 0e650e81..764ee753 100644 --- a/src/display_version.c +++ b/src/display_version.c @@ -182,4 +182,7 @@ void display_running_version(void) { #endif yajl_free(handle); + free(reply); + free(pid_from_atom); + free(socket_path); } From da5fe3b93463b70887c20f79cf0c6054e69cdb04 Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Tue, 15 Nov 2016 19:26:53 +0200 Subject: [PATCH 009/180] fix incorrect reply to ipc command (#2567) --- src/commands.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/commands.c b/src/commands.c index 70622b7d..2387ddd7 100644 --- a/src/commands.c +++ b/src/commands.c @@ -893,8 +893,10 @@ void cmd_workspace_number(I3_CMD, const char *which, const char *_no_auto_back_a cmd_output->needs_tree_render = true; return; } - if (!no_auto_back_and_forth && maybe_back_and_forth(cmd_output, workspace->name)) + if (!no_auto_back_and_forth && maybe_back_and_forth(cmd_output, workspace->name)) { + ysuccess(true); return; + } workspace_show(workspace); cmd_output->needs_tree_render = true; @@ -940,8 +942,10 @@ void cmd_workspace_name(I3_CMD, const char *name, const char *_no_auto_back_and_ } DLOG("should switch to workspace %s\n", name); - if (!no_auto_back_and_forth && maybe_back_and_forth(cmd_output, name)) + if (!no_auto_back_and_forth && maybe_back_and_forth(cmd_output, name)) { + ysuccess(true); return; + } workspace_show_by_name(name); cmd_output->needs_tree_render = true; From aa20c416c38426e790543dca2652b083a52d8a58 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 19 Nov 2016 14:45:22 -0800 Subject: [PATCH 010/180] configure.ac: verify macros in m4/ are being replaced (Thanks sur5r) (#2571) See the comment for more details, and see the motivating blog post: https://blogs.noname-ev.de/sur5r/index.php?/archives/7-Another-instance-of-AC_DEFINE-being-undefined.html --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index 1a91b3b1..b57f9efa 100644 --- a/configure.ac +++ b/configure.ac @@ -15,6 +15,12 @@ AC_CONFIG_SRCDIR([libi3/ipc_recv_message.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) +dnl Verify macros defined in m4/ such as AX_SANITIZERS are not present in the +dnl output, i.e. are replaced as expected. This line results in a better error +dnl message when using aclocal < 1.13 (which does not understand +dnl AC_CONFIG_MACRO_DIR) without passing the -I m4 parameter. +m4_pattern_forbid([AX_SANITIZERS]) + # Verify we are using GNU make because we use '%'-style pattern rules in # Makefile.am, which are a GNU make extension. Pull requests to replace # '%'-style pattern rules with a more portable alternative are welcome. From 3e7a07e48d3c8e32b39c54000e8ebe0d02d47112 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 20 Nov 2016 23:20:14 -0800 Subject: [PATCH 011/180] tests: add inject_randr15 (#2573) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This tool is similar to xtrace in usage in that it intercepts traffic to the X server. The motivating feature for writing the tool is its ability to inject prepared reply messages instead of the server’s reply. In this particular case, we’ll inject a RRGetMonitors reply to test i3’s RandR 1.5 code paths. The added testcase is a noop for now, but with the code that’s lingering in the randr15 branch, i3 does actually detect monitors as per the injected reply: 2016-11-20 21:10:05 - randr.c:__randr_query_outputs:618 - RandR 1.5 available, querying monitors 2016-11-20 21:10:05 - randr.c:__randr_query_outputs:628 - 1 RandR monitors found (timestamp 0) 2016-11-20 21:10:05 - randr.c:__randr_query_outputs:646 - name DP3, x 0, y 0, width 3840 px, height 2160 px, width 520 mm, height 290 mm, primary 1, automatic 1 This is preparation work for issue #1799 --- Makefile.am | 18 +- testcases/inject_randr1.5.c | 441 ++++++++++++++++++++++++++++++ testcases/lib/SocketActivation.pm | 12 +- testcases/lib/i3test.pm.in | 1 + testcases/t/533-randr15.t | 73 +++++ 5 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 testcases/inject_randr1.5.c create mode 100644 testcases/t/533-randr15.t diff --git a/Makefile.am b/Makefile.am index c90e26c7..aea4256b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,7 +45,10 @@ dist_xsessions_DATA = \ noinst_LIBRARIES = libi3.a -check_PROGRAMS = test.commands_parser test.config_parser +check_PROGRAMS = \ + test.commands_parser \ + test.config_parser \ + test.inject_randr15 check_SCRIPTS = \ testcases/complete-run.pl @@ -401,6 +404,19 @@ i3_config_wizard_i3_config_wizard_SOURCES = \ i3-config-wizard/main.c \ i3-config-wizard/xcb.h +test_inject_randr15_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_inject_randr15_CFLAGS = \ + $(AM_CFLAGS) \ + $(i3_CFLAGS) + +test_inject_randr15_SOURCES = \ + testcases/inject_randr1.5.c + +test_inject_randr15_LDADD = \ + $(i3_LDADD) + test_commands_parser_CPPFLAGS = \ $(AM_CPPFLAGS) \ -DTEST_PARSER diff --git a/testcases/inject_randr1.5.c b/testcases/inject_randr1.5.c new file mode 100644 index 00000000..bd0df399 --- /dev/null +++ b/testcases/inject_randr1.5.c @@ -0,0 +1,441 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) + * + * inject_randr1.5.c: An X11 proxy which interprets RandR 1.5 GetMonitors + * requests and overwrites their reply with a custom reply. + * + * This tool can be refactored as necessary in order to perform the same + * purpose for other request types. The RandR 1.5 specific portions of the code + * have been marked as such to make such a refactoring easier. + * + */ +#include "all.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void uds_connection_cb(EV_P_ ev_io *w, int revents); +static void read_client_setup_request_cb(EV_P_ ev_io *w, int revents); +static void read_server_setup_reply_cb(EV_P_ ev_io *w, int revents); +static void read_client_x11_packet_cb(EV_P_ ev_io *w, int revents); +static void read_server_x11_packet_cb(EV_P_ ev_io *w, int revents); + +static char *sun_path = NULL; + +void cleanup_socket(void) { + if (sun_path != NULL) { + unlink(sun_path); + free(sun_path); + sun_path = NULL; + } +} + +/* BEGIN RandR 1.5 specific */ +static void *injected_reply = NULL; +static off_t injected_reply_len = 0; +/* END RandR 1.5 specific */ + +#define XCB_PAD(i) (-(i)&3) + +struct connstate { + /* clientw is a libev watcher for the connection which we accept()ed. */ + ev_io *clientw; + + /* serverw is a libev watcher for the connection to X11 which we initiated + * on behalf of the client. */ + ev_io *serverw; + + /* sequence is the client-side sequence number counter. In X11’s wire + * encoding, sequence counters are not included in requests, only in + * replies. */ + int sequence; + + /* BEGIN RandR 1.5 specific */ + /* sequence number of the most recent GetExtension request for RANDR */ + int getext_randr; + /* sequence number of the most recent RRGetMonitors request */ + int getmonitors; + + int randr_major_opcode; + /* END RandR 1.5 specific */ +}; + +/* + * Returns 0 on EOF + * Returns -1 on error (with errno from read() untouched) + * + */ +static size_t readall_into(void *buffer, const size_t len, int fd) { + size_t read_bytes = 0; + while (read_bytes < len) { + ssize_t n = read(fd, buffer + read_bytes, len - read_bytes); + if (n <= 0) { + return n; + } + read_bytes += (size_t)n; + } + return read_bytes; +} + +/* + * Exits the program with an error if the read failed. + * + */ +static void must_read(int n) { + if (n == -1) { + err(EXIT_FAILURE, "read()"); + } + if (n == 0) { + errx(EXIT_FAILURE, "EOF"); + } +} + +/* + * Exits the program with an error if the write failed. + * + */ +static void must_write(int n) { + if (n == -1) { + err(EXIT_FAILURE, "write()"); + } +} + +static void uds_connection_cb(EV_P_ ev_io *w, int revents) { + struct sockaddr_un addr; + socklen_t addrlen = sizeof(addr); + const int clientfd = accept(w->fd, (struct sockaddr *)&addr, &addrlen); + if (clientfd == -1) { + if (errno == EINTR) { + return; + } + err(EXIT_FAILURE, "accept()"); + } + + struct connstate *connstate = scalloc(1, sizeof(struct connstate)); + + ev_io *clientw = scalloc(1, sizeof(ev_io)); + connstate->clientw = clientw; + clientw->data = connstate; + ev_io_init(clientw, read_client_setup_request_cb, clientfd, EV_READ); + ev_io_start(EV_A_ clientw); +} + +// https://www.x.org/releases/current/doc/xproto/x11protocol.html#Encoding::Connection_Setup +static void read_client_setup_request_cb(EV_P_ ev_io *w, int revents) { + ev_io_stop(EV_A_ w); + struct connstate *connstate = (struct connstate *)w->data; + + /* Read X11 setup request in its entirety. */ + xcb_setup_request_t setup_request; + must_read(readall_into(&setup_request, sizeof(setup_request), w->fd)); + + /* Establish a connection to X11. */ + int fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd == -1) { + err(EXIT_FAILURE, "socket()"); + } + + char *host; + int displayp; + if (xcb_parse_display(getenv("DISPLAY"), &host, &displayp, NULL) == 0) { + errx(EXIT_FAILURE, "Could not parse DISPLAY=%s", getenv("DISPLAY")); + } + free(host); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/.X11-unix/X%d", displayp); + if (connect(fd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { + err(EXIT_FAILURE, "connect(%s)", addr.sun_path); + } + + /* Relay setup request. */ + must_write(writeall(fd, &setup_request, sizeof(setup_request))); + + if (setup_request.authorization_protocol_name_len > 0 || + setup_request.authorization_protocol_data_len > 0) { + const size_t authlen = setup_request.authorization_protocol_name_len + + XCB_PAD(setup_request.authorization_protocol_name_len) + + setup_request.authorization_protocol_data_len + + XCB_PAD(setup_request.authorization_protocol_data_len); + void *buf = smalloc(authlen); + must_read(readall_into(buf, authlen, w->fd)); + must_write(writeall(fd, buf, authlen)); + free(buf); + } + + /* Wait for a response from the X11 server. */ + ev_io *serverw = scalloc(1, sizeof(ev_io)); + connstate->serverw = serverw; + serverw->data = connstate; + ev_io_init(serverw, read_server_setup_reply_cb, fd, EV_READ); + ev_io_start(EV_A_ serverw); +} + +static void read_server_setup_reply_cb(EV_P_ ev_io *w, int revents) { + struct connstate *connstate = (struct connstate *)w->data; + xcb_setup_failed_t setup_failed; + must_read(readall_into(&setup_failed, sizeof(setup_failed), w->fd)); + + switch (setup_failed.status) { + case 0: + errx(EXIT_FAILURE, "error authenticating at the X11 server"); + + case 2: + errx(EXIT_FAILURE, "two-factor auth not implemented"); + + case 1: + must_write(writeall(connstate->clientw->fd, &setup_failed, sizeof(xcb_setup_failed_t))); + const size_t len = (setup_failed.length * 4); + void *buf = smalloc(len); + must_read(readall_into(buf, len, w->fd)); + must_write(writeall(connstate->clientw->fd, buf, len)); + free(buf); + + ev_set_cb(connstate->clientw, read_client_x11_packet_cb); + ev_set_cb(connstate->serverw, read_server_x11_packet_cb); + ev_io_start(EV_A_ connstate->clientw); + break; + + default: + errx(EXIT_FAILURE, "X11 protocol error: expected setup_failed.status in [0..2], got %d", setup_failed.status); + } +} + +// https://www.x.org/releases/current/doc/xproto/x11protocol.html#request_format +typedef struct { + uint8_t opcode; + uint8_t pad0; + uint16_t length; +} generic_x11_request_t; + +// https://www.x.org/releases/current/doc/xproto/x11protocol.html#reply_format +typedef struct { + uint8_t code; /* if 1, this is a reply. if 0, this is an error. else, an event */ + uint8_t pad0; + uint16_t sequence; + uint32_t length; +} generic_x11_reply_t; + +static void read_client_x11_packet_cb(EV_P_ ev_io *w, int revents) { + struct connstate *connstate = (struct connstate *)w->data; + + void *request = smalloc(sizeof(generic_x11_request_t)); + must_read(readall_into(request, sizeof(generic_x11_request_t), connstate->clientw->fd)); + const size_t len = (((generic_x11_request_t *)request)->length * 4); + if (len > sizeof(generic_x11_request_t)) { + request = srealloc(request, len); + must_read(readall_into(request + sizeof(generic_x11_request_t), + len - sizeof(generic_x11_request_t), + connstate->clientw->fd)); + } + + // XXX: sequence counter wrapping is not implemented, but should not be + // necessary given that this tool is scoped for test cases. + connstate->sequence++; + + /* BEGIN RandR 1.5 specific */ + const uint8_t opcode = ((generic_x11_request_t *)request)->opcode; + if (opcode == XCB_QUERY_EXTENSION) { + xcb_query_extension_request_t *req = request; + const char *name = request + sizeof(xcb_query_extension_request_t); + if (req->name_len == strlen("RANDR") && + strncmp(name, "RANDR", strlen("RANDR")) == 0) { + connstate->getext_randr = connstate->sequence; + } + } else if (opcode == connstate->randr_major_opcode) { + const uint8_t randr_opcode = ((generic_x11_request_t *)request)->pad0; + if (randr_opcode == XCB_RANDR_GET_MONITORS) { + connstate->getmonitors = connstate->sequence; + } + } + /* END RandR 1.5 specific */ + + must_write(writeall(connstate->serverw->fd, request, len)); + free(request); +} + +static void read_server_x11_packet_cb(EV_P_ ev_io *w, int revents) { + struct connstate *connstate = (struct connstate *)w->data; + // all packets from the server are at least 32 bytes in length + size_t len = 32; + void *packet = smalloc(len); + must_read(readall_into(packet, len, connstate->serverw->fd)); + switch (((generic_x11_reply_t *)packet)->code) { + case 0: // error + break; + + case 1: // reply + len += ((generic_x11_reply_t *)packet)->length * 4; + if (len > 32) { + packet = srealloc(packet, len); + must_read(readall_into(packet + 32, len - 32, connstate->serverw->fd)); + } + + /* BEGIN RandR 1.5 specific */ + const uint16_t sequence = ((generic_x11_reply_t *)packet)->sequence; + + if (sequence == connstate->getext_randr) { + xcb_query_extension_reply_t *reply = packet; + connstate->randr_major_opcode = reply->major_opcode; + } + + if (sequence == connstate->getmonitors) { + printf("RRGetMonitors reply!\n"); + xcb_randr_get_monitors_reply_t *reply = packet; + if (injected_reply != NULL) { + printf("injecting reply\n"); + ((generic_x11_reply_t *)injected_reply)->sequence = sequence; + must_write(writeall(connstate->clientw->fd, injected_reply, injected_reply_len)); + free(packet); + return; + } + } + /* END RandR 1.5 specific */ + + break; + + default: // event + break; + } + must_write(writeall(connstate->clientw->fd, packet, len)); + free(packet); +} + +static void child_cb(EV_P_ ev_child *w, int revents) { + ev_child_stop(EV_A_ w); + if (WIFEXITED(w->rstatus)) { + exit(WEXITSTATUS(w->rstatus)); + } else { + exit(WTERMSIG(w->rstatus) + 128); + } +} + +static void must_read_reply(const char *filename) { + FILE *f; + if ((f = fopen(filename, "r")) == NULL) { + err(EXIT_FAILURE, "fopen(%s)", filename); + } + struct stat stbuf; + if (fstat(fileno(f), &stbuf) != 0) { + err(EXIT_FAILURE, "fstat(%s)", filename); + } + /* BEGIN RandR 1.5 specific */ + injected_reply_len = stbuf.st_size; + injected_reply = smalloc(stbuf.st_size); + int n = fread(injected_reply, 1, stbuf.st_size, f); + /* END RandR 1.5 specific */ + if (n != stbuf.st_size) { + err(EXIT_FAILURE, "fread(%s)", filename); + } + fclose(f); +} + +int main(int argc, char *argv[]) { + static struct option long_options[] = { + {"getmonitors_reply", required_argument, 0, 0}, + {0, 0, 0, 0}, + }; + char *options_string = ""; + int opt; + int option_index = 0; + + while ((opt = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { + switch (opt) { + case 0: + if (strcmp(long_options[option_index].name, "getmonitors_reply") == 0) { + must_read_reply(optarg); + } + break; + default: + exit(EXIT_FAILURE); + } + } + + if (optind >= argc) { + errx(EXIT_FAILURE, "syntax: %s [options] \n", argv[0]); + } + + int fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd == -1) { + err(EXIT_FAILURE, "socket(AF_UNIX)"); + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { + warn("Could not set FD_CLOEXEC"); + } + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + int i; + bool bound = false; + for (i = 0; i < 100; i++) { + /* XXX: The path to X11 sockets differs on some platforms (e.g. Trusted + * Solaris, HPUX), but since libxcb doesn’t provide a function to + * generate the path, we’ll just have to hard-code it for now. */ + snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/.X11-unix/X%d", i); + + if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { + warn("bind(%s)", addr.sun_path); + } else { + bound = true; + /* Let the user know bind() was successful, so that they know the + * error messages can be disregarded. */ + fprintf(stderr, "Successfuly bound to %s\n", addr.sun_path); + sun_path = sstrdup(addr.sun_path); + break; + } + } + + if (!bound) { + err(EXIT_FAILURE, "bind()"); + } + + atexit(cleanup_socket); + + /* This program will be started for each testcase which requires it, so we + * expect precisely one connection. */ + if (listen(fd, 1) == -1) { + err(EXIT_FAILURE, "listen()"); + } + + pid_t child = fork(); + if (child == -1) { + err(EXIT_FAILURE, "fork()"); + } + if (child == 0) { + char *display; + sasprintf(&display, ":%d", i); + setenv("DISPLAY", display, 1); + free(display); + + char **child_args = argv + optind; + execvp(child_args[0], child_args); + err(EXIT_FAILURE, "exec()"); + } + + struct ev_loop *loop = ev_default_loop(0); + + ev_child cw; + ev_child_init(&cw, child_cb, child, 0); + ev_child_start(loop, &cw); + + ev_io watcher; + ev_io_init(&watcher, uds_connection_cb, fd, EV_READ); + ev_io_start(loop, &watcher); + + ev_run(loop, 0); +} diff --git a/testcases/lib/SocketActivation.pm b/testcases/lib/SocketActivation.pm index 53dbb3b6..0f307eb3 100644 --- a/testcases/lib/SocketActivation.pm +++ b/testcases/lib/SocketActivation.pm @@ -88,7 +88,10 @@ sub activate_i3 { # the interactive signalhandler to make it crash immediately instead. # Also disable logging to SHM since we redirect the logs anyways. # Force Xinerama because we use Xdmx for multi-monitor tests. - my $i3cmd = q|i3 --shmlog-size=0 --disable-signalhandler --force-xinerama|; + my $i3cmd = q|i3 --shmlog-size=0 --disable-signalhandler|; + if (!defined($args{inject_randr15})) { + $i3cmd .= q| --force-xinerama|; + } if (!$args{validate_config}) { # We only set logging if i3 is actually started, but not if we only # validate the config file. This is to keep logging to a minimum as @@ -139,6 +142,13 @@ sub activate_i3 { 'sh -c "export LISTEN_PID=\$\$; ' . $cmd . '"'; } + if ($args{inject_randr15}) { + # See comment in $args{strace} branch. + $cmd = 'test.inject_randr15 --getmonitors_reply="' . + $args{inject_randr15} . '" -- ' . + 'sh -c "export LISTEN_PID=\$\$; ' . $cmd . '"'; + } + # We need to use the shell due to using output redirections. exec '/bin/sh', '-c', $cmd; diff --git a/testcases/lib/i3test.pm.in b/testcases/lib/i3test.pm.in index f9f6e821..f7e1515d 100644 --- a/testcases/lib/i3test.pm.in +++ b/testcases/lib/i3test.pm.in @@ -861,6 +861,7 @@ sub launch_with_config { cv => $cv, dont_create_temp_dir => $args{dont_create_temp_dir}, validate_config => $args{validate_config}, + inject_randr15 => $args{inject_randr15}, ); # If we called i3 with -C, we wait for it to exit and then return as diff --git a/testcases/t/533-randr15.t b/testcases/t/533-randr15.t new file mode 100644 index 00000000..f520806c --- /dev/null +++ b/testcases/t/533-randr15.t @@ -0,0 +1,73 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# TODO: Description of this file. +# Ticket: #999 +# Bug still in: 4.13-12-g2ff3d9d +use File::Temp qw(tempfile); +use i3test i3_autostart => 0; + +my $config = < 1); + +# Prepare a RRGetMonitors reply, see A.2.4 in +# https://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt +my $reply = pack('cxSLLLLx[LLL]', + 1, # reply + 0, # sequence (will be filled in by inject_randr15) + # 56 = length($reply) + length($monitor1) + # 32 = minimum X11 reply length + (56-32) / 4, # length in words + 0, # timestamp TODO + 1, # nmonitors + 0); # noutputs + +# Manually intern _NET_CURRENT_DESKTOP as $x->atom will not create atoms if +# they are not yet interned. +my $atom_cookie = $x->intern_atom(0, length("DP3"), "DP3"); +my $DP3 = $x->intern_atom_reply($atom_cookie->{sequence})->{atom}; + +# MONITORINFO is defined in A.1.1 in +# https://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt +my $monitor1 = pack('LccSssSSLL', + $DP3, # name (ATOM) + 1, # primary + 1, # automatic + 0, # ncrtcs + 0, # x + 0, # y + 3840, # width in pixels + 2160, # height in pixels + 520, # width in millimeters + 290); # height in millimeters + +print $outfh $reply; +print $outfh $monitor1; + +close($outfh); + +my $pid = launch_with_config($config, inject_randr15 => $outname); + +cmd 'nop'; + +exit_gracefully($pid); + +done_testing; From 70e7f0e39a462d55617cda735339a2861d4e69ca Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 21 Nov 2016 00:37:10 -0800 Subject: [PATCH 012/180] Remove unused src/debug.c (#2575) --- Makefile.am | 1 - docs/hacking-howto | 3 - include/debug.h | 15 --- src/debug.c | 245 --------------------------------------------- 4 files changed, 264 deletions(-) delete mode 100644 include/debug.h delete mode 100644 src/debug.c diff --git a/Makefile.am b/Makefile.am index aea4256b..f35a2f2f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -518,7 +518,6 @@ i3_SOURCES = \ src/config.c \ src/config_directives.c \ src/config_parser.c \ - src/debug.c \ src/display_version.c \ src/ewmh.c \ src/fake_outputs.c \ diff --git a/docs/hacking-howto b/docs/hacking-howto index 74a690e7..2ba74917 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -119,9 +119,6 @@ src/config.c:: Contains all functions handling the configuration file (calling the parser src/config_parser.c) with the correct path, switching key bindings mode). -src/debug.c:: -Contains debugging functions to print unhandled X events. - src/ewmh.c:: Functions to get/set certain EWMH properties easily. diff --git a/include/debug.h b/include/debug.h deleted file mode 100644 index ab5f3808..00000000 --- a/include/debug.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * vim:ts=4:sw=4:expandtab - * - * i3 - an improved dynamic tiling window manager - * © 2009 Michael Stapelberg and contributors (see also: LICENSE) - * - * debug.c: Debugging functions, especially FormatEvent, which prints unhandled - * events. This code is from xcb-util. - * - */ -#pragma once - -#include - -int handle_event(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e); diff --git a/src/debug.c b/src/debug.c deleted file mode 100644 index ea4ca997..00000000 --- a/src/debug.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * vim:ts=4:sw=4:expandtab - * - * i3 - an improved dynamic tiling window manager - * © 2009 Michael Stapelberg and contributors (see also: LICENSE) - * - * debug.c: Debugging functions, especially FormatEvent, which prints unhandled - * events. This code is from xcb-util. - * - */ -#include - -#include -#include - -#include "log.h" - -static const char *labelError[] = { - "Success", - "BadRequest", - "BadValue", - "BadWindow", - "BadPixmap", - "BadAtom", - "BadCursor", - "BadFont", - "BadMatch", - "BadDrawable", - "BadAccess", - "BadAlloc", - "BadColor", - "BadGC", - "BadIDChoice", - "BadName", - "BadLength", - "BadImplementation", -}; - -static const char *labelRequest[] = { - "no request", - "CreateWindow", - "ChangeWindowAttributes", - "GetWindowAttributes", - "DestroyWindow", - "DestroySubwindows", - "ChangeSaveSet", - "ReparentWindow", - "MapWindow", - "MapSubwindows", - "UnmapWindow", - "UnmapSubwindows", - "ConfigureWindow", - "CirculateWindow", - "GetGeometry", - "QueryTree", - "InternAtom", - "GetAtomName", - "ChangeProperty", - "DeleteProperty", - "GetProperty", - "ListProperties", - "SetSelectionOwner", - "GetSelectionOwner", - "ConvertSelection", - "SendEvent", - "GrabPointer", - "UngrabPointer", - "GrabButton", - "UngrabButton", - "ChangeActivePointerGrab", - "GrabKeyboard", - "UngrabKeyboard", - "GrabKey", - "UngrabKey", - "AllowEvents", - "GrabServer", - "UngrabServer", - "QueryPointer", - "GetMotionEvents", - "TranslateCoords", - "WarpPointer", - "SetInputFocus", - "GetInputFocus", - "QueryKeymap", - "OpenFont", - "CloseFont", - "QueryFont", - "QueryTextExtents", - "ListFonts", - "ListFontsWithInfo", - "SetFontPath", - "GetFontPath", - "CreatePixmap", - "FreePixmap", - "CreateGC", - "ChangeGC", - "CopyGC", - "SetDashes", - "SetClipRectangles", - "FreeGC", - "ClearArea", - "CopyArea", - "CopyPlane", - "PolyPoint", - "PolyLine", - "PolySegment", - "PolyRectangle", - "PolyArc", - "FillPoly", - "PolyFillRectangle", - "PolyFillArc", - "PutImage", - "GetImage", - "PolyText", - "PolyText", - "ImageText", - "ImageText", - "CreateColormap", - "FreeColormap", - "CopyColormapAndFree", - "InstallColormap", - "UninstallColormap", - "ListInstalledColormaps", - "AllocColor", - "AllocNamedColor", - "AllocColorCells", - "AllocColorPlanes", - "FreeColors", - "StoreColors", - "StoreNamedColor", - "QueryColors", - "LookupColor", - "CreateCursor", - "CreateGlyphCursor", - "FreeCursor", - "RecolorCursor", - "QueryBestSize", - "QueryExtension", - "ListExtensions", - "ChangeKeyboardMapping", - "GetKeyboardMapping", - "ChangeKeyboardControl", - "GetKeyboardControl", - "Bell", - "ChangePointerControl", - "GetPointerControl", - "SetScreenSaver", - "GetScreenSaver", - "ChangeHosts", - "ListHosts", - "SetAccessControl", - "SetCloseDownMode", - "KillClient", - "RotateProperties", - "ForceScreenSaver", - "SetPointerMapping", - "GetPointerMapping", - "SetModifierMapping", - "GetModifierMapping", - "major 120", - "major 121", - "major 122", - "major 123", - "major 124", - "major 125", - "major 126", - "NoOperation", -}; - -static const char *labelEvent[] = { - "error", - "reply", - "KeyPress", - "KeyRelease", - "ButtonPress", - "ButtonRelease", - "MotionNotify", - "EnterNotify", - "LeaveNotify", - "FocusIn", - "FocusOut", - "KeymapNotify", - "Expose", - "GraphicsExpose", - "NoExpose", - "VisibilityNotify", - "CreateNotify", - "DestroyNotify", - "UnmapNotify", - "MapNotify", - "MapRequest", - "ReparentNotify", - "ConfigureNotify", - "ConfigureRequest", - "GravityNotify", - "ResizeRequest", - "CirculateNotify", - "CirculateRequest", - "PropertyNotify", - "SelectionClear", - "SelectionRequest", - "SelectionNotify", - "ColormapNotify", - "ClientMessage", - "MappingNotify", -}; - -static const char *labelSendEvent[] = { - "", - " (from SendEvent)", -}; - -int format_event(xcb_generic_event_t *e) { - uint8_t sendEvent; - uint16_t seqnum; - - sendEvent = (e->response_type & 0x80) ? 1 : 0; - e->response_type &= ~0x80; - seqnum = *((uint16_t *)e + 1); - - switch (e->response_type) { - case 0: - DLOG("Error %s on seqnum %d (%s).\n", - labelError[*((uint8_t *)e + 1)], - seqnum, - labelRequest[*((uint8_t *)e + 10)]); - break; - default: - if (e->response_type > sizeof(labelEvent) / sizeof(char *)) - break; - DLOG("Event %s following seqnum %d%s.\n", - labelEvent[e->response_type], - seqnum, - labelSendEvent[sendEvent]); - break; - case XCB_KEYMAP_NOTIFY: - DLOG("Event %s%s.\n", - labelEvent[e->response_type], - labelSendEvent[sendEvent]); - break; - } - - fflush(stdout); - return 1; -} From 90d68d7ea0f25b579f91f26ca3c27c9536a3a44d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 21 Nov 2016 00:37:17 -0800 Subject: [PATCH 013/180] Remove some now-unused functions from xcb.[ch] (#2574) xcb_draw_line is unused since commit d7f9700ba41db61788a7b0f22350cdd9d008a907 xcb_draw_rect is unused since commit a79d33fc7fd41ab6e9b853f5356eeec64aa66ef5 xcb_raise_window is unused since commit 7208d010489ba9ebd79b20aa830ae7fb176f05dc xcb_warp_pointer is unused since commit 755c618cd41815c72d30fd0d3c4770557e952df2 --- include/xcb.h | 28 ---------------------------- src/xcb.c | 43 ------------------------------------------- 2 files changed, 71 deletions(-) diff --git a/include/xcb.h b/include/xcb.h index 94f2945d..92be7b89 100644 --- a/include/xcb.h +++ b/include/xcb.h @@ -69,22 +69,6 @@ extern unsigned int xcb_numlock_mask; xcb_window_t create_window(xcb_connection_t *conn, Rect r, uint16_t depth, xcb_visualid_t visual, uint16_t window_class, enum xcursor_cursor_t cursor, bool map, uint32_t mask, uint32_t *values); -/** - * Draws a line from x,y to to_x,to_y using the given color - * - */ -void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, - xcb_gcontext_t gc, uint32_t colorpixel, uint32_t x, - uint32_t y, uint32_t to_x, uint32_t to_y); - -/** - * Draws a rectangle from x,y with width,height using the given color - * - */ -void xcb_draw_rect(xcb_connection_t *conn, xcb_drawable_t drawable, - xcb_gcontext_t gc, uint32_t colorpixel, uint32_t x, - uint32_t y, uint32_t width, uint32_t height); - /** * Generates a configure_notify_event with absolute coordinates (relative to * the X root window, not to the client’s frame) for the given client. @@ -98,12 +82,6 @@ void fake_absolute_configure_notify(Con *con); */ void send_take_focus(xcb_window_t window, xcb_timestamp_t timestamp); -/** - * Raises the given window (typically client->frame) above all other windows - * - */ -void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window); - /** * Configures the given window to have the size/position specified by given rect * @@ -122,12 +100,6 @@ xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply); */ bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom); -/** - * Moves the mouse pointer into the middle of rect. - * - */ -void xcb_warp_pointer_rect(xcb_connection_t *conn, Rect *rect); - /** * Set the cursor of the root window to the given cursor id. * This function should only be used if xcursor_supported == false. diff --git a/src/xcb.c b/src/xcb.c index 900840a2..726d1e89 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -62,28 +62,6 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims, return result; } -/* - * Draws a line from x,y to to_x,to_y using the given color - * - */ -void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc, - uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t to_x, uint32_t to_y) { - xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, (uint32_t[]){colorpixel}); - xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, drawable, gc, 2, - (xcb_point_t[]){{x, y}, {to_x, to_y}}); -} - -/* - * Draws a rectangle from x,y with width,height using the given color - * - */ -void xcb_draw_rect(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc, - uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { - xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, (uint32_t[]){colorpixel}); - xcb_rectangle_t rect = {x, y, width, height}; - xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect); -} - /* * Generates a configure_notify_event with absolute coordinates (relative to the X root * window, not to the client’s frame) for the given client. @@ -127,15 +105,6 @@ void send_take_focus(xcb_window_t window, xcb_timestamp_t timestamp) { free(event); } -/* - * Raises the given window (typically client->frame) above all other windows - * - */ -void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window) { - uint32_t values[] = {XCB_STACK_MODE_ABOVE}; - xcb_configure_window(conn, window, XCB_CONFIG_WINDOW_STACK_MODE, values); -} - /* * Configures the given window to have the size/position specified by given rect * @@ -201,18 +170,6 @@ bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom) { return false; } -/** - * Moves the mouse pointer into the middle of rect. - * - */ -void xcb_warp_pointer_rect(xcb_connection_t *conn, Rect *rect) { - int mid_x = rect->x + (rect->width / 2); - int mid_y = rect->y + (rect->height / 2); - - LOG("warp pointer to: %d %d\n", mid_x, mid_y); - xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, mid_x, mid_y); -} - /* * Set the cursor of the root window to the given cursor id. * This function should only be used if xcursor_supported == false. From 2f9bb7dd5a296f002219fbbdcb6169410d529814 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 21 Nov 2016 02:41:15 -0800 Subject: [PATCH 014/180] Fix memory leak: free marks when destroying containers (#2578) --- src/tree.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tree.c b/src/tree.c index 6e128363..d2fe4e07 100644 --- a/src/tree.c +++ b/src/tree.c @@ -329,6 +329,12 @@ bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_par match_free(match); free(match); } + while (!TAILQ_EMPTY(&(con->marks_head))) { + mark_t *mark = TAILQ_FIRST(&(con->marks_head)); + TAILQ_REMOVE(&(con->marks_head), mark, marks); + FREE(mark->name); + FREE(mark); + } free(con); /* in the case of floating windows, we already focused another container From fd3403d96e40648c420c3734410fdb727507937a Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 21 Nov 2016 03:02:43 -0800 Subject: [PATCH 015/180] remove debug.h from Makefile.am (#2581) --- Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index f35a2f2f..0368ecca 100644 --- a/Makefile.am +++ b/Makefile.am @@ -473,7 +473,6 @@ i3_SOURCES = \ include/config_parser.h \ include/con.h \ include/data.h \ - include/debug.h \ include/display_version.h \ include/ewmh.h \ include/fake_outputs.h \ From 0dd9d2202f1810526bf1d833a4b21f9394abf4ba Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 21 Nov 2016 03:16:06 -0800 Subject: [PATCH 016/180] release.sh: update for v4.13 release (#2582) --- release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release.sh b/release.sh index 33cb4f53..22d903c4 100755 --- a/release.sh +++ b/release.sh @@ -1,8 +1,8 @@ #!/bin/zsh # This script is used to prepare a new release of i3. -export RELEASE_VERSION="4.12" -export PREVIOUS_VERSION="4.11" +export RELEASE_VERSION="4.13" +export PREVIOUS_VERSION="4.12" export RELEASE_BRANCH="next" if [ ! -e "../i3.github.io" ] From f2ffd8d8644c6c663f9da90cff42ac31acdc462e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 21 Nov 2016 21:41:43 +0100 Subject: [PATCH 017/180] Added instructions to update Github milestones after release. (#2561) --- release.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release.sh b/release.sh index 22d903c4..8f537c0e 100755 --- a/release.sh +++ b/release.sh @@ -232,6 +232,10 @@ echo "" echo " cd ${TMPDIR}" echo " sendmail -t < email.txt" echo "" +echo "Update milestones on GitHub:" +echo " Set due date of ${RELEASE_VERSION} to $(date +'%Y-$m-%d') and close the milestone" +echo " Create milestone for the next version with unset due date" +echo "" echo "Announce on:" echo " twitter" echo " google+" From 633a9f7b1475ffd5c72489bc6bd2d224c441c9a9 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 28 Nov 2016 18:20:46 +0100 Subject: [PATCH 018/180] Implement RandR 1.5 support (#2580) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This comes with the intentionally undocumented --disable-randr15 command line flag and disable-randr15 configuration directive. We will add documentation before the release if and only if it turns out that users actually need to use this flag in their setups. Ideally, nobody would need to use the flag and everything would just keep working, but it’s better to be safe than sorry. fixes #1799 --- generate-command-parser.pl | 10 +- include/config_directives.h | 1 + include/configuration.h | 3 + include/randr.h | 2 +- parser-specs/config.spec | 6 + src/config_directives.c | 4 + src/handlers.c | 19 +++ src/main.c | 9 +- src/randr.c | 218 +++++++++++++++++++++++++------- testcases/inject_randr1.5.c | 1 - testcases/t/201-config-parser.t | 2 + testcases/t/533-randr15.t | 37 +++++- 12 files changed, 259 insertions(+), 53 deletions(-) diff --git a/generate-command-parser.pl b/generate-command-parser.pl index 6208945d..a7687c7b 100755 --- a/generate-command-parser.pl +++ b/generate-command-parser.pl @@ -65,7 +65,7 @@ for my $line (@raw_lines) { my $current_state; for my $line (@lines) { - if (my ($state) = ($line =~ /^state ([A-Z_]+):$/)) { + if (my ($state) = ($line =~ /^state ([A-Z0-9_]+):$/)) { #say "got a new state: $state"; $current_state = $state; } else { @@ -155,12 +155,20 @@ for my $state (@keys) { # to generate a format string. The format uses %d for s, # literal numbers or state IDs and %s for NULL, s and literal # strings. + + # remove the function name temporarily, so that the following + # replacements only apply to the arguments. + my ($funcname) = ($fmt =~ /^(.+)\(/); + $fmt =~ s/^$funcname//; + $fmt =~ s/$_/%d/g for @keys; $fmt =~ s/\$([a-z_]+)/%s/g; $fmt =~ s/\&([a-z_]+)/%ld/g; $fmt =~ s/"([a-z0-9_]+)"/%s/g; $fmt =~ s/(?:-?|\b)[0-9]+\b/%d/g; + $fmt = $funcname . $fmt; + say $callfh " case $call_id:"; say $callfh " result->next_state = $next_state;"; say $callfh '#ifndef TEST_PARSER'; diff --git a/include/config_directives.h b/include/config_directives.h index 7f1bfe4a..0bf52168 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -51,6 +51,7 @@ CFGFUN(focus_follows_mouse, const char *value); CFGFUN(mouse_warping, const char *value); CFGFUN(force_focus_wrapping, const char *value); CFGFUN(force_xinerama, const char *value); +CFGFUN(disable_randr15, const char *value); CFGFUN(fake_outputs, const char *outputs); CFGFUN(force_display_urgency_hint, const long duration_ms); CFGFUN(focus_on_window_activation, const char *mode); diff --git a/include/configuration.h b/include/configuration.h index f93afde7..66628eeb 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -156,6 +156,9 @@ struct Config { * is fetched once and never updated. */ bool force_xinerama; + /** Don’t use RandR 1.5 for querying outputs. */ + bool disable_randr15; + /** Overwrites output detection (for testing), see src/fake_outputs.c */ char *fake_outputs; diff --git a/include/randr.h b/include/randr.h index 55068316..8cbfc842 100644 --- a/include/randr.h +++ b/include/randr.h @@ -29,7 +29,7 @@ typedef enum { * XRandR information to setup workspaces for each screen. * */ -void randr_init(int *event_base); +void randr_init(int *event_base, const bool disable_randr15); /** * Initializes a CT_OUTPUT Con (searches existing ones from inplace restart diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 90296819..19e2d21a 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -37,6 +37,7 @@ state INITIAL: 'mouse_warping' -> MOUSE_WARPING 'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING 'force_xinerama', 'force-xinerama' -> FORCE_XINERAMA + 'disable_randr15', 'disable-randr15' -> DISABLE_RANDR15 'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT @@ -205,6 +206,11 @@ state FORCE_XINERAMA: value = word -> call cfg_force_xinerama($value) +# disable_randr15 +state DISABLE_RANDR15: + value = word + -> call cfg_disable_randr15($value) + # workspace_back_and_forth state WORKSPACE_BACK_AND_FORTH: value = word diff --git a/src/config_directives.c b/src/config_directives.c index 6b5464f1..a260518c 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -252,6 +252,10 @@ CFGFUN(force_xinerama, const char *value) { config.force_xinerama = eval_boolstr(value); } +CFGFUN(disable_randr15, const char *value) { + config.disable_randr15 = eval_boolstr(value); +} + CFGFUN(force_focus_wrapping, const char *value) { config.force_focus_wrapping = eval_boolstr(value); } diff --git a/src/handlers.c b/src/handlers.c index 7dfacef7..5e589e9c 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -1150,6 +1150,21 @@ static void handle_focus_in(xcb_focus_in_event_t *event) { return; } +/* + * Handles ConfigureNotify events for the root window, which are generated when + * the monitor configuration changed. + * + */ +static void handle_configure_notify(xcb_configure_notify_event_t *event) { + if (event->event != root) { + DLOG("ConfigureNotify for non-root window 0x%08x, ignoring\n", event->event); + return; + } + DLOG("ConfigureNotify for root window 0x%08x\n", event->event); + + randr_query_outputs(); +} + /* * Handles the WM_CLASS property for assignments and criteria selection. * @@ -1476,6 +1491,10 @@ void handle_event(int type, xcb_generic_event_t *event) { break; } + case XCB_CONFIGURE_NOTIFY: + handle_configure_notify((xcb_configure_notify_event_t *)event); + break; + default: //DLOG("Unhandled event of type %d\n", type); break; diff --git a/src/main.c b/src/main.c index 4737175b..43efb3c2 100644 --- a/src/main.c +++ b/src/main.c @@ -194,6 +194,7 @@ int main(int argc, char *argv[]) { char *layout_path = NULL; bool delete_layout_path = false; bool force_xinerama = false; + bool disable_randr15 = false; char *fake_outputs = NULL; bool disable_signalhandler = false; bool only_check_config = false; @@ -209,6 +210,8 @@ int main(int argc, char *argv[]) { {"restart", required_argument, 0, 0}, {"force-xinerama", no_argument, 0, 0}, {"force_xinerama", no_argument, 0, 0}, + {"disable-randr15", no_argument, 0, 0}, + {"disable_randr15", no_argument, 0, 0}, {"disable-signalhandler", no_argument, 0, 0}, {"shmlog-size", required_argument, 0, 0}, {"shmlog_size", required_argument, 0, 0}, @@ -289,6 +292,10 @@ int main(int argc, char *argv[]) { "Please check if your driver really does not support RandR " "and disable this option as soon as you can.\n"); break; + } else if (strcmp(long_options[option_index].name, "disable-randr15") == 0 || + strcmp(long_options[option_index].name, "disable_randr15") == 0) { + disable_randr15 = true; + break; } else if (strcmp(long_options[option_index].name, "disable-signalhandler") == 0) { disable_signalhandler = true; break; @@ -661,7 +668,7 @@ int main(int argc, char *argv[]) { xinerama_init(); } else { DLOG("Checking for XRandR...\n"); - randr_init(&randr_base); + randr_init(&randr_base, disable_randr15 || config.disable_randr15); } /* We need to force disabling outputs which have been loaded from the diff --git a/src/randr.c b/src/randr.c index e5dcddfc..16ef62b8 100644 --- a/src/randr.c +++ b/src/randr.c @@ -14,11 +14,6 @@ #include #include -/* While a clean namespace is usually a pretty good thing, we really need - * to use shorter names than the whole xcb_randr_* default names. */ -typedef xcb_randr_get_crtc_info_reply_t crtc_info; -typedef xcb_randr_get_screen_resources_current_reply_t resources_reply; - /* Pointer to the result of the query for primary output */ xcb_randr_get_output_primary_reply_t *primary; @@ -27,6 +22,7 @@ struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs); /* This is the output covering the root window */ static Output *root_output; +static bool has_randr_1_5 = false; /* * Get a specific output by its internal X11 id. Used by randr_query_outputs @@ -534,18 +530,112 @@ static void output_change_mode(xcb_connection_t *conn, Output *output) { } /* - * Gets called by randr_query_outputs() for each output. The function adds new - * outputs to the list of outputs, checks if the mode of existing outputs has - * been changed or if an existing output has been disabled. It will then change - * either the "changed" or the "to_be_deleted" flag of the output, if + * randr_query_outputs_15 uses RandR ≥ 1.5 to update outputs. + * + */ +static bool randr_query_outputs_15(void) { +#if XCB_RANDR_MINOR_VERSION < 5 + return false; +#else + /* RandR 1.5 available at compile-time, i.e. libxcb is new enough */ + if (!has_randr_1_5) { + return false; + } + /* RandR 1.5 available at run-time (supported by the server and not + * disabled by the user) */ + DLOG("Querying outputs using RandR 1.5\n"); + xcb_generic_error_t *err; + xcb_randr_get_monitors_reply_t *monitors = + xcb_randr_get_monitors_reply( + conn, xcb_randr_get_monitors(conn, root, true), &err); + if (err != NULL) { + ELOG("Could not get RandR monitors: X11 error code %d\n", err->error_code); + free(err); + /* Fall back to RandR ≤ 1.4 */ + return false; + } + + /* Mark all outputs as to_be_disabled, since xcb_randr_get_monitors() will + * only return active outputs. */ + Output *output; + TAILQ_FOREACH(output, &outputs, outputs) { + if (output != root_output) { + output->to_be_disabled = true; + } + } + + DLOG("%d RandR monitors found (timestamp %d)\n", + xcb_randr_get_monitors_monitors_length(monitors), + monitors->timestamp); + + xcb_randr_monitor_info_iterator_t iter; + for (iter = xcb_randr_get_monitors_monitors_iterator(monitors); + iter.rem; + xcb_randr_monitor_info_next(&iter)) { + const xcb_randr_monitor_info_t *monitor_info = iter.data; + xcb_get_atom_name_reply_t *atom_reply = + xcb_get_atom_name_reply( + conn, xcb_get_atom_name(conn, monitor_info->name), &err); + if (err != NULL) { + ELOG("Could not get RandR monitor name: X11 error code %d\n", err->error_code); + free(err); + continue; + } + char *name; + sasprintf(&name, "%.*s", + xcb_get_atom_name_name_length(atom_reply), + xcb_get_atom_name_name(atom_reply)); + free(atom_reply); + + Output *new = get_output_by_name(name); + if (new == NULL) { + new = scalloc(1, sizeof(Output)); + new->name = sstrdup(name); + if (monitor_info->primary) { + TAILQ_INSERT_HEAD(&outputs, new, outputs); + } else { + TAILQ_INSERT_TAIL(&outputs, new, outputs); + } + } + /* We specified get_active == true in xcb_randr_get_monitors(), so we + * will only receive active outputs. */ + new->active = true; + new->to_be_disabled = false; + + new->primary = monitor_info->primary; + + new->changed = + update_if_necessary(&(new->rect.x), monitor_info->x) | + update_if_necessary(&(new->rect.y), monitor_info->y) | + update_if_necessary(&(new->rect.width), monitor_info->width) | + update_if_necessary(&(new->rect.height), monitor_info->height); + + DLOG("name %s, x %d, y %d, width %d px, height %d px, width %d mm, height %d mm, primary %d, automatic %d\n", + name, + monitor_info->x, monitor_info->y, monitor_info->width, monitor_info->height, + monitor_info->width_in_millimeters, monitor_info->height_in_millimeters, + monitor_info->primary, monitor_info->automatic); + free(name); + } + free(monitors); + return true; +#endif +} + +/* + * Gets called by randr_query_outputs_14() for each output. The function adds + * new outputs to the list of outputs, checks if the mode of existing outputs + * has been changed or if an existing output has been disabled. It will then + * change either the "changed" or the "to_be_deleted" flag of the output, if * appropriate. * */ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, xcb_randr_get_output_info_reply_t *output, - xcb_timestamp_t cts, resources_reply *res) { + xcb_timestamp_t cts, + xcb_randr_get_screen_resources_current_reply_t *res) { /* each CRT controller has a position in which we are interested in */ - crtc_info *crtc; + xcb_randr_get_crtc_info_reply_t *crtc; Output *new = get_output_by_id(id); bool existing = (new != NULL); @@ -614,25 +704,16 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, } /* - * (Re-)queries the outputs via RandR and stores them in the list of outputs. - * - * If no outputs are found use the root window. + * randr_query_outputs_14 uses RandR ≤ 1.4 to update outputs. * */ -void randr_query_outputs(void) { - Output *output, *other; - xcb_randr_get_output_primary_cookie_t pcookie; - xcb_randr_get_screen_resources_current_cookie_t rcookie; - - /* timestamp of the configuration so that we get consistent replies to all - * requests (if the configuration changes between our different calls) */ - xcb_timestamp_t cts; - - /* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */ - xcb_randr_output_t *randr_outputs; +static void randr_query_outputs_14(void) { + DLOG("Querying outputs using RandR ≤ 1.4\n"); /* Get screen resources (primary output, crtcs, outputs, modes) */ + xcb_randr_get_screen_resources_current_cookie_t rcookie; rcookie = xcb_randr_get_screen_resources_current(conn, root); + xcb_randr_get_output_primary_cookie_t pcookie; pcookie = xcb_randr_get_output_primary(conn, root); if ((primary = xcb_randr_get_output_primary_reply(conn, pcookie, NULL)) == NULL) @@ -640,30 +721,52 @@ void randr_query_outputs(void) { else DLOG("primary output is %08x\n", primary->output); - resources_reply *res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL); + xcb_randr_get_screen_resources_current_reply_t *res = + xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL); if (res == NULL) { ELOG("Could not query screen resources.\n"); - } else { - cts = res->config_timestamp; + return; + } - int len = xcb_randr_get_screen_resources_current_outputs_length(res); - randr_outputs = xcb_randr_get_screen_resources_current_outputs(res); + /* timestamp of the configuration so that we get consistent replies to all + * requests (if the configuration changes between our different calls) */ + const xcb_timestamp_t cts = res->config_timestamp; - /* Request information for each output */ - xcb_randr_get_output_info_cookie_t ocookie[len]; - for (int i = 0; i < len; i++) - ocookie[i] = xcb_randr_get_output_info(conn, randr_outputs[i], cts); + const int len = xcb_randr_get_screen_resources_current_outputs_length(res); - /* Loop through all outputs available for this X11 screen */ - for (int i = 0; i < len; i++) { - xcb_randr_get_output_info_reply_t *output; + /* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */ + xcb_randr_output_t *randr_outputs = xcb_randr_get_screen_resources_current_outputs(res); - if ((output = xcb_randr_get_output_info_reply(conn, ocookie[i], NULL)) == NULL) - continue; + /* Request information for each output */ + xcb_randr_get_output_info_cookie_t ocookie[len]; + for (int i = 0; i < len; i++) + ocookie[i] = xcb_randr_get_output_info(conn, randr_outputs[i], cts); - handle_output(conn, randr_outputs[i], output, cts, res); - free(output); - } + /* Loop through all outputs available for this X11 screen */ + for (int i = 0; i < len; i++) { + xcb_randr_get_output_info_reply_t *output; + + if ((output = xcb_randr_get_output_info_reply(conn, ocookie[i], NULL)) == NULL) + continue; + + handle_output(conn, randr_outputs[i], output, cts, res); + free(output); + } + + FREE(res); +} + +/* + * (Re-)queries the outputs via RandR and stores them in the list of outputs. + * + * If no outputs are found use the root window. + * + */ +void randr_query_outputs(void) { + Output *output, *other; + + if (!randr_query_outputs_15()) { + randr_query_outputs_14(); } /* If there's no randr output, enable the output covering the root window. */ @@ -763,7 +866,6 @@ void randr_query_outputs(void) { /* render_layout flushes */ tree_render(); - FREE(res); FREE(primary); } @@ -857,12 +959,18 @@ void randr_disable_output(Output *output) { output->changed = false; } +static void fallback_to_root_output(void) { + root_output->active = true; + output_init_con(root_output); + init_ws_for_output(root_output, output_get_content(root_output->con)); +} + /* * We have just established a connection to the X server and need the initial * XRandR information to setup workspaces for each screen. * */ -void randr_init(int *event_base) { +void randr_init(int *event_base, const bool disable_randr15) { const xcb_query_extension_reply_t *extreply; root_output = create_root_output(conn); @@ -871,13 +979,27 @@ void randr_init(int *event_base) { extreply = xcb_get_extension_data(conn, &xcb_randr_id); if (!extreply->present) { DLOG("RandR is not present, activating root output.\n"); - root_output->active = true; - output_init_con(root_output); - init_ws_for_output(root_output, output_get_content(root_output->con)); - + fallback_to_root_output(); return; } + xcb_generic_error_t *err; + xcb_randr_query_version_reply_t *randr_version = + xcb_randr_query_version_reply( + conn, xcb_randr_query_version(conn, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION), &err); + if (err != NULL) { + free(err); + ELOG("Could not query RandR version: X11 error code %d\n", err->error_code); + fallback_to_root_output(); + return; + } + + has_randr_1_5 = (randr_version->major_version >= 1) && + (randr_version->minor_version >= 5) && + !disable_randr15; + + free(randr_version); + randr_query_outputs(); if (event_base != NULL) diff --git a/testcases/inject_randr1.5.c b/testcases/inject_randr1.5.c index bd0df399..5796ef05 100644 --- a/testcases/inject_randr1.5.c +++ b/testcases/inject_randr1.5.c @@ -294,7 +294,6 @@ static void read_server_x11_packet_cb(EV_P_ ev_io *w, int revents) { if (sequence == connstate->getmonitors) { printf("RRGetMonitors reply!\n"); - xcb_randr_get_monitors_reply_t *reply = packet; if (injected_reply != NULL) { printf("injecting reply\n"); ((generic_x11_reply_t *)injected_reply)->sequence = sequence; diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 6cd84b6f..1de86c65 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -467,6 +467,8 @@ my $expected_all_tokens = "ERROR: CONFIG: Expected one of these tokens: , ' force_focus_wrapping force_xinerama force-xinerama + disable_randr15 + disable-randr15 workspace_auto_back_and_forth fake_outputs fake-outputs diff --git a/testcases/t/533-randr15.t b/testcases/t/533-randr15.t index f520806c..08fa88cc 100644 --- a/testcases/t/533-randr15.t +++ b/testcases/t/533-randr15.t @@ -66,7 +66,42 @@ close($outfh); my $pid = launch_with_config($config, inject_randr15 => $outname); -cmd 'nop'; +my $tree = i3->get_tree->recv; +my @outputs = map { $_->{name} } @{$tree->{nodes}}; +is_deeply(\@outputs, [ '__i3', 'DP3' ], 'outputs are __i3 and DP3'); + +my ($dp3) = grep { $_->{name} eq 'DP3' } @{$tree->{nodes}}; +is_deeply($dp3->{rect}, { + width => 3840, + height => 2160, + x => 0, + y => 0, + }, 'Output DP3 at 3840x2160+0+0'); + +exit_gracefully($pid); + +################################################################################ +# Verify that adding monitors with RandR 1.5 results in i3 outputs. +################################################################################ + +# When inject_randr15 is defined but false, fake-xinerama will be turned off, +# but inject_randr15 will not actually be used. +my $pid = launch_with_config($config, inject_randr15 => ''); + +$tree = i3->get_tree->recv; +@outputs = map { $_->{name} } @{$tree->{nodes}}; +is_deeply(\@outputs, [ '__i3', 'default' ], 'outputs are __i3 and default'); + +SKIP: { + skip 'xrandr --setmonitor failed (xrandr too old?)', 1 unless + system(q|xrandr --setmonitor up2414q 3840/527x2160/296+1280+0 none|) == 0; + + sync_with_i3; + + $tree = i3->get_tree->recv; + @outputs = map { $_->{name} } @{$tree->{nodes}}; + is_deeply(\@outputs, [ '__i3', 'default', 'up2414q' ], 'outputs are __i3, default and up2414q'); +} exit_gracefully($pid); From f25c3d5e77f410305efeed97da5ac9adb25491f3 Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Mon, 28 Nov 2016 23:07:45 +0200 Subject: [PATCH 019/180] Use the DPI setting within the i3-config-wizard and i3-nagbar (#2585) --- i3-config-wizard/main.c | 1 + i3-nagbar/main.c | 1 + 2 files changed, 2 insertions(+) diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 2bb43270..9e851c06 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -854,6 +854,7 @@ int main(int argc, char *argv[]) { xcb_numlock_mask = get_mod_mask_for(XCB_NUM_LOCK, symbols, modmap_reply); + init_dpi(); font = load_font(pattern, true); bold_font = load_font(patternbold, true); diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index 2e9e77d4..b9f27a87 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -468,6 +468,7 @@ int main(int argc, char *argv[]) { color_border_bottom = draw_util_hex_to_color("#ab7100"); } + init_dpi(); font = load_font(pattern, true); set_font(&font); From a3013969976c0f2572e6137f8a6b0ed306287b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 28 Nov 2016 22:09:39 +0100 Subject: [PATCH 020/180] Respect minimum size hints for floating windows. (#2508) This commit introduces proper support for the minimum size on floating windows by ensuring that it is respected during mapping, later changes as well as resizes. Furthermore, this commit fixes minor issues with how the hints are handled during calculations. fixes #2436 --- include/data.h | 4 ++ src/floating.c | 96 +++++++++++++++++---------- src/handlers.c | 70 +++++++++++++------ src/manage.c | 6 ++ testcases/t/141-resize.t | 4 +- testcases/t/221-floating-type-hints.t | 12 ++-- 6 files changed, 128 insertions(+), 64 deletions(-) diff --git a/include/data.h b/include/data.h index 410f2e0d..3d67e315 100644 --- a/include/data.h +++ b/include/data.h @@ -450,6 +450,10 @@ struct Window { int width_increment; int height_increment; + /* Minimum size specified for the window. */ + int min_width; + int min_height; + /* aspect ratio from WM_NORMAL_HINTS (MPlayer uses this for example) */ double aspect_ratio; }; diff --git a/src/floating.c b/src/floating.c index 0a8b6957..f2994339 100644 --- a/src/floating.c +++ b/src/floating.c @@ -72,18 +72,29 @@ void floating_check_size(Con *floating_con) { Rect floating_sane_max_dimensions; Con *focused_con = con_descend_focused(floating_con); - /* obey size increments */ - if (focused_con->window != NULL && (focused_con->window->height_increment || focused_con->window->width_increment)) { - Rect border_rect = con_border_style_rect(focused_con); + Rect border_rect = con_border_style_rect(focused_con); + /* We have to do the opposite calculations that render_con() do + * to get the exact size we want. */ + border_rect.width = -border_rect.width; + border_rect.width += 2 * focused_con->border_width; + border_rect.height = -border_rect.height; + border_rect.height += 2 * focused_con->border_width; + if (con_border_style(focused_con) == BS_NORMAL) { + border_rect.height += render_deco_height(); + } - /* We have to do the opposite calculations that render_con() do - * to get the exact size we want. */ - border_rect.width = -border_rect.width; - border_rect.width += 2 * focused_con->border_width; - border_rect.height = -border_rect.height; - border_rect.height += 2 * focused_con->border_width; - if (con_border_style(focused_con) == BS_NORMAL) - border_rect.height += render_deco_height(); + if (focused_con->window != NULL) { + if (focused_con->window->min_width) { + floating_con->rect.width -= border_rect.width; + floating_con->rect.width = max(floating_con->rect.width, focused_con->window->min_width); + floating_con->rect.width += border_rect.width; + } + + if (focused_con->window->min_height) { + floating_con->rect.height -= border_rect.height; + floating_con->rect.height = max(floating_con->rect.height, focused_con->window->min_height); + floating_con->rect.height += border_rect.height; + } if (focused_con->window->height_increment && floating_con->rect.height >= focused_con->window->base_height + border_rect.height) { @@ -100,36 +111,50 @@ void floating_check_size(Con *floating_con) { } } + /* Unless user requests otherwise (-1), raise the width/height to + * reasonable minimum dimensions */ + if (config.floating_minimum_height != -1) { + floating_con->rect.height -= border_rect.height; + if (config.floating_minimum_height == 0) { + floating_con->rect.height = max(floating_con->rect.height, floating_sane_min_height); + } else { + floating_con->rect.height = max(floating_con->rect.height, config.floating_minimum_height); + } + floating_con->rect.height += border_rect.height; + } + + if (config.floating_minimum_width != -1) { + floating_con->rect.width -= border_rect.width; + if (config.floating_minimum_width == 0) { + floating_con->rect.width = max(floating_con->rect.width, floating_sane_min_width); + } else { + floating_con->rect.width = max(floating_con->rect.width, config.floating_minimum_width); + } + floating_con->rect.width += border_rect.width; + } + /* Unless user requests otherwise (-1), ensure width/height do not exceed * configured maxima or, if unconfigured, limit to combined width of all * outputs */ - if (config.floating_minimum_height != -1) { - if (config.floating_minimum_height == 0) - floating_con->rect.height = max(floating_con->rect.height, floating_sane_min_height); - else - floating_con->rect.height = max(floating_con->rect.height, config.floating_minimum_height); - } - if (config.floating_minimum_width != -1) { - if (config.floating_minimum_width == 0) - floating_con->rect.width = max(floating_con->rect.width, floating_sane_min_width); - else - floating_con->rect.width = max(floating_con->rect.width, config.floating_minimum_width); - } - - /* Unless user requests otherwise (-1), raise the width/height to - * reasonable minimum dimensions */ floating_sane_max_dimensions = total_outputs_dimensions(); if (config.floating_maximum_height != -1) { - if (config.floating_maximum_height == 0) + floating_con->rect.height -= border_rect.height; + if (config.floating_maximum_height == 0) { floating_con->rect.height = min(floating_con->rect.height, floating_sane_max_dimensions.height); - else + } else { floating_con->rect.height = min(floating_con->rect.height, config.floating_maximum_height); + } + floating_con->rect.height += border_rect.height; } + if (config.floating_maximum_width != -1) { - if (config.floating_maximum_width == 0) + floating_con->rect.width -= border_rect.width; + if (config.floating_maximum_width == 0) { floating_con->rect.width = min(floating_con->rect.width, floating_sane_max_dimensions.width); - else + } else { floating_con->rect.width = min(floating_con->rect.width, config.floating_maximum_width); + } + floating_con->rect.width += border_rect.width; } } @@ -208,7 +233,8 @@ void floating_enable(Con *con, bool automatic) { } } - floating_check_size(nc); + TAILQ_INSERT_TAIL(&(nc->nodes_head), con, nodes); + TAILQ_INSERT_TAIL(&(nc->focus_head), con, focused); /* 3: attach the child to the new parent container. We need to do this * because con_border_style_rect() needs to access con->parent. */ @@ -227,13 +253,16 @@ void floating_enable(Con *con, bool automatic) { nc->rect.width -= border_style_rect.width; /* Add some more pixels for the title bar */ - if (con_border_style(con) == BS_NORMAL) + if (con_border_style(con) == BS_NORMAL) { nc->rect.height += deco_height; + } /* Honor the X11 border */ nc->rect.height += con->border_width * 2; nc->rect.width += con->border_width * 2; + floating_check_size(nc); + /* Some clients (like GIMP’s color picker window) get mapped * to (0, 0), so we push them to a reasonable position * (centered over their leader) */ @@ -280,9 +309,6 @@ void floating_enable(Con *con, bool automatic) { DLOG("Corrected y = %d (deco_height = %d)\n", nc->rect.y, deco_height); - TAILQ_INSERT_TAIL(&(nc->nodes_head), con, nodes); - TAILQ_INSERT_TAIL(&(nc->focus_head), con, focused); - /* render the cons to get initial window_rect correct */ render_con(nc, false); render_con(con, false); diff --git a/src/handlers.c b/src/handlers.c index 5e589e9c..9b248058 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -929,54 +929,72 @@ static bool handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t stat xcb_size_hints_t size_hints; - //CLIENT_LOG(client); - /* If the hints were already in this event, use them, if not, request them */ - if (reply != NULL) + if (reply != NULL) { xcb_icccm_get_wm_size_hints_from_reply(&size_hints, reply); - else + } else { xcb_icccm_get_wm_normal_hints_reply(conn, xcb_icccm_get_wm_normal_hints_unchecked(conn, con->window->id), &size_hints, NULL); + } + + int win_width = con->window_rect.width; + int win_height = con->window_rect.height; if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)) { - // TODO: Minimum size is not yet implemented DLOG("Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height); + + con->window->min_width = size_hints.min_width; + con->window->min_height = size_hints.min_height; + } + + if (con_is_floating(con)) { + win_width = MAX(win_width, con->window->min_width); + win_height = MAX(win_height, con->window->min_height); } bool changed = false; if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)) { - if (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF) + if (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF) { if (con->window->width_increment != size_hints.width_inc) { con->window->width_increment = size_hints.width_inc; changed = true; } - if (size_hints.height_inc > 0 && size_hints.height_inc < 0xFFFF) + } + + if (size_hints.height_inc > 0 && size_hints.height_inc < 0xFFFF) { if (con->window->height_increment != size_hints.height_inc) { con->window->height_increment = size_hints.height_inc; changed = true; } + } - if (changed) + if (changed) { DLOG("resize increments changed\n"); + } } - int base_width = 0, base_height = 0; + bool has_base_size = false; + int base_width = 0; + int base_height = 0; - /* base_width/height are the desired size of the window. - We check if either the program-specified size or the program-specified - min-size is available */ + /* The base width / height is the desired size of the window. */ if (size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) { base_width = size_hints.base_width; base_height = size_hints.base_height; - } else if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { - /* TODO: is this right? icccm says not */ + has_base_size = true; + } + + /* If the window didn't specify a base size, the ICCCM tells us to fall + * back to the minimum size instead, if available. */ + if (!has_base_size && size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { base_width = size_hints.min_width; base_height = size_hints.min_height; } - if (base_width != con->window->base_width || - base_height != con->window->base_height) { + // TODO XXX Should we only do this is the base size is > 0? + if (base_width != con->window->base_width || base_height != con->window->base_height) { con->window->base_width = base_width; con->window->base_height = base_height; + DLOG("client's base_height changed to %d\n", base_height); DLOG("client's base_width changed to %d\n", base_width); changed = true; @@ -989,9 +1007,13 @@ static bool handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t stat goto render_and_return; } - /* XXX: do we really use rect here, not window_rect? */ - double width = con->rect.width - base_width; - double height = con->rect.height - base_height; + /* The ICCCM says to subtract the base size from the window size for aspect + * ratio calculations. However, unlike determining the base size itself we + * must not fall back to using the minimum size in this case according to + * the ICCCM. */ + double width = win_width - base_width * has_base_size; + double height = win_height - base_height * has_base_size; + /* Convert numerator/denominator to a double */ double min_aspect = (double)size_hints.min_aspect_num / size_hints.min_aspect_den; double max_aspect = (double)size_hints.max_aspect_num / size_hints.min_aspect_den; @@ -1000,8 +1022,9 @@ static bool handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t stat DLOG("width = %f, height = %f\n", width, height); /* Sanity checks, this is user-input, in a way */ - if (max_aspect <= 0 || min_aspect <= 0 || height == 0 || (width / height) <= 0) + if (max_aspect <= 0 || min_aspect <= 0 || height == 0 || (width / height) <= 0) { goto render_and_return; + } /* Check if we need to set proportional_* variables using the correct ratio */ double aspect_ratio = 0.0; @@ -1009,8 +1032,9 @@ static bool handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t stat aspect_ratio = min_aspect; } else if ((width / height) > max_aspect) { aspect_ratio = max_aspect; - } else + } else { goto render_and_return; + } if (fabs(con->window->aspect_ratio - aspect_ratio) > DBL_EPSILON) { con->window->aspect_ratio = aspect_ratio; @@ -1018,8 +1042,10 @@ static bool handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t stat } render_and_return: - if (changed) + if (changed) { tree_render(); + } + FREE(reply); return true; } diff --git a/src/manage.c b/src/manage.c index 81ee16fd..86a361c3 100644 --- a/src/manage.c +++ b/src/manage.c @@ -491,6 +491,12 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki geom->height = wm_size_hints.height; } + if (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { + DLOG("Window specifies minimum size %d x %d\n", wm_size_hints.min_width, wm_size_hints.min_height); + nc->window->min_width = wm_size_hints.min_width; + nc->window->min_height = wm_size_hints.min_height; + } + /* Store the requested geometry. The width/height gets raised to at least * 75x50 when entering floating mode, which is the minimum size for a * window to be useful (smaller windows are usually overlays/toolbars/… diff --git a/testcases/t/141-resize.t b/testcases/t/141-resize.t index 44ad9bbf..64e33bc3 100644 --- a/testcases/t/141-resize.t +++ b/testcases/t/141-resize.t @@ -298,11 +298,11 @@ sub get_floating_rect { # focus is on the right window, so we resize the left one using criteria my $leftold = get_floating_rect($left->id); my $rightold = get_floating_rect($right->id); -cmd '[id="' . $left->id . '"] resize shrink height 10px or 10ppt'; +cmd '[id="' . $left->id . '"] resize grow height 10px or 10ppt'; my $leftnew = get_floating_rect($left->id); my $rightnew = get_floating_rect($right->id); is($rightnew->{height}, $rightold->{height}, 'height of right container unchanged'); -is($leftnew->{height}, $leftold->{height} - 10, 'height of left container changed'); +is($leftnew->{height}, $leftold->{height} + 10, 'height of left container changed'); done_testing; diff --git a/testcases/t/221-floating-type-hints.t b/testcases/t/221-floating-type-hints.t index 01c73a75..60590904 100644 --- a/testcases/t/221-floating-type-hints.t +++ b/testcases/t/221-floating-type-hints.t @@ -62,10 +62,10 @@ sub open_with_fixed_size { my $flags = $XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | $XCB_ICCCM_SIZE_HINT_P_MAX_SIZE; - my $min_width = 55; - my $max_width = 55; - my $min_height = 77; - my $max_height = 77; + my $min_width = 150; + my $max_width = 150; + my $min_height = 100; + my $max_height = 100; my $pad = 0x00; @@ -82,7 +82,7 @@ sub open_with_fixed_size { $atomtype->id, 32, 12, - pack('C5N8', $flags, $pad, $pad, $pad, $pad, 0, 0, 0, $min_width, $min_height, $max_width, $max_height), + pack('C5N7', $flags, $pad, $pad, $pad, $pad, 0, 0, 0, $min_width, $min_height, $max_width, $max_height), ); }, ); @@ -114,6 +114,8 @@ $window->unmap; $window = open_with_fixed_size; is(get_ws($ws)->{floating_nodes}[0]->{nodes}[0]->{window}, $window->id, 'Fixed size window opened floating'); +is(get_ws($ws)->{floating_nodes}[0]->{nodes}[0]->{window_rect}->{width}, 150, 'Fixed size window opened with minimum width'); +is(get_ws($ws)->{floating_nodes}[0]->{nodes}[0]->{window_rect}->{height}, 100, 'Fixed size window opened with minimum height'); $window->unmap; done_testing; From d7dcef61d70bea4d3f0b6de5b59435c26aea9b50 Mon Sep 17 00:00:00 2001 From: Johannes Lange Date: Wed, 30 Nov 2016 08:19:36 +0100 Subject: [PATCH 021/180] `move` syntax clarification: (#2591) both x and y position need to be specified --- docs/userguide | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/userguide b/docs/userguide index acdc0a58..e1e65c24 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1921,7 +1921,8 @@ move [ px] # Moves the container either to a specific location # or to the center of the screen. If 'absolute' is # used, it is moved to the center of all outputs. -move [absolute] position [[ px] [ px]|center] +move [absolute] position [px] [px] +move [absolute] position center # Moves the container to the current position of the # mouse cursor. Only affects floating containers. From 05a2270eb7aff19b060ebac7830a29c5278b7cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Moravec?= Date: Fri, 2 Dec 2016 18:53:59 +0100 Subject: [PATCH 022/180] Fix read of uninitialized memory (#2596) Previous code was reading whole array, it was slower and it read uninitialized memory --- src/bindings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings.c b/src/bindings.c index eec821b6..c76e7779 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -981,7 +981,7 @@ int *bindings_get_buttons_to_grab(void) { } /* Avoid duplicates. */ - for (int i = 0; i < num_max; i++) { + for (int i = 0; i < num; i++) { if (buffer[i] == button) continue; } From 6b9b12c3038a766b68ea9c5e8a4b815163cd9049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 2 Dec 2016 19:05:43 +0100 Subject: [PATCH 023/180] Do not set input focus in i3-input. (#2598) This commit removes all traces of setting and reverting the input focus in i3-input. We don't need to do this because grabbing the keyboard is sufficient to have the attention we need. Changing the input focus and reverting it can cause situations where i3 executes the IPC command before processing the FocusIn events. This leads to i3's input focus change to be rejected due to the timing, leading to an inconsistent focus state. fixes #2597 --- i3-input/main.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/i3-input/main.c b/i3-input/main.c index 97d574a2..0f07c845 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -54,7 +54,6 @@ static int limit; xcb_window_t root; xcb_connection_t *conn; xcb_screen_t *root_screen; -static xcb_get_input_focus_cookie_t focus_cookie; /* * Having verboselog(), errorlog() and debuglog() is necessary when using libi3. @@ -79,24 +78,6 @@ void errorlog(char *fmt, ...) { void debuglog(char *fmt, ...) { } -/* - * Restores the X11 input focus to wherever it was before. - * This is necessary because i3-input’s window has override_redirect=1 - * (→ unmanaged by the window manager) and thus i3-input changes focus itself. - * This function is called on exit(). - * - */ -static void restore_input_focus(void) { - xcb_generic_error_t *error; - xcb_get_input_focus_reply_t *reply = xcb_get_input_focus_reply(conn, focus_cookie, &error); - if (error != NULL) { - fprintf(stderr, "[i3-input] ERROR: Could not restore input focus (X error %d)\n", error->error_code); - return; - } - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, reply->focus, XCB_CURRENT_TIME); - xcb_flush(conn); -} - /* * Concats the glyphs (either UCS-2 or UTF-8) to a single string, suitable for * rendering it (UCS-2) or sending it to i3 (UTF-8). @@ -208,10 +189,6 @@ static void finish_input() { /* prefix the command if a prefix was specified on commandline */ printf("command = %s\n", full); - restore_input_focus(); - - xcb_aux_sync(conn); - ipc_send_message(sockfd, strlen(full), 0, (uint8_t *)full); free(full); @@ -265,7 +242,6 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press return 1; } if (sym == XK_Escape) { - restore_input_focus(); exit(0); } @@ -467,9 +443,6 @@ int main(int argc, char *argv[]) { sockfd = ipc_connect(socket_path); - /* Request the current InputFocus to restore when i3-input exits. */ - focus_cookie = xcb_get_input_focus(conn); - root_screen = xcb_aux_get_screen(conn, screen); root = root_screen->root; @@ -509,10 +482,6 @@ int main(int argc, char *argv[]) { xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, logical_px(500), font.height + logical_px(8)); xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0); - /* Set input focus (we have override_redirect=1, so the wm will not do - * this for us) */ - xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME); - /* Grab the keyboard to get all input */ xcb_flush(conn); @@ -531,7 +500,6 @@ int main(int argc, char *argv[]) { if (reply->status != XCB_GRAB_STATUS_SUCCESS) { fprintf(stderr, "Could not grab keyboard, status = %d\n", reply->status); - restore_input_focus(); exit(-1); } From fbf58a67bb0bc74d5fa6da14aafb9a0ac649df7c Mon Sep 17 00:00:00 2001 From: cresh Date: Fri, 2 Dec 2016 19:06:39 +0100 Subject: [PATCH 024/180] Some systems need to link to libiconv explicitly, thus add a check for it. (#2586) --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index b57f9efa..c0f3258d 100644 --- a/configure.ac +++ b/configure.ac @@ -85,6 +85,8 @@ AC_SEARCH_LIBS([ev_run], [ev], , [AC_MSG_FAILURE([cannot find the required ev_ru AC_SEARCH_LIBS([shm_open], [rt]) +AC_SEARCH_LIBS([iconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the required iconv_open() function despite trying to link with -liconv])]) + AX_PTHREAD dnl Each prefix corresponds to a source tarball which users might have From 8d739b7fe15fd351b5d703f922db01be46699a92 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Fri, 9 Dec 2016 08:37:49 +0100 Subject: [PATCH 025/180] Fix name of mcedit (#2524) It's "mcedit", not "mc-edit". --- i3-sensible-editor | 2 +- man/i3-sensible-editor.man | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/i3-sensible-editor b/i3-sensible-editor index b93893a1..ad3f6bdd 100755 --- a/i3-sensible-editor +++ b/i3-sensible-editor @@ -9,7 +9,7 @@ # mechanism to find the preferred editor # Hopefully one of these is installed (no flamewars about preference please!): -for editor in "$VISUAL" "$EDITOR" nano nvim vim vi emacs pico qe mg jed gedit mc-edit; do +for editor in "$VISUAL" "$EDITOR" nano nvim vim vi emacs pico qe mg jed gedit mcedit; do if command -v "$editor" > /dev/null 2>&1; then exec "$editor" "$@" fi diff --git a/man/i3-sensible-editor.man b/man/i3-sensible-editor.man index bfc5c5c6..effae6c0 100644 --- a/man/i3-sensible-editor.man +++ b/man/i3-sensible-editor.man @@ -29,7 +29,7 @@ It tries to start one of the following (in that order): * mg * jed * gedit -* mc-edit +* mcedit Please don’t complain about the order: If the user has any preference, they will have $VISUAL or $EDITOR set. From 25d27c5b2e0050e4bcc6bcdf8c03d7ab949b77db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 2 Jan 2017 15:56:28 +0100 Subject: [PATCH 026/180] Free allocated X resource value. (#2620) This fixes a little memory leak. --- libi3/dpi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libi3/dpi.c b/libi3/dpi.c index d0d1bc68..ce85cacc 100644 --- a/libi3/dpi.c +++ b/libi3/dpi.c @@ -53,6 +53,10 @@ void init_dpi(void) { DLOG("Found Xft.dpi = %ld.\n", dpi); init_dpi_end: + if (resource != NULL) { + free(resource); + } + if (database != NULL) { xcb_xrm_database_free(database); } From 46fcb1188f15b5e9410b7ce6287886639765c04d Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 3 Jan 2017 09:38:45 +0100 Subject: [PATCH 027/180] .github/CONTRIBUTING.md: explain that compositors are unsupported (#2621) --- .github/CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 474355ad..c19ac81e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,6 +14,9 @@ Note that bug reports and feature requests for related projects should be filed having access to the source code is too time-consuming. Additionally, experience has shown that often, the software in question is responsible for the issue. Please raise an issue with the software in question, not i3. +5. Please note that i3 does not support compositors (e.g. compton). If you + encountered the issue you are about to report while using a compositor, + please try reproducing it without a compositor. ## Pull requests From 9cb5df42d2bab6a5bbce5073efd458de147233a7 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Mon, 9 Jan 2017 18:47:16 -0600 Subject: [PATCH 028/180] properly detect version when building out of tree --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c0f3258d..9d4b2f40 100644 --- a/configure.ac +++ b/configure.ac @@ -31,8 +31,8 @@ AX_EXTEND_SRCDIR AS_IF([test -d ${srcdir}/.git], [ - VERSION="$(git describe --tags --abbrev=0)" - I3_VERSION="$(git describe --tags --always) ($(git log --pretty=format:%cd --date=short -n1), branch \\\"$(git describe --tags --always --all | sed s:heads/::)\\\")" + VERSION="$(git -C ${srcdir} describe --tags --abbrev=0)" + I3_VERSION="$(git -C ${srcdir} describe --tags --always) ($(git -C ${srcdir} log --pretty=format:%cd --date=short -n1), branch \\\"$(git -C ${srcdir} describe --tags --always --all | sed s:heads/::)\\\")" # Mirrors what libi3/is_debug_build.c does: is_release=$(test $(echo "${I3_VERSION}" | cut -d '(' -f 1 | wc -m) -lt 10 && echo yes || echo no) ], From 934b23fa52dd404d29970cd083d411f5e7b52263 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Mon, 9 Jan 2017 18:43:38 -0600 Subject: [PATCH 029/180] fix auto exclude in-work-tree build dirs updates: -- configure: add build directory to gitignore #2543 -- https://github.com/i3/i3/pull/2543 --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 9d4b2f40..4f67d5ea 100644 --- a/configure.ac +++ b/configure.ac @@ -154,8 +154,9 @@ else print_BUILD_MANS=no fi -git_dir=`git rev-parse --git-dir 2>/dev/null` -if test -n "$git_dir"; then +in_git_worktree=`git rev-parse --is-inside-work-tree 2>/dev/null` +if "$in_git_worktree" == "true"; then + git_dir=`git rev-parse --git-dir 2>/dev/null` srcdir=`dirname "$git_dir"` exclude_dir=`pwd | sed "s,^$srcdir,,g"` if ! grep -q "^$exclude_dir" "$git_dir/info/exclude"; then From 6da187b27f8e398366b50a04b3a09528e4453688 Mon Sep 17 00:00:00 2001 From: Johannes Lange Date: Tue, 10 Jan 2017 09:22:22 +0100 Subject: [PATCH 030/180] linking vim_like_marks from show_marks documentation (first occurrence (#2626) of marks in userguide) --- docs/userguide | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/userguide b/docs/userguide index e1e65c24..6dc2241b 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1127,9 +1127,9 @@ none:: [[show_marks]] === Drawing marks on window decoration -If activated, marks on windows are drawn in their window decoration. However, -any mark starting with an underscore in its name (+_+) will not be drawn even if -this option is activated. +If activated, marks (see <>) on windows are drawn in their window +decoration. However, any mark starting with an underscore in its name (+_+) will +not be drawn even if this option is activated. The default for this option is +yes+. From 584263b1b3393015d7c77a63e21bd5c50583e5ce Mon Sep 17 00:00:00 2001 From: Jens-Wolfhard Schicke-Uffmann Date: Tue, 10 Jan 2017 09:29:06 +0100 Subject: [PATCH 031/180] Report error during error log creation (#2625) --- src/log.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/log.c b/src/log.c index 1c33649a..916085f4 100644 --- a/src/log.c +++ b/src/log.c @@ -88,8 +88,13 @@ void init_logging(void) { fprintf(stderr, "Could not initialize errorlog\n"); else { errorfile = fopen(errorfilename, "w"); - if (fcntl(fileno(errorfile), F_SETFD, FD_CLOEXEC)) { - fprintf(stderr, "Could not set close-on-exec flag\n"); + if (!errorfile) { + fprintf(stderr, "Could not initialize errorlog on %s: %s\n", + errorfilename, strerror(errno)); + } else { + if (fcntl(fileno(errorfile), F_SETFD, FD_CLOEXEC)) { + fprintf(stderr, "Could not set close-on-exec flag\n"); + } } } } From abf830079230c3806e0fdf8b97c4c12832bec7fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Wed, 4 Jan 2017 10:41:47 +0100 Subject: [PATCH 032/180] Rewrite the signal handler dialogs. This commit is a rewrite of the popup dialogs used when i3 crashes. We now use our draw_util suite and both properly react to EXPOSE events and clean up the windows when the handler exits. As a side-effect, this fixes #2422 --- include/sighandler.h | 7 +- src/sighandler.c | 343 +++++++++++++++++++++++-------------------- 2 files changed, 186 insertions(+), 164 deletions(-) diff --git a/include/sighandler.h b/include/sighandler.h index 20ede4eb..2cc20cd2 100644 --- a/include/sighandler.h +++ b/include/sighandler.h @@ -3,10 +3,6 @@ * * i3 - an improved dynamic tiling window manager * © 2009 Michael Stapelberg and contributors (see also: LICENSE) - * © 2009 Jan-Erik Rediger - * - * sighandler.c: Interactive crash dialog upon SIGSEGV/SIGABRT/SIGFPE (offers - * to restart inplace). * */ #pragma once @@ -14,7 +10,8 @@ #include /** - * Setup signal handlers to safely handle SIGSEGV and SIGFPE + * Configured a signal handler to gracefully handle crashes and allow the user + * to generate a backtrace and rescue their session. * */ void setup_signal_handler(void); diff --git a/src/sighandler.c b/src/sighandler.c index 79f90d9a..8ce0d9d7 100644 --- a/src/sighandler.c +++ b/src/sighandler.c @@ -3,10 +3,6 @@ * * i3 - an improved dynamic tiling window manager * © 2009 Michael Stapelberg and contributors (see also: LICENSE) - * © 2009 Jan-Erik Rediger - * - * sighandler.c: Interactive crash dialog upon SIGSEGV/SIGABRT/SIGFPE (offers - * to restart inplace). * */ #include "all.h" @@ -20,28 +16,44 @@ #include -static void open_popups(void); +typedef struct dialog_t { + xcb_window_t id; + xcb_colormap_t colormap; + Rect dims; + surface_t surface; -static xcb_gcontext_t pixmap_gc; -static xcb_pixmap_t pixmap; + TAILQ_ENTRY(dialog_t) + dialogs; +} dialog_t; + +static TAILQ_HEAD(dialogs_head, dialog_t) dialogs = TAILQ_HEAD_INITIALIZER(dialogs); static int raised_signal; - -static char *crash_text[] = { - "i3 just crashed.", - "To debug this problem, either attach gdb now", - "or press", - "- 'b' to save a backtrace (needs GDB),", - "- 'r' to restart i3 in-place or", - "- 'f' to forget the current layout and restart"}; -static int crash_text_longest = 5; -static int backtrace_string_index = 3; static int backtrace_done = 0; +static int sighandler_backtrace(void); +static void sighandler_setup(void); +static void sighandler_create_dialogs(void); +static void sighandler_destroy_dialogs(void); +static void sighandler_handle_expose(void); +static void sighandler_draw_dialog(dialog_t *dialog); +static void sighandler_handle_key_press(xcb_key_press_event_t *event); + +static i3String *message_intro; +static i3String *message_intro2; +static i3String *message_option_backtrace; +static i3String *message_option_restart; +static i3String *message_option_forget; +static int dialog_width; +static int dialog_height; + +static int border_width = 2; +static int margin = 4; + /* * Attach gdb to pid_parent and dump a backtrace to i3-backtrace.$pid in the * tmpdir */ -static int backtrace(void) { +static int sighandler_backtrace(void) { char *tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; @@ -125,53 +137,144 @@ static int backtrace(void) { return 1; } -/* - * Draw the window containing the info text - * - */ -static int sig_draw_window(xcb_window_t win, int width, int height, int font_height, i3String **crash_text_i3strings) { - /* re-draw the background */ - xcb_rectangle_t border = {0, 0, width, height}, - inner = {2, 2, width - 4, height - 4}; - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#FF0000")}); - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border); - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#000000")}); - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &inner); +static void sighandler_setup(void) { + border_width = logical_px(border_width); + margin = logical_px(margin); - /* restore font color */ - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000")); + int num_lines = 5; + message_intro = i3string_from_utf8("i3 has just crashed. Please report a bug for this."); + message_intro2 = i3string_from_utf8("To debug this problem, you can either attach gdb or choose from the following options:"); + message_option_backtrace = i3string_from_utf8("- 'b' to save a backtrace (requires gdb)"); + message_option_restart = i3string_from_utf8("- 'r' to restart i3 in-place"); + message_option_forget = i3string_from_utf8("- 'f' to forget the previous layout and restart i3"); - char *bt_colour = "#FFFFFF"; - if (backtrace_done < 0) - bt_colour = "#AA0000"; - else if (backtrace_done > 0) - bt_colour = "#00AA00"; + int width_longest_message = predict_text_width(message_intro2); - for (int i = 0; crash_text_i3strings[i] != NULL; ++i) { - /* fix the colour for the backtrace line when it finished */ - if (i == backtrace_string_index) - set_font_colors(pixmap_gc, draw_util_hex_to_color(bt_colour), draw_util_hex_to_color("#000000")); - - draw_text(crash_text_i3strings[i], pixmap, pixmap_gc, NULL, - 8, 5 + i * font_height, width - 16); - - /* and reset the colour again for other lines */ - if (i == backtrace_string_index) - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000")); - } - - /* Copy the contents of the pixmap to the real window */ - xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, width, height); - xcb_flush(conn); - - return 1; + dialog_width = width_longest_message + 2 * border_width + 2 * margin; + dialog_height = num_lines * config.font.height + 2 * border_width + 2 * margin; } -/* - * Handles keypresses of 'b', 'r' and 'f' to get a backtrace or restart i3 - * - */ -static int sig_handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) { +static void sighandler_create_dialogs(void) { + Output *output; + TAILQ_FOREACH(output, &outputs, outputs) { + if (!output->active) { + continue; + } + + dialog_t *dialog = scalloc(1, sizeof(struct dialog_t)); + TAILQ_INSERT_TAIL(&dialogs, dialog, dialogs); + + xcb_visualid_t visual = get_visualid_by_depth(root_depth); + dialog->colormap = xcb_generate_id(conn); + xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, dialog->colormap, root, visual); + + uint32_t mask = 0; + uint32_t values[4]; + int i = 0; + + /* Needs to be set in the case of a 32-bit root depth. */ + mask |= XCB_CW_BACK_PIXEL; + values[i++] = root_screen->black_pixel; + + /* Needs to be set in the case of a 32-bit root depth. */ + mask |= XCB_CW_BORDER_PIXEL; + values[i++] = root_screen->black_pixel; + + mask |= XCB_CW_OVERRIDE_REDIRECT; + values[i++] = 1; + + /* Needs to be set in the case of a 32-bit root depth. */ + mask |= XCB_CW_COLORMAP; + values[i++] = dialog->colormap; + + dialog->dims.x = output->rect.x + (output->rect.width / 2); + dialog->dims.y = output->rect.y + (output->rect.height / 2); + dialog->dims.width = dialog_width; + dialog->dims.height = dialog_height; + + /* Make sure the dialog is centered. */ + dialog->dims.x -= dialog->dims.width / 2; + dialog->dims.y -= dialog->dims.height / 2; + + dialog->id = create_window(conn, dialog->dims, root_depth, visual, + XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, + true, mask, values); + + draw_util_surface_init(conn, &(dialog->surface), dialog->id, get_visualtype_by_id(visual), + dialog->dims.width, dialog->dims.height); + + xcb_grab_keyboard(conn, false, dialog->id, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + + /* Confine the pointer to the crash dialog. */ + xcb_grab_pointer(conn, false, dialog->id, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, dialog->id, + XCB_NONE, XCB_CURRENT_TIME); + } + + sighandler_handle_expose(); + xcb_flush(conn); +} + +static void sighandler_destroy_dialogs(void) { + while (!TAILQ_EMPTY(&dialogs)) { + dialog_t *dialog = TAILQ_FIRST(&dialogs); + + xcb_free_colormap(conn, dialog->colormap); + draw_util_surface_free(conn, &(dialog->surface)); + xcb_destroy_window(conn, dialog->id); + + TAILQ_REMOVE(&dialogs, dialog, dialogs); + free(dialog); + } + + xcb_flush(conn); +} + +static void sighandler_handle_expose(void) { + dialog_t *current; + TAILQ_FOREACH(current, &dialogs, dialogs) { + sighandler_draw_dialog(current); + } + + xcb_flush(conn); +} + +static void sighandler_draw_dialog(dialog_t *dialog) { + const color_t black = draw_util_hex_to_color("#000000"); + const color_t white = draw_util_hex_to_color("#FFFFFF"); + const color_t red = draw_util_hex_to_color("#FF0000"); + + /* Start with a clean slate and draw a red border. */ + draw_util_clear_surface(conn, &(dialog->surface), red); + draw_util_rectangle(conn, &(dialog->surface), black, border_width, border_width, + dialog->dims.width - 2 * border_width, dialog->dims.height - 2 * border_width); + + int y = border_width + margin; + const int x = border_width + margin; + const int max_width = dialog->dims.width - 2 * x; + + draw_util_text(message_intro, &(dialog->surface), white, black, x, y, max_width); + y += config.font.height; + + draw_util_text(message_intro2, &(dialog->surface), white, black, x, y, max_width); + y += config.font.height; + + char *bt_color = "#FFFFFF"; + if (backtrace_done < 0) { + bt_color = "#AA0000"; + } else if (backtrace_done > 0) { + bt_color = "#00AA00"; + } + draw_util_text(message_option_backtrace, &(dialog->surface), draw_util_hex_to_color(bt_color), black, x, y, max_width); + y += config.font.height; + + draw_util_text(message_option_restart, &(dialog->surface), white, black, x, y, max_width); + y += config.font.height; + + draw_util_text(message_option_forget, &(dialog->surface), white, black, x, y, max_width); + y += config.font.height; +} + +static void sighandler_handle_key_press(xcb_key_press_event_t *event) { uint16_t state = event->state; /* Apparently, after activating numlock once, the numlock modifier @@ -186,106 +289,17 @@ static int sig_handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_p /* fork and exec/attach GDB to the parent to get a backtrace in the * tmpdir */ - backtrace_done = backtrace(); - - /* re-open the windows to indicate that it's finished */ - open_popups(); - } - - if (sym == 'r') + backtrace_done = sighandler_backtrace(); + sighandler_handle_expose(); + } else if (sym == 'r') { + sighandler_destroy_dialogs(); i3_restart(false); - - if (sym == 'f') + } else if (sym == 'f') { + sighandler_destroy_dialogs(); i3_restart(true); - - return 1; -} - -/* - * Opens the window we use for input/output and maps it - * - */ -static xcb_window_t open_input_window(xcb_connection_t *conn, Rect screen_rect, uint32_t width, uint32_t height) { - xcb_window_t win = xcb_generate_id(conn); - - uint32_t mask = 0; - uint32_t values[2]; - - mask |= XCB_CW_BACK_PIXEL; - values[0] = 0; - - mask |= XCB_CW_OVERRIDE_REDIRECT; - values[1] = 1; - - /* center each popup on the specified screen */ - uint32_t x = screen_rect.x + ((screen_rect.width / 2) - (width / 2)), - y = screen_rect.y + ((screen_rect.height / 2) - (height / 2)); - - xcb_create_window(conn, - XCB_COPY_FROM_PARENT, - win, /* the window id */ - root, /* parent == root */ - x, y, width, height, /* dimensions */ - 0, /* border = 0, we draw our own */ - XCB_WINDOW_CLASS_INPUT_OUTPUT, - XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ - mask, - values); - - /* Map the window (= make it visible) */ - xcb_map_window(conn, win); - - return win; -} - -static void open_popups() { - /* width and height of the popup window, so that the text fits in */ - int crash_text_num = sizeof(crash_text) / sizeof(char *); - int height = 13 + (crash_text_num * config.font.height); - - int crash_text_length = sizeof(crash_text) / sizeof(char *); - i3String **crash_text_i3strings = smalloc(sizeof(i3String *) * (crash_text_length + 1)); - /* Pre-compute i3Strings for our text */ - for (int i = 0; i < crash_text_length; ++i) { - crash_text_i3strings[i] = i3string_from_utf8(crash_text[i]); - } - crash_text_i3strings[crash_text_length] = NULL; - /* calculate width for longest text */ - int font_width = predict_text_width(crash_text_i3strings[crash_text_longest]); - int width = font_width + 20; - - /* Open a popup window on each virtual screen */ - Output *screen; - xcb_window_t win; - TAILQ_FOREACH(screen, &outputs, outputs) { - if (!screen->active) - continue; - win = open_input_window(conn, screen->rect, width, height); - - /* Create pixmap */ - pixmap = xcb_generate_id(conn); - pixmap_gc = xcb_generate_id(conn); - xcb_create_pixmap(conn, root_depth, pixmap, win, width, height); - xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0); - - /* Grab the keyboard to get all input */ - xcb_grab_keyboard(conn, false, win, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - - /* Grab the cursor inside the popup */ - xcb_grab_pointer(conn, false, win, XCB_NONE, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, win, XCB_NONE, XCB_CURRENT_TIME); - - sig_draw_window(win, width, height, config.font.height, crash_text_i3strings); - xcb_flush(conn); } } -/* - * Handle signals - * It creates a window asking the user to restart in-place - * or exit to generate a core dump - * - */ void handle_signal(int sig, siginfo_t *info, void *data) { DLOG("i3 crashed. SIG: %d\n", sig); @@ -294,22 +308,33 @@ void handle_signal(int sig, siginfo_t *info, void *data) { sigaction(sig, &action, NULL); raised_signal = sig; - open_popups(); + sighandler_setup(); + sighandler_create_dialogs(); xcb_generic_event_t *event; /* Yay, more own eventhandlers… */ while ((event = xcb_wait_for_event(conn))) { /* Strip off the highest bit (set if the event is generated) */ int type = (event->response_type & 0x7F); - if (type == XCB_KEY_PRESS) { - sig_handle_key_press(NULL, conn, (xcb_key_press_event_t *)event); + switch (type) { + case XCB_KEY_PRESS: + sighandler_handle_key_press((xcb_key_press_event_t *)event); + break; + case XCB_EXPOSE: + if (((xcb_expose_event_t *)event)->count == 0) { + sighandler_handle_expose(); + } + + break; } + free(event); } } /* - * Setup signal handlers to safely handle SIGSEGV and SIGFPE + * Configured a signal handler to gracefully handle crashes and allow the user + * to generate a backtrace and rescue their session. * */ void setup_signal_handler(void) { From 0a6e2865e0389e6ab346d22ba2caf4153e825907 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Tue, 10 Jan 2017 20:48:59 -0600 Subject: [PATCH 033/180] fix conditional in configure script --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4f67d5ea..87ffbbe7 100644 --- a/configure.ac +++ b/configure.ac @@ -155,7 +155,7 @@ else fi in_git_worktree=`git rev-parse --is-inside-work-tree 2>/dev/null` -if "$in_git_worktree" == "true"; then +if [[ "$in_git_worktree" = "true" ]]; then git_dir=`git rev-parse --git-dir 2>/dev/null` srcdir=`dirname "$git_dir"` exclude_dir=`pwd | sed "s,^$srcdir,,g"` From f7a0453543a43b3f5b0f603c7dfdf6cc1fd33808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 18:28:29 +0100 Subject: [PATCH 034/180] Free trayclient when removing it. (#2632) fixes #2619 --- i3bar/src/xcb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 2715e447..49c8de1c 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -870,11 +870,13 @@ static void handle_destroy_notify(xcb_destroy_notify_event_t *event) { DLOG("checking output %s\n", walk->name); trayclient *trayclient; TAILQ_FOREACH(trayclient, walk->trayclients, tailq) { - if (trayclient->win != event->window) + if (trayclient->win != event->window) { continue; + } DLOG("Removing tray client with window ID %08x\n", event->window); TAILQ_REMOVE(walk->trayclients, trayclient, tailq); + FREE(trayclient); /* Trigger an update, we now have more space for the statusline */ configure_trayclients(); @@ -1558,6 +1560,7 @@ void kick_tray_clients(i3_output *output) { /* We remove the trayclient right here. We might receive an UnmapNotify * event afterwards, but better safe than sorry. */ TAILQ_REMOVE(output->trayclients, trayclient, tailq); + FREE(trayclient); } /* Fake a DestroyNotify so that Qt re-adds tray icons. From 14eea7fce571ed6b1592af382aa4440b87c62b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 18:30:50 +0100 Subject: [PATCH 035/180] Added support for _NET_MOVERESIZE_WINDOW. (#2634) fixes #2603 --- include/atoms_NET_SUPPORTED.xmacro | 1 + src/handlers.c | 34 +++++++ testcases/t/266-net-moveresize-window.t | 117 ++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 testcases/t/266-net-moveresize-window.t diff --git a/include/atoms_NET_SUPPORTED.xmacro b/include/atoms_NET_SUPPORTED.xmacro index 1358e0f1..a7b9676d 100644 --- a/include/atoms_NET_SUPPORTED.xmacro +++ b/include/atoms_NET_SUPPORTED.xmacro @@ -31,3 +31,4 @@ xmacro(_NET_DESKTOP_NAMES) xmacro(_NET_DESKTOP_VIEWPORT) xmacro(_NET_ACTIVE_WINDOW) xmacro(_NET_CLOSE_WINDOW) +xmacro(_NET_MOVERESIZE_WINDOW) diff --git a/src/handlers.c b/src/handlers.c index 9b248058..e02a1ee5 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -637,6 +637,11 @@ static void handle_expose_event(xcb_expose_event_t *event) { #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ #define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */ +#define _NET_MOVERESIZE_WINDOW_X (1 << 8) +#define _NET_MOVERESIZE_WINDOW_Y (1 << 9) +#define _NET_MOVERESIZE_WINDOW_WIDTH (1 << 10) +#define _NET_MOVERESIZE_WINDOW_HEIGHT (1 << 11) + /* * Handle client messages (EWMH) * @@ -897,6 +902,35 @@ static void handle_client_message(xcb_client_message_event_t *event) { DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction); break; } + } else if (event->type == A__NET_MOVERESIZE_WINDOW) { + DLOG("Received _NET_MOVE_RESIZE_WINDOW. Handling by faking a configure request.\n"); + + void *_generated_event = scalloc(32, 1); + xcb_configure_request_event_t *generated_event = _generated_event; + + generated_event->window = event->window; + generated_event->response_type = XCB_CONFIGURE_REQUEST; + + generated_event->value_mask = 0; + if (event->data.data32[0] & _NET_MOVERESIZE_WINDOW_X) { + generated_event->value_mask |= XCB_CONFIG_WINDOW_X; + generated_event->x = event->data.data32[1]; + } + if (event->data.data32[0] & _NET_MOVERESIZE_WINDOW_Y) { + generated_event->value_mask |= XCB_CONFIG_WINDOW_Y; + generated_event->y = event->data.data32[2]; + } + if (event->data.data32[0] & _NET_MOVERESIZE_WINDOW_WIDTH) { + generated_event->value_mask |= XCB_CONFIG_WINDOW_WIDTH; + generated_event->width = event->data.data32[3]; + } + if (event->data.data32[0] & _NET_MOVERESIZE_WINDOW_HEIGHT) { + generated_event->value_mask |= XCB_CONFIG_WINDOW_HEIGHT; + generated_event->height = event->data.data32[4]; + } + + handle_configure_request(generated_event); + FREE(generated_event); } else { DLOG("Skipping client message for unhandled type %d\n", event->type); } diff --git a/testcases/t/266-net-moveresize-window.t b/testcases/t/266-net-moveresize-window.t new file mode 100644 index 00000000..69542f9c --- /dev/null +++ b/testcases/t/266-net-moveresize-window.t @@ -0,0 +1,117 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Tests for _NET_MOVERESIZE_WINDOW. +# Ticket: #2603 +use i3test i3_autostart => 0; + +sub moveresize_window { + my ($win, $pos_x, $pos_y, $width, $height) = @_; + + my $flags = 0; + $flags |= (1 << 8) if $pos_x >= 0; + $flags |= (1 << 9) if $pos_y >= 0; + $flags |= (1 << 10) if $width >= 0; + $flags |= (1 << 11) if $height >= 0; + + my $msg = pack "CCSLLLLLLL", + X11::XCB::CLIENT_MESSAGE, # response_type + 32, # format + 0, # sequence + $win->id, # window + $x->atom(name => '_NET_MOVERESIZE_WINDOW')->id, # message type + $flags, # data32[0] (flags) + $pos_x, # data32[1] (x) + $pos_y, # data32[2] (y) + $width, # data32[3] (width) + $height; # data32[4] (height) + + $x->send_event(0, $x->get_root_window(), X11::XCB::EVENT_MASK_SUBSTRUCTURE_REDIRECT, $msg); + sync_with_i3; +} + +my $config = < [50, 50, 100, 100]); +moveresize_window($window, 0, 0, 555, 666); + +$content = get_ws($ws); +is($content->{floating_nodes}->[0]->{rect}->{x}, 0, 'the x coordinate is correct'); +is($content->{floating_nodes}->[0]->{rect}->{y}, 0, 'the y coordinate is correct'); +is($content->{floating_nodes}->[0]->{rect}->{width}, 555, 'the width is correct'); +is($content->{floating_nodes}->[0]->{rect}->{height}, 666, 'the height is correct'); + +exit_gracefully($pid); + +############################################################################### +# A _NET_MOVERESIZE_WINDOW client message can change only the position of a +# window. +############################################################################### + +$pid = launch_with_config($config); +$ws = fresh_workspace; + +$window = open_floating_window(rect => [50, 50, 100, 100]); +moveresize_window($window, 100, 100, -1, -1); + +$content = get_ws($ws); +is($content->{floating_nodes}->[0]->{rect}->{x}, 100, 'the x coordinate is correct'); +is($content->{floating_nodes}->[0]->{rect}->{y}, 100, 'the y coordinate is correct'); +is($content->{floating_nodes}->[0]->{rect}->{width}, 100, 'the width is unchanged'); +is($content->{floating_nodes}->[0]->{rect}->{height}, 100, 'the height is unchanged'); + +exit_gracefully($pid); + +############################################################################### +# A _NET_MOVERESIZE_WINDOW client message can change only the size of a +# window. +############################################################################### + +$pid = launch_with_config($config); +$ws = fresh_workspace; + +$window = open_floating_window(rect => [50, 50, 100, 100]); +moveresize_window($window, -1, -1, 200, 200); + +$content = get_ws($ws); +is($content->{floating_nodes}->[0]->{rect}->{x}, 50, 'the x coordinate is unchanged'); +is($content->{floating_nodes}->[0]->{rect}->{y}, 50, 'the y coordinate is unchanged'); +is($content->{floating_nodes}->[0]->{rect}->{width}, 200, 'the width is correct'); +is($content->{floating_nodes}->[0]->{rect}->{height}, 200, 'the height is correct'); + +exit_gracefully($pid); + +############################################################################### + +done_testing; From 33d6a4e829cf6b67f285541a86499b89d44b8a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 18:33:29 +0100 Subject: [PATCH 036/180] Validate that a binding mode is not defined more than once. (#2633) While defining the same mode usually wouldn't hurt and, in fact, the old behavior allows to split the definition of a binding mode into several blocks, this can lead to user errors where they accidentally define a mode twice and don't understand why the mode behaves a certain way (this has been observed in real life :-)). There's no good usecase for splitting a single binding mode into multiple blocks, thus the new behavior is better. fixes #2615 --- src/bindings.c | 3 ++- src/config_directives.c | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/bindings.c b/src/bindings.c index c76e7779..bfec27e1 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -32,8 +32,9 @@ static struct Mode *mode_from_name(const char *name, bool pango_markup) { /* Try to find the mode in the list of modes and return it */ SLIST_FOREACH(mode, &modes, modes) { - if (strcmp(mode->name, name) == 0) + if (strcmp(mode->name, name) == 0) { return mode; + } } /* If the mode was not found, create a new one */ diff --git a/src/config_directives.c b/src/config_directives.c index a260518c..82e1a346 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -126,6 +126,15 @@ CFGFUN(enter_mode, const char *pango_markup, const char *modename) { ELOG("You cannot use the name %s for your mode\n", DEFAULT_BINDING_MODE); exit(1); } + + struct Mode *mode; + SLIST_FOREACH(mode, &modes, modes) { + if (strcmp(mode->name, modename) == 0) { + ELOG("The binding mode with name \"%s\" is defined at least twice.\n", modename); + exit(1); + } + } + DLOG("\t now in mode %s\n", modename); FREE(current_mode); current_mode = sstrdup(modename); From e0582aa5ebf7f4497c55d9350f503124bc0271c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 18:34:09 +0100 Subject: [PATCH 037/180] Remove unused function arguments. (#2635) The connection is no longer necessary since the non-cairo paths have been removed. --- i3bar/src/xcb.c | 23 +++++++++++------------ include/libi3.h | 6 +++--- libi3/draw_util.c | 14 +++++++------- src/handlers.c | 2 +- src/sighandler.c | 4 ++-- src/x.c | 42 +++++++++++++++++++++--------------------- 6 files changed, 45 insertions(+), 46 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 49c8de1c..d3bfca69 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -181,7 +181,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b uint32_t center_x = x - sep_offset; if (config.separator_symbol == NULL) { /* Draw a classic one pixel, vertical separator. */ - draw_util_rectangle(xcb_connection, &output->statusline_buffer, sep_fg, + draw_util_rectangle(&output->statusline_buffer, sep_fg, center_x, logical_px(sep_voff_px), logical_px(1), @@ -250,7 +250,7 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color struct status_block *block; color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg); - draw_util_clear_surface(xcb_connection, &output->statusline_buffer, bar_color); + draw_util_clear_surface(&output->statusline_buffer, bar_color); /* Use unsigned integer wraparound to clip off the left side. * For example, if clip_left is 75, then x will start at the very large @@ -301,13 +301,13 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color } /* Draw the border. */ - draw_util_rectangle(xcb_connection, &output->statusline_buffer, border_color, + draw_util_rectangle(&output->statusline_buffer, border_color, x, logical_px(1), full_render_width, bar_height - logical_px(2)); /* Draw the background. */ - draw_util_rectangle(xcb_connection, &output->statusline_buffer, bg_color, + draw_util_rectangle(&output->statusline_buffer, bg_color, x + border_width, logical_px(1) + border_width, full_render_width - 2 * border_width, @@ -1946,8 +1946,7 @@ void draw_bars(bool unhide) { bool use_focus_colors = output_has_focus(outputs_walk); /* First things first: clear the backbuffer */ - draw_util_clear_surface(xcb_connection, &(outputs_walk->buffer), - (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg)); + draw_util_clear_surface(&(outputs_walk->buffer), (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg)); if (!config.disable_ws) { i3_ws *ws_walk; @@ -1977,14 +1976,14 @@ void draw_bars(bool unhide) { } /* Draw the border of the button. */ - draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), border_color, + draw_util_rectangle(&(outputs_walk->buffer), border_color, workspace_width, logical_px(1), ws_walk->name_width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1), font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1)); /* Draw the inside of the button. */ - draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color, + draw_util_rectangle(&(outputs_walk->buffer), bg_color, workspace_width + logical_px(1), 2 * logical_px(1), ws_walk->name_width + 2 * logical_px(ws_hoff_px), @@ -2007,13 +2006,13 @@ void draw_bars(bool unhide) { color_t fg_color = colors.binding_mode_fg; color_t bg_color = colors.binding_mode_bg; - draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), colors.binding_mode_border, + draw_util_rectangle(&(outputs_walk->buffer), colors.binding_mode_border, workspace_width, logical_px(1), binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1), font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1)); - draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color, + draw_util_rectangle(&(outputs_walk->buffer), bg_color, workspace_width + logical_px(1), 2 * logical_px(1), binding.width + 2 * logical_px(ws_hoff_px), @@ -2049,7 +2048,7 @@ void draw_bars(bool unhide) { int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width; draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text); - draw_util_copy_surface(xcb_connection, &outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0, + draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0, x_dest, 0, visible_statusline_width, (int16_t)bar_height); outputs_walk->statusline_width = statusline_width; @@ -2080,7 +2079,7 @@ void redraw_bars(void) { continue; } - draw_util_copy_surface(xcb_connection, &(outputs_walk->buffer), &(outputs_walk->bar), 0, 0, + draw_util_copy_surface(&(outputs_walk->buffer), &(outputs_walk->bar), 0, 0, 0, 0, outputs_walk->rect.w, outputs_walk->rect.h); xcb_flush(xcb_connection); } diff --git a/include/libi3.h b/include/libi3.h index 94e1d78b..d33d6c71 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -597,17 +597,17 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_ * surface as well as restoring the cairo state. * */ -void draw_util_rectangle(xcb_connection_t *conn, surface_t *surface, color_t color, double x, double y, double w, double h); +void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, double w, double h); /** * Clears a surface with the given color. * */ -void draw_util_clear_surface(xcb_connection_t *conn, surface_t *surface, color_t color); +void draw_util_clear_surface(surface_t *surface, color_t color); /** * Copies a surface onto another surface. * */ -void draw_util_copy_surface(xcb_connection_t *conn, surface_t *src, surface_t *dest, double src_x, double src_y, +void draw_util_copy_surface(surface_t *src, surface_t *dest, double src_x, double src_y, double dest_x, double dest_y, double width, double height); diff --git a/libi3/draw_util.c b/libi3/draw_util.c index e471405b..e4f0d065 100644 --- a/libi3/draw_util.c +++ b/libi3/draw_util.c @@ -19,7 +19,7 @@ xcb_visualtype_t *visual_type; /* Forward declarations */ -static void draw_util_set_source_color(xcb_connection_t *conn, surface_t *surface, color_t color); +static void draw_util_set_source_color(surface_t *surface, color_t color); #define RETURN_UNLESS_SURFACE_INITIALIZED(surface) \ do { \ @@ -110,7 +110,7 @@ color_t draw_util_hex_to_color(const char *color) { * Set the given color as the source color on the surface. * */ -static void draw_util_set_source_color(xcb_connection_t *conn, surface_t *surface, color_t color) { +static void draw_util_set_source_color(surface_t *surface, color_t color) { RETURN_UNLESS_SURFACE_INITIALIZED(surface); cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha); @@ -141,7 +141,7 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_ * surface as well as restoring the cairo state. * */ -void draw_util_rectangle(xcb_connection_t *conn, surface_t *surface, color_t color, double x, double y, double w, double h) { +void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, double w, double h) { RETURN_UNLESS_SURFACE_INITIALIZED(surface); cairo_save(surface->cr); @@ -150,7 +150,7 @@ void draw_util_rectangle(xcb_connection_t *conn, surface_t *surface, color_t col * onto the surface rather than blending it. This is a bit more efficient and * allows better color control for the user when using opacity. */ cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE); - draw_util_set_source_color(conn, surface, color); + draw_util_set_source_color(surface, color); cairo_rectangle(surface->cr, x, y, w, h); cairo_fill(surface->cr); @@ -166,7 +166,7 @@ void draw_util_rectangle(xcb_connection_t *conn, surface_t *surface, color_t col * Clears a surface with the given color. * */ -void draw_util_clear_surface(xcb_connection_t *conn, surface_t *surface, color_t color) { +void draw_util_clear_surface(surface_t *surface, color_t color) { RETURN_UNLESS_SURFACE_INITIALIZED(surface); cairo_save(surface->cr); @@ -175,7 +175,7 @@ void draw_util_clear_surface(xcb_connection_t *conn, surface_t *surface, color_t * onto the surface rather than blending it. This is a bit more efficient and * allows better color control for the user when using opacity. */ cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE); - draw_util_set_source_color(conn, surface, color); + draw_util_set_source_color(surface, color); cairo_paint(surface->cr); @@ -190,7 +190,7 @@ void draw_util_clear_surface(xcb_connection_t *conn, surface_t *surface, color_t * Copies a surface onto another surface. * */ -void draw_util_copy_surface(xcb_connection_t *conn, surface_t *src, surface_t *dest, double src_x, double src_y, +void draw_util_copy_surface(surface_t *src, surface_t *dest, double src_x, double src_y, double dest_x, double dest_y, double width, double height) { RETURN_UNLESS_SURFACE_INITIALIZED(src); RETURN_UNLESS_SURFACE_INITIALIZED(dest); diff --git a/src/handlers.c b/src/handlers.c index e02a1ee5..6d7be465 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -617,7 +617,7 @@ static void handle_expose_event(xcb_expose_event_t *event) { * only tell us that the X server lost (parts of) the window contents. We * can handle that by copying the appropriate part from our surface to the * window. */ - draw_util_copy_surface(conn, &(parent->frame_buffer), &(parent->frame), + draw_util_copy_surface(&(parent->frame_buffer), &(parent->frame), event->x, event->y, event->x, event->y, event->width, event->height); xcb_flush(conn); diff --git a/src/sighandler.c b/src/sighandler.c index 8ce0d9d7..b1e7d166 100644 --- a/src/sighandler.c +++ b/src/sighandler.c @@ -244,8 +244,8 @@ static void sighandler_draw_dialog(dialog_t *dialog) { const color_t red = draw_util_hex_to_color("#FF0000"); /* Start with a clean slate and draw a red border. */ - draw_util_clear_surface(conn, &(dialog->surface), red); - draw_util_rectangle(conn, &(dialog->surface), black, border_width, border_width, + draw_util_clear_surface(&(dialog->surface), red); + draw_util_rectangle(&(dialog->surface), black, border_width, border_width, dialog->dims.width - 2 * border_width, dialog->dims.height - 2 * border_width); int y = border_width + margin; diff --git a/src/x.c b/src/x.c index c2153d5c..f3dbc237 100644 --- a/src/x.c +++ b/src/x.c @@ -330,10 +330,10 @@ static void x_draw_title_border(Con *con, struct deco_render_params *p) { deco_diff_r = 0; } - draw_util_rectangle(conn, &(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, dr->x, dr->y, dr->width, 1); - draw_util_rectangle(conn, &(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, dr->x + deco_diff_l, dr->y + dr->height - 1, dr->width - (deco_diff_l + deco_diff_r), 1); } @@ -349,7 +349,7 @@ static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p /* We actually only redraw the far right two pixels as that is the * distance we keep from the edge (not the entire border width). * Redrawing the entire border would cause text to be cut off. */ - draw_util_rectangle(conn, &(con->parent->frame_buffer), p->color->background, + draw_util_rectangle(&(con->parent->frame_buffer), p->color->background, dr->x + dr->width - 2 * logical_px(1), dr->y, 2 * logical_px(1), @@ -360,11 +360,11 @@ static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p * be easily distinguished. */ if (con->parent->layout == L_TABBED) { /* Left side */ - draw_util_rectangle(conn, &(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, dr->x, dr->y, 1, dr->height); /* Right side */ - draw_util_rectangle(conn, &(con->parent->frame_buffer), p->color->border, + draw_util_rectangle(&(con->parent->frame_buffer), p->color->border, dr->x + dr->width - 1, dr->y, 1, dr->height); } @@ -458,16 +458,16 @@ void x_draw_decoration(Con *con) { /* 2: draw the client.background, but only for the parts around the window_rect */ if (con->window != NULL) { /* top area */ - draw_util_rectangle(conn, &(con->frame_buffer), config.client.background, + draw_util_rectangle(&(con->frame_buffer), config.client.background, 0, 0, r->width, w->y); /* bottom area */ - draw_util_rectangle(conn, &(con->frame_buffer), config.client.background, + draw_util_rectangle(&(con->frame_buffer), config.client.background, 0, w->y + w->height, r->width, r->height - (w->y + w->height)); /* left area */ - draw_util_rectangle(conn, &(con->frame_buffer), config.client.background, + draw_util_rectangle(&(con->frame_buffer), config.client.background, 0, 0, w->x, r->height); /* right area */ - draw_util_rectangle(conn, &(con->frame_buffer), config.client.background, + draw_util_rectangle(&(con->frame_buffer), config.client.background, w->x + w->width, 0, r->width - (w->x + w->width), r->height); } @@ -484,21 +484,21 @@ void x_draw_decoration(Con *con) { * rectangle because some childs are not freely resizable and we want * their background color to "shine through". */ if (!(borders_to_hide & ADJ_LEFT_SCREEN_EDGE)) { - draw_util_rectangle(conn, &(con->frame_buffer), p->color->child_border, 0, 0, br.x, r->height); + draw_util_rectangle(&(con->frame_buffer), p->color->child_border, 0, 0, br.x, r->height); } if (!(borders_to_hide & ADJ_RIGHT_SCREEN_EDGE)) { - draw_util_rectangle(conn, &(con->frame_buffer), + draw_util_rectangle(&(con->frame_buffer), p->color->child_border, r->width + (br.width + br.x), 0, -(br.width + br.x), r->height); } if (!(borders_to_hide & ADJ_LOWER_SCREEN_EDGE)) { - draw_util_rectangle(conn, &(con->frame_buffer), + draw_util_rectangle(&(con->frame_buffer), p->color->child_border, br.x, r->height + (br.height + br.y), r->width + br.width, -(br.height + br.y)); } /* pixel border needs an additional line at the top */ if (p->border_style == BS_PIXEL && !(borders_to_hide & ADJ_UPPER_SCREEN_EDGE)) { - draw_util_rectangle(conn, &(con->frame_buffer), + draw_util_rectangle(&(con->frame_buffer), p->color->child_border, br.x, 0, r->width + br.width, br.y); } @@ -510,10 +510,10 @@ void x_draw_decoration(Con *con) { TAILQ_PREV(con, nodes_head, nodes) == NULL && con->parent->type != CT_FLOATING_CON) { if (p->parent_layout == L_SPLITH) { - draw_util_rectangle(conn, &(con->frame_buffer), p->color->indicator, + draw_util_rectangle(&(con->frame_buffer), p->color->indicator, r->width + (br.width + br.x), br.y, -(br.width + br.x), r->height + br.height); } else if (p->parent_layout == L_SPLITV) { - draw_util_rectangle(conn, &(con->frame_buffer), p->color->indicator, + draw_util_rectangle(&(con->frame_buffer), p->color->indicator, br.x, r->height + (br.height + br.y), r->width + br.width, -(br.height + br.y)); } } @@ -533,12 +533,12 @@ void x_draw_decoration(Con *con) { * garbage left on there. This is important to avoid tearing when using * transparency. */ if (con == TAILQ_FIRST(&(con->parent->nodes_head))) { - draw_util_clear_surface(conn, &(con->parent->frame_buffer), COLOR_TRANSPARENT); + draw_util_clear_surface(&(con->parent->frame_buffer), COLOR_TRANSPARENT); FREE(con->parent->deco_render_params); } /* 4: paint the bar */ - draw_util_rectangle(conn, &(parent->frame_buffer), p->color->background, + draw_util_rectangle(&(parent->frame_buffer), p->color->background, con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height); /* 5: draw two unconnected horizontal lines in border color */ @@ -619,7 +619,7 @@ void x_draw_decoration(Con *con) { after_title: x_draw_decoration_after_title(con, p); copy_pixmaps: - draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); + draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); } /* @@ -642,7 +642,7 @@ void x_deco_recurse(Con *con) { x_deco_recurse(current); if (state->mapped) { - draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); + draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); } } @@ -829,7 +829,7 @@ void x_push_node(Con *con) { xcb_flush(conn); xcb_set_window_rect(conn, con->frame.id, rect); if (con->frame_buffer.id != XCB_NONE) { - draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); + draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); } xcb_flush(conn); @@ -881,7 +881,7 @@ void x_push_node(Con *con) { /* copy the pixmap contents to the frame window immediately after mapping */ if (con->frame_buffer.id != XCB_NONE) { - draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); + draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); } xcb_flush(conn); From f80cbf7872bc9ced15ff0428d8c1edf79713791a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 18:34:28 +0100 Subject: [PATCH 038/180] Fix blinking test. (#2637) Thanks to @sandsmark for figuring this out. --- testcases/t/221-floating-type-hints.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testcases/t/221-floating-type-hints.t b/testcases/t/221-floating-type-hints.t index 60590904..ae0f05c3 100644 --- a/testcases/t/221-floating-type-hints.t +++ b/testcases/t/221-floating-type-hints.t @@ -81,8 +81,8 @@ sub open_with_fixed_size { $atomname->id, $atomtype->id, 32, - 12, - pack('C5N7', $flags, $pad, $pad, $pad, $pad, 0, 0, 0, $min_width, $min_height, $max_width, $max_height), + 13, + pack('C5N8', $flags, $pad, $pad, $pad, $pad, 0, 0, 0, $min_width, $min_height, $max_width, $max_height), ); }, ); From d58dbc3a77a27624e70fb4ffd149af2716502863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 18:34:58 +0100 Subject: [PATCH 039/180] Only react on the last Expose event in a series of events. (#2636) Thanks to @psychon for pointing this out during the review of PR #2624. This commit extends this change to all other occurences of Expose events within i3. --- i3-config-wizard/main.c | 5 ++++- i3-input/main.c | 5 ++++- i3-nagbar/main.c | 5 ++++- i3bar/src/xcb.c | 7 +++++-- src/handlers.c | 5 ++++- src/restore_layout.c | 5 ++++- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 9e851c06..8eec941c 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -966,7 +966,10 @@ int main(int argc, char *argv[]) { break; case XCB_EXPOSE: - handle_expose(); + if (((xcb_expose_event_t *)event)->count == 0) { + handle_expose(); + } + break; } diff --git a/i3-input/main.c b/i3-input/main.c index 0f07c845..6d1e3378 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -525,7 +525,10 @@ int main(int argc, char *argv[]) { break; case XCB_EXPOSE: - handle_expose(NULL, conn, (xcb_expose_event_t *)event); + if (((xcb_expose_event_t *)event)->count == 0) { + handle_expose(NULL, conn, (xcb_expose_event_t *)event); + } + break; } diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index b9f27a87..eb25e9cb 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -596,7 +596,10 @@ int main(int argc, char *argv[]) { switch (type) { case XCB_EXPOSE: - handle_expose(conn, (xcb_expose_event_t *)event); + if (((xcb_expose_event_t *)event)->count == 0) { + handle_expose(conn, (xcb_expose_event_t *)event); + } + break; case XCB_BUTTON_PRESS: diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index d3bfca69..edef9b7e 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -1149,8 +1149,11 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { handle_visibility_notify((xcb_visibility_notify_event_t *)event); break; case XCB_EXPOSE: - /* Expose-events happen, when the window needs to be redrawn */ - redraw_bars(); + if (((xcb_expose_event_t *)event)->count == 0) { + /* Expose-events happen, when the window needs to be redrawn */ + redraw_bars(); + } + break; case XCB_BUTTON_PRESS: /* Button press events are mouse buttons clicked on one of our bars */ diff --git a/src/handlers.c b/src/handlers.c index 6d7be465..315688c4 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -1511,7 +1511,10 @@ void handle_event(int type, xcb_generic_event_t *event) { break; case XCB_EXPOSE: - handle_expose_event((xcb_expose_event_t *)event); + if (((xcb_expose_event_t *)event)->count == 0) { + handle_expose_event((xcb_expose_event_t *)event); + } + break; case XCB_MOTION_NOTIFY: diff --git a/src/restore_layout.c b/src/restore_layout.c index d48e5c6e..9edf4b11 100644 --- a/src/restore_layout.c +++ b/src/restore_layout.c @@ -360,7 +360,10 @@ static void configure_notify(xcb_configure_notify_event_t *event) { static void restore_handle_event(int type, xcb_generic_event_t *event) { switch (type) { case XCB_EXPOSE: - expose_event((xcb_expose_event_t *)event); + if (((xcb_expose_event_t *)event)->count == 0) { + expose_event((xcb_expose_event_t *)event); + } + break; case XCB_CONFIGURE_NOTIFY: configure_notify((xcb_configure_notify_event_t *)event); From 7f84f498463d908108de05297fa0b4740909c696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 13 Jan 2017 19:01:36 +0100 Subject: [PATCH 040/180] Don't exit() on redefined binding mode. (#2638) Doing a hard exit() is a rather harsh action for something i3 can handle perfectly fine and is only meant to be a check to make debugging easier for users in certain situations. --- src/config_directives.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/config_directives.c b/src/config_directives.c index 82e1a346..879d225e 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -124,14 +124,13 @@ CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *ke CFGFUN(enter_mode, const char *pango_markup, const char *modename) { if (strcasecmp(modename, DEFAULT_BINDING_MODE) == 0) { ELOG("You cannot use the name %s for your mode\n", DEFAULT_BINDING_MODE); - exit(1); + return; } struct Mode *mode; SLIST_FOREACH(mode, &modes, modes) { if (strcmp(mode->name, modename) == 0) { ELOG("The binding mode with name \"%s\" is defined at least twice.\n", modename); - exit(1); } } From 367811be2d285452bbeecd94bf69bae20ee8221d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Mon, 16 Jan 2017 23:00:01 +0100 Subject: [PATCH 041/180] Ensure that marks and the title are displayed even if the window title is empty. (#2639) Previously rendering marks and the title were skipped if the title is empty. With marks this is obviously wrong, with the title it is also wrong because title_format might be set. --- src/x.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/x.c b/src/x.c index f3dbc237..d9a70a92 100644 --- a/src/x.c +++ b/src/x.c @@ -572,9 +572,6 @@ void x_draw_decoration(Con *con) { goto after_title; } - if (win->name == NULL) - goto copy_pixmaps; - int mark_width = 0; if (config.show_marks && !TAILQ_EMPTY(&(con->marks_head))) { char *formatted_mark = sstrdup(""); @@ -608,13 +605,19 @@ void x_draw_decoration(Con *con) { } i3String *title = con->title_format == NULL ? win->name : con_parse_title_format(con); + if (title == NULL) { + goto copy_pixmaps; + } + draw_util_text(title, &(parent->frame_buffer), p->color->text, p->color->background, con->deco_rect.x + logical_px(2), con->deco_rect.y + text_offset_y, con->deco_rect.width - mark_width - 2 * logical_px(2)); - if (con->title_format != NULL) + + if (con->title_format != NULL) { I3STRING_FREE(title); + } after_title: x_draw_decoration_after_title(con, p); From f356439a8d5bf96d1226e478d99c1561b94bd76c Mon Sep 17 00:00:00 2001 From: fred777 Date: Sat, 21 Jan 2017 13:21:32 +0100 Subject: [PATCH 042/180] Update userguide (#2647) key identifier Esc is invalid, use Escape instead --- docs/userguide | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/userguide b/docs/userguide index 6dc2241b..d15aed73 100644 --- a/docs/userguide +++ b/docs/userguide @@ -479,7 +479,7 @@ mode *Example*: ------------------------------------------------------------------------ -# Press $mod+o followed by either f, t, Esc or Return to launch firefox, +# Press $mod+o followed by either f, t, Escape or Return to launch firefox, # thunderbird or return to the default mode, respectively. set $mode_launcher Launch: [f]irefox [t]hunderbird bindsym $mod+o mode "$mode_launcher" @@ -488,7 +488,7 @@ mode "$mode_launcher" { bindsym f exec firefox bindsym t exec thunderbird - bindsym Esc mode "default" + bindsym Escape mode "default" bindsym Return mode "default" } ------------------------------------------------------------------------ From 8edb4a1f0cbda0127996d5ee85a98e5d1c416515 Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Sat, 21 Jan 2017 17:25:21 +0200 Subject: [PATCH 043/180] migrate i3-nagbar to draw_util (#2644) --- i3-nagbar/main.c | 169 +++++++++++++++++------------------------------ 1 file changed, 61 insertions(+), 108 deletions(-) diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index eb25e9cb..7d38f731 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -38,6 +38,13 @@ * constant for that. */ #define XCB_CURSOR_LEFT_PTR 68 +#define MSG_PADDING logical_px(8) +#define BTN_PADDING logical_px(3) +#define BTN_BORDER logical_px(3) +#define BTN_GAP logical_px(20) +#define CLOSE_BTN_GAP logical_px(15) +#define BAR_BORDER logical_px(2) + static char *argv0 = NULL; typedef struct { @@ -48,11 +55,12 @@ typedef struct { } button_t; static xcb_window_t win; -static xcb_pixmap_t pixmap; -static xcb_gcontext_t pixmap_gc; -static xcb_rectangle_t rect = {0, 0, 600, 20}; +static surface_t bar; + static i3Font font; static i3String *prompt; + +static button_t btn_close; static button_t *buttons; static int buttoncnt; @@ -138,7 +146,7 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve printf("button released on x = %d, y = %d\n", event->event_x, event->event_y); /* If the user hits the close button, we exit(0) */ - if (event->event_x >= (rect.width - logical_px(32))) + if (event->event_x >= btn_close.x && event->event_x < btn_close.x + btn_close.width) exit(0); button_t *button = get_button_at(event->event_x, event->event_y); if (!button) @@ -190,108 +198,64 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve /* TODO: unset flag, re-render */ } +/* + * Draws a button and returns its width + * + */ +static int button_draw(button_t *button, int position) { + int text_width = predict_text_width(button->label); + button->width = text_width + 2 * BTN_PADDING + 2 * BTN_BORDER; + button->x = position - button->width; + + /* draw border */ + draw_util_rectangle(&bar, color_border, + position - button->width, + MSG_PADDING - BTN_PADDING - BTN_BORDER, + button->width, + font.height + 2 * BTN_PADDING + 2 * BTN_BORDER); + /* draw background */ + draw_util_rectangle(&bar, color_button_background, + position - button->width + BTN_BORDER, + MSG_PADDING - BTN_PADDING, + text_width + 2 * BTN_PADDING, + font.height + 2 * BTN_PADDING); + /* draw label */ + draw_util_text(button->label, &bar, color_text, color_button_background, + position - button->width + BTN_BORDER + BTN_PADDING, + MSG_PADDING, + 200); + return button->width; +} + /* * Handles expose events (redraws of the window) and rendering in general. Will * be called from the code with event == NULL or from X with event != NULL. * */ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { - /* re-draw the background */ - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){color_background.colorpixel}); - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &rect); + /* draw background */ + draw_util_clear_surface(&bar, color_background); + /* draw message */ + draw_util_text(prompt, &bar, color_text, color_background, + MSG_PADDING, MSG_PADDING, + bar.width - 2 * MSG_PADDING); - /* restore font color */ - set_font_colors(pixmap_gc, color_text, color_background); - draw_text(prompt, pixmap, pixmap_gc, NULL, - logical_px(4) + logical_px(4), - logical_px(4) + logical_px(4), - rect.width - logical_px(4) - logical_px(4)); + int position = bar.width - (MSG_PADDING - BTN_BORDER - BTN_PADDING); /* render close button */ - const char *close_button_label = "X"; - int line_width = logical_px(4); - /* set width to the width of the label */ - int w = predict_text_width(i3string_from_utf8(close_button_label)); - /* account for left/right padding, which seems to be set to 8px (total) below */ - w += logical_px(8); - int y = rect.width; - uint32_t values[3]; - values[0] = color_button_background.colorpixel; - values[1] = line_width; - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values); - - xcb_rectangle_t close = {y - w - (2 * line_width), 0, w + (2 * line_width), rect.height}; - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close); - - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){color_border.colorpixel}); - xcb_point_t points[] = { - {y - w - (2 * line_width), line_width / 2}, - {y - (line_width / 2), line_width / 2}, - {y - (line_width / 2), (rect.height - (line_width / 2)) - logical_px(2)}, - {y - w - (2 * line_width), (rect.height - (line_width / 2)) - logical_px(2)}, - {y - w - (2 * line_width), line_width / 2}}; - xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points); - - values[0] = 1; - set_font_colors(pixmap_gc, color_text, color_button_background); - /* the x term here seems to set left/right padding */ - draw_text_ascii(close_button_label, pixmap, pixmap_gc, - y - w - line_width + w / 2 - logical_px(4), - logical_px(4) + logical_px(3), - rect.width - y + w + line_width - w / 2 + logical_px(4)); - y -= w; - - y -= logical_px(20); + position -= button_draw(&btn_close, position); + position -= CLOSE_BTN_GAP; /* render custom buttons */ - line_width = 1; - for (int c = 0; c < buttoncnt; c++) { - /* set w to the width of the label */ - w = predict_text_width(buttons[c].label); - /* account for left/right padding, which seems to be set to 12px (total) below */ - w += logical_px(12); - y -= logical_px(30); - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){color_button_background.colorpixel}); - close = (xcb_rectangle_t){y - w - (2 * line_width), logical_px(2), w + (2 * line_width), rect.height - logical_px(6)}; - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close); - - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){color_border.colorpixel}); - buttons[c].x = y - w - (2 * line_width); - buttons[c].width = w; - xcb_point_t points2[] = { - {y - w - (2 * line_width), (line_width / 2) + logical_px(2)}, - {y - (line_width / 2), (line_width / 2) + logical_px(2)}, - {y - (line_width / 2), (rect.height - logical_px(4) - (line_width / 2))}, - {y - w - (2 * line_width), (rect.height - logical_px(4) - (line_width / 2))}, - {y - w - (2 * line_width), (line_width / 2) + logical_px(2)}}; - xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points2); - - values[0] = color_text.colorpixel; - values[1] = color_button_background.colorpixel; - set_font_colors(pixmap_gc, color_text, color_button_background); - /* the x term seems to set left/right padding */ - draw_text(buttons[c].label, pixmap, pixmap_gc, NULL, - y - w - line_width + logical_px(6), - logical_px(4) + logical_px(3), - rect.width - y + w + line_width - logical_px(6)); - - y -= w; + for (int i = 0; i < buttoncnt; i++) { + position -= BTN_GAP; + position -= button_draw(&buttons[i], position); } /* border line at the bottom */ - line_width = logical_px(2); - values[0] = color_border_bottom.colorpixel; - values[1] = line_width; - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values); - xcb_point_t bottom[] = { - {0, rect.height - 0}, - {rect.width, rect.height - 0}}; - xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 2, bottom); + draw_util_rectangle(&bar, color_border_bottom, 0, bar.height - BAR_BORDER, bar.width, BAR_BORDER); - /* Copy the contents of the pixmap to the real window */ - xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, rect.width, rect.height); xcb_flush(conn); - return 1; } @@ -301,7 +265,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) { */ static xcb_rectangle_t get_window_position(void) { /* Default values if we cannot determine the primary output or its CRTC info. */ - xcb_rectangle_t result = (xcb_rectangle_t){50, 50, 500, font.height + logical_px(8) + logical_px(8)}; + xcb_rectangle_t result = (xcb_rectangle_t){50, 50, 500, font.height + 2 * MSG_PADDING + BAR_BORDER}; xcb_randr_get_screen_resources_current_cookie_t rcookie = xcb_randr_get_screen_resources_current(conn, root); xcb_randr_get_output_primary_cookie_t pcookie = xcb_randr_get_output_primary(conn, root); @@ -438,6 +402,8 @@ int main(int argc, char *argv[]) { } } + btn_close.label = i3string_from_utf8("X"); + int screens; if ((conn = xcb_connect(NULL, &screens)) == NULL || xcb_connection_has_error(conn)) @@ -575,11 +541,8 @@ int main(int argc, char *argv[]) { 12, &strut_partial); - /* Create pixmap */ - pixmap = xcb_generate_id(conn); - pixmap_gc = xcb_generate_id(conn); - xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, 500, font.height + logical_px(8)); - xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0); + /* Initialize the drawable bar */ + draw_util_surface_init(conn, &bar, win, get_visualtype(root_screen), win_pos.width, win_pos.height); /* Grab the keyboard to get all input */ xcb_flush(conn); @@ -612,18 +575,7 @@ int main(int argc, char *argv[]) { case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t *configure_notify = (xcb_configure_notify_event_t *)event; - rect = (xcb_rectangle_t){ - configure_notify->x, - configure_notify->y, - configure_notify->width, - configure_notify->height}; - - /* Recreate the pixmap / gc */ - xcb_free_pixmap(conn, pixmap); - xcb_free_gc(conn, pixmap_gc); - - xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, rect.width, rect.height); - xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0); + draw_util_surface_set_size(&bar, configure_notify->width, configure_notify->height); break; } } @@ -632,6 +584,7 @@ int main(int argc, char *argv[]) { } FREE(pattern); + draw_util_surface_free(conn, &bar); return 0; } From c78afab5f8b4dd7045846e8dd7663ac75335eeb6 Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Sat, 21 Jan 2017 17:30:31 +0200 Subject: [PATCH 044/180] migrate i3-input to draw_util (#2645) --- i3-input/main.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/i3-input/main.c b/i3-input/main.c index 6d1e3378..785a133f 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -33,6 +33,10 @@ #include "i3-input.h" +#define MAX_WIDTH logical_px(500) +#define BORDER logical_px(2) +#define PADDING logical_px(2) + /* IPC format string. %s will be replaced with what the user entered, then * the command will be sent to i3 */ static char *format; @@ -42,8 +46,7 @@ static int sockfd; static xcb_key_symbols_t *symbols; static bool modeswitch_active = false; static xcb_window_t win; -static xcb_pixmap_t pixmap; -static xcb_gcontext_t pixmap_gc; +static surface_t surface; static xcb_char2b_t glyphs_ucs[512]; static char *glyphs_utf8[512]; static int input_position; @@ -109,30 +112,30 @@ static uint8_t *concat_strings(char **glyphs, int max) { static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t *event) { printf("expose!\n"); - /* re-draw the background */ - xcb_rectangle_t border = {0, 0, logical_px(500), font.height + logical_px(8)}, - inner = {logical_px(2), logical_px(2), logical_px(496), font.height + logical_px(8) - logical_px(4)}; - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#FF0000")}); - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border); - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#000000")}); - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &inner); + color_t border_color = draw_util_hex_to_color("#FF0000"); + color_t fg_color = draw_util_hex_to_color("#FFFFFF"); + color_t bg_color = draw_util_hex_to_color("#000000"); - /* restore font color */ - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000")); + int text_offset = BORDER + PADDING; + + /* draw border */ + draw_util_rectangle(&surface, border_color, 0, 0, surface.width, surface.height); + + /* draw background */ + draw_util_rectangle(&surface, bg_color, BORDER, BORDER, surface.width - 2 * BORDER, surface.height - 2 * BORDER); /* draw the prompt … */ if (prompt != NULL) { - draw_text(prompt, pixmap, pixmap_gc, NULL, logical_px(4), logical_px(4), logical_px(492)); + draw_util_text(prompt, &surface, fg_color, bg_color, text_offset, text_offset, MAX_WIDTH - text_offset); } + /* … and the text */ if (input_position > 0) { i3String *input = i3string_from_ucs2(glyphs_ucs, input_position); - draw_text(input, pixmap, pixmap_gc, NULL, prompt_offset + logical_px(4), logical_px(4), logical_px(492)); + draw_util_text(input, &surface, fg_color, bg_color, text_offset + prompt_offset, text_offset, MAX_WIDTH - text_offset); i3string_free(input); } - /* Copy the contents of the pixmap to the real window */ - xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, logical_px(500), font.height + logical_px(8)); xcb_flush(conn); return 1; @@ -287,7 +290,7 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press } static xcb_rectangle_t get_window_position(void) { - xcb_rectangle_t result = (xcb_rectangle_t){logical_px(50), logical_px(50), logical_px(500), font.height + logical_px(8)}; + xcb_rectangle_t result = (xcb_rectangle_t){logical_px(50), logical_px(50), MAX_WIDTH, font.height + 2 * BORDER + 2 * PADDING}; xcb_get_property_reply_t *supporting_wm_reply = NULL; xcb_get_input_focus_reply_t *input_focus = NULL; @@ -448,6 +451,7 @@ int main(int argc, char *argv[]) { symbols = xcb_key_symbols_alloc(conn); + init_dpi(); font = load_font(pattern, true); set_font(&font); @@ -476,11 +480,8 @@ int main(int argc, char *argv[]) { /* Map the window (make it visible) */ xcb_map_window(conn, win); - /* Create pixmap */ - pixmap = xcb_generate_id(conn); - pixmap_gc = xcb_generate_id(conn); - xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, logical_px(500), font.height + logical_px(8)); - xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0); + /* Initialize the drawable surface */ + draw_util_surface_init(conn, &surface, win, get_visualtype(root_screen), win_pos.width, win_pos.height); /* Grab the keyboard to get all input */ xcb_flush(conn); @@ -535,5 +536,6 @@ int main(int argc, char *argv[]) { free(event); } + draw_util_surface_free(conn, &surface); return 0; } From 564945bc14b060bddb6437db6cbb8553f78e2d6a Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Sat, 21 Jan 2017 17:53:09 +0200 Subject: [PATCH 045/180] migrate placeholder windows to draw_util (#2646) --- src/restore_layout.c | 58 +++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/src/restore_layout.c b/src/restore_layout.c index 9edf4b11..d567e971 100644 --- a/src/restore_layout.c +++ b/src/restore_layout.c @@ -15,6 +15,8 @@ #include #endif +#define TEXT_PADDING logical_px(2) + typedef struct placeholder_state { /** The X11 placeholder window. */ xcb_window_t window; @@ -24,10 +26,8 @@ typedef struct placeholder_state { /** Current size of the placeholder window (to detect size changes). */ Rect rect; - /** The pixmap to render on (back buffer). */ - xcb_pixmap_t pixmap; - /** The graphics context for “pixmap”. */ - xcb_gcontext_t gc; + /** The drawable surface */ + surface_t surface; TAILQ_ENTRY(placeholder_state) state; @@ -138,17 +138,15 @@ void restore_connect(void) { } static void update_placeholder_contents(placeholder_state *state) { - xcb_change_gc(restore_conn, state->gc, XCB_GC_FOREGROUND, - (uint32_t[]){config.client.placeholder.background.colorpixel}); - xcb_poly_fill_rectangle(restore_conn, state->pixmap, state->gc, 1, - (xcb_rectangle_t[]){{0, 0, state->rect.width, state->rect.height}}); + const color_t foreground = config.client.placeholder.text; + const color_t background = config.client.placeholder.background; + + draw_util_clear_surface(&(state->surface), background); // TODO: make i3font functions per-connection, at least these two for now…? xcb_flush(restore_conn); xcb_aux_sync(restore_conn); - set_font_colors(state->gc, config.client.placeholder.text, config.client.placeholder.background); - Match *swallows; int n = 0; TAILQ_FOREACH(swallows, &(state->con->swallow_head), matches) { @@ -175,7 +173,10 @@ static void update_placeholder_contents(placeholder_state *state) { DLOG("con %p (placeholder 0x%08x) line %d: %s\n", state->con, state->window, n, serialized); i3String *str = i3string_from_utf8(serialized); - draw_text(str, state->pixmap, state->gc, NULL, 2, (n * (config.font.height + 2)) + 2, state->rect.width - 2); + draw_util_text(str, &(state->surface), foreground, background, + TEXT_PADDING, + (n * (config.font.height + TEXT_PADDING)) + TEXT_PADDING, + state->rect.width - 2 * TEXT_PADDING); i3string_free(str); n++; free(serialized); @@ -186,7 +187,7 @@ static void update_placeholder_contents(placeholder_state *state) { int text_width = predict_text_width(line); int x = (state->rect.width / 2) - (text_width / 2); int y = (state->rect.height / 2) - (config.font.height / 2); - draw_text(line, state->pixmap, state->gc, NULL, x, y, text_width); + draw_util_text(line, &(state->surface), foreground, background, x, y, text_width); i3string_free(line); xcb_flush(conn); xcb_aux_sync(conn); @@ -228,11 +229,8 @@ static void open_placeholder_window(Con *con) { state->window = placeholder; state->con = con; state->rect = con->rect; - state->pixmap = xcb_generate_id(restore_conn); - xcb_create_pixmap(restore_conn, root_depth, state->pixmap, - state->window, state->rect.width, state->rect.height); - state->gc = xcb_generate_id(restore_conn); - xcb_create_gc(restore_conn, state->gc, state->pixmap, XCB_GC_GRAPHICS_EXPOSURES, (uint32_t[]){0}); + + draw_util_surface_init(conn, &(state->surface), placeholder, get_visualtype(root_screen), state->rect.width, state->rect.height); update_placeholder_contents(state); TAILQ_INSERT_TAIL(&state_head, state, state); @@ -286,8 +284,7 @@ bool restore_kill_placeholder(xcb_window_t placeholder) { continue; xcb_destroy_window(restore_conn, state->window); - xcb_free_pixmap(restore_conn, state->pixmap); - xcb_free_gc(restore_conn, state->gc); + draw_util_surface_free(restore_conn, &(state->surface)); TAILQ_REMOVE(&state_head, state, state); free(state); DLOG("placeholder window 0x%08x destroyed.\n", placeholder); @@ -306,14 +303,8 @@ static void expose_event(xcb_expose_event_t *event) { DLOG("refreshing window 0x%08x contents (con %p)\n", state->window, state->con); - /* Since we render to our pixmap on every change anyways, expose events - * only tell us that the X server lost (parts of) the window contents. We - * can handle that by copying the appropriate part from our pixmap to the - * window. */ - xcb_copy_area(restore_conn, state->pixmap, state->window, state->gc, - event->x, event->y, event->x, event->y, - event->width, event->height); - xcb_flush(restore_conn); + update_placeholder_contents(state); + return; } @@ -338,19 +329,10 @@ static void configure_notify(xcb_configure_notify_event_t *event) { state->rect.width = event->width; state->rect.height = event->height; - xcb_free_pixmap(restore_conn, state->pixmap); - xcb_free_gc(restore_conn, state->gc); - - state->pixmap = xcb_generate_id(restore_conn); - xcb_create_pixmap(restore_conn, root_depth, state->pixmap, - state->window, state->rect.width, state->rect.height); - state->gc = xcb_generate_id(restore_conn); - xcb_create_gc(restore_conn, state->gc, state->pixmap, XCB_GC_GRAPHICS_EXPOSURES, (uint32_t[]){0}); + draw_util_surface_set_size(&(state->surface), state->rect.width, state->rect.height); update_placeholder_contents(state); - xcb_copy_area(restore_conn, state->pixmap, state->window, state->gc, - 0, 0, 0, 0, state->rect.width, state->rect.height); - xcb_flush(restore_conn); + return; } From 04dcf42397a7cf0e1284a2c6b16fb40c15af1f3e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 22 Jan 2017 17:08:32 -0500 Subject: [PATCH 046/180] Add the ipc shutdown event (#2652) This event is triggered when the connection to the ipc is about to shutdown because of a user action such as with a `restart` or `exit` command. The `change` field indicates why the ipc is shutting down. It can be either "restart" or "exit". fixes #2318 --- docs/ipc | 16 +++++++ include/i3/ipc.h | 3 ++ include/ipc.h | 13 +++-- src/commands.c | 4 +- src/ipc.c | 32 ++++++++++++- src/util.c | 2 +- testcases/t/264-ipc-shutdown-event.t | 71 ++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 testcases/t/264-ipc-shutdown-event.t diff --git a/docs/ipc b/docs/ipc index fda289a0..5d47bcbd 100644 --- a/docs/ipc +++ b/docs/ipc @@ -671,6 +671,8 @@ barconfig_update (4):: binding (5):: Sent when a configured command binding is triggered with the keyboard or mouse +shutdown (6):: + Sent when the ipc shuts down because of a restart or exit by user command *Example:* -------------------------------------------------------------------- @@ -829,6 +831,20 @@ input_type (string):: } --------------------------- +=== shutdown event + +This event is triggered when the connection to the ipc is about to shutdown +because of a user action such as a +restart+ or +exit+ command. The +change +(string)+ field indicates why the ipc is shutting down. It can be either ++"restart"+ or +"exit"+. + +*Example:* +--------------------------- +{ + "change": "restart" +} +--------------------------- + == See also (existing libraries) [[libraries]] diff --git a/include/i3/ipc.h b/include/i3/ipc.h index 98ac35b0..249cc32e 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -91,3 +91,6 @@ typedef struct i3_ipc_header { /** The binding event will be triggered when bindings run */ #define I3_IPC_EVENT_BINDING (I3_IPC_EVENT_MASK | 5) + +/** The shutdown event will be triggered when the ipc shuts down */ +#define I3_IPC_EVENT_SHUTDOWN (I3_IPC_EVENT_MASK | 6) diff --git a/include/ipc.h b/include/ipc.h index 7ff4704c..7ffbf7a8 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -77,11 +77,18 @@ int ipc_create_socket(const char *filename); void ipc_send_event(const char *event, uint32_t message_type, const char *payload); /** - * Calls shutdown() on each socket and closes it. This function to be called - * when exiting or restarting only! + * Calls to ipc_shutdown() should provide a reason for the shutdown. + */ +typedef enum { + SHUTDOWN_REASON_RESTART, + SHUTDOWN_REASON_EXIT +} shutdown_reason_t; + +/** + * Calls shutdown() on each socket and closes it. * */ -void ipc_shutdown(void); +void ipc_shutdown(shutdown_reason_t reason); void dump_node(yajl_gen gen, Con *con, bool inplace_restart); diff --git a/src/commands.c b/src/commands.c index 2387ddd7..56c07b6a 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1562,7 +1562,7 @@ void cmd_exit(I3_CMD) { #ifdef I3_ASAN_ENABLED __lsan_do_leak_check(); #endif - ipc_shutdown(); + ipc_shutdown(SHUTDOWN_REASON_EXIT); unlink(config.ipc_socket_path); xcb_disconnect(conn); exit(0); @@ -1595,7 +1595,7 @@ void cmd_reload(I3_CMD) { */ void cmd_restart(I3_CMD) { LOG("restarting i3\n"); - ipc_shutdown(); + ipc_shutdown(SHUTDOWN_REASON_RESTART); unlink(config.ipc_socket_path); /* We need to call this manually since atexit handlers don’t get called * when exec()ing */ diff --git a/src/ipc.c b/src/ipc.c index db2fa362..bb20b340 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -62,11 +62,39 @@ void ipc_send_event(const char *event, uint32_t message_type, const char *payloa } /* - * Calls shutdown() on each socket and closes it. This function to be called + * For shutdown events, we send the reason for the shutdown. + */ +static void ipc_send_shutdown_event(shutdown_reason_t reason) { + yajl_gen gen = ygenalloc(); + y(map_open); + + ystr("change"); + + if (reason == SHUTDOWN_REASON_RESTART) { + ystr("restart"); + } else if (reason == SHUTDOWN_REASON_EXIT) { + ystr("exit"); + } + + y(map_close); + + const unsigned char *payload; + ylength length; + + y(get_buf, &payload, &length); + ipc_send_event("shutdown", I3_IPC_EVENT_SHUTDOWN, (const char *)payload); + + y(free); +} + +/* + * Calls shutdown() on each socket and closes it. This function is to be called * when exiting or restarting only! * */ -void ipc_shutdown(void) { +void ipc_shutdown(shutdown_reason_t reason) { + ipc_send_shutdown_event(reason); + ipc_client *current; while (!TAILQ_EMPTY(&all_clients)) { current = TAILQ_FIRST(&all_clients); diff --git a/src/util.c b/src/util.c index cfe4c953..5c8fc774 100644 --- a/src/util.c +++ b/src/util.c @@ -259,7 +259,7 @@ void i3_restart(bool forget_layout) { restore_geometry(); - ipc_shutdown(); + ipc_shutdown(SHUTDOWN_REASON_RESTART); LOG("restarting \"%s\"...\n", start_argv[0]); /* make sure -a is in the argument list or add it */ diff --git a/testcases/t/264-ipc-shutdown-event.t b/testcases/t/264-ipc-shutdown-event.t new file mode 100644 index 00000000..379b9bf2 --- /dev/null +++ b/testcases/t/264-ipc-shutdown-event.t @@ -0,0 +1,71 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Test the ipc shutdown event. This event is triggered when the connection to +# the ipc is about to shutdown because of a user action such as with a +# `restart` or `exit` command. The `change` field indicates why the ipc is +# shutting down. It can be either "restart" or "exit". +# +# Ticket: #2318 +# Bug still in: 4.12-46-g2123888 +use i3test; + +SKIP: { + skip "AnyEvent::I3 too old (need >= 0.17)", 1 if $AnyEvent::I3::VERSION < 0.17; + +my $i3 = i3(get_socket_path()); +$i3->connect->recv; + +my $cv = AE::cv; +my $timer = AE::timer 0.5, 0, sub { $cv->send(0); }; + +$i3->subscribe({ + shutdown => sub { + $cv->send(shift); + } + })->recv; + +cmd 'restart'; + +my $e = $cv->recv; + +diag "Event:\n", Dumper($e); +ok($e, 'the shutdown event should emit when the ipc is restarted by command'); +is($e->{change}, 'restart', 'the `change` field should tell the reason for the shutdown'); + +# restarting kills the ipc client so we have to make a new one +$i3 = i3(get_socket_path()); +$i3->connect->recv; + +$cv = AE::cv; +$timer = AE::timer 0.5, 0, sub { $cv->send(0); }; + +$i3->subscribe({ + shutdown => sub { + $cv->send(shift); + } + })->recv; + +cmd 'exit'; + +$e = $cv->recv; + +diag "Event:\n", Dumper($e); +ok($e, 'the shutdown event should emit when the ipc is exited by command'); +is($e->{change}, 'exit', 'the `change` field should tell the reason for the shutdown'); +} + +done_testing; From a55733f719c146438d9665445bfcadec9f69c1e2 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 23 Jan 2017 02:40:08 -0500 Subject: [PATCH 047/180] Testcases: Check for required binaries (#2655) Fail fast in case test binaries are not built and provide instructions on how to build them. --- testcases/complete-run.pl.in | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/testcases/complete-run.pl.in b/testcases/complete-run.pl.in index d872bda1..2019253c 100755 --- a/testcases/complete-run.pl.in +++ b/testcases/complete-run.pl.in @@ -87,6 +87,17 @@ foreach my $binary (@binaries) { die "$binary is not an executable" unless -x $binary; } +my @test_binaries = qw( + @abs_top_builddir@/test.commands_parser + @abs_top_builddir@/test.config_parser + @abs_top_builddir@/test.inject_randr15 + ); + +foreach my $binary (@test_binaries) { + die "$binary executable not found, did you run “make check”?" unless -e $binary; + die "$binary is not an executable" unless -x $binary; +} + $ENV{PATH} = join(':', '@abs_top_builddir@/i3-nagbar', '@abs_top_builddir@/i3-msg', From 348d0d4622857caa6539f5a259e6cfca183dfe0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4nel?= Date: Tue, 24 Jan 2017 17:40:32 +0100 Subject: [PATCH 048/180] Added missing cases for workspace event (#2656) The possible values "rename", "reload" and "restored" of the property 'change' from the workspace event were missing. Because no events of those types contain an old workspace, this was trivial. --- docs/ipc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ipc b/docs/ipc index 5d47bcbd..466b6596 100644 --- a/docs/ipc +++ b/docs/ipc @@ -696,9 +696,9 @@ if ($is_event) { This event consists of a single serialized map containing a property +change (string)+ which indicates the type of the change ("focus", "init", -"empty", "urgent"). A +current (object)+ property will be present with the -affected workspace whenever the type of event affects a workspace (otherwise, -it will be +null). +"empty", "urgent", "reload", "rename", "restored"). A +current (object)+ +property will be present with the affected workspace whenever the type of event +affects a workspace (otherwise, it will be +null). When the change is "focus", an +old (object)+ property will be present with the previous workspace. When the first switch occurs (when i3 focuses the From fa488d721dfd1e1abe849faadc12b1f9ec93ac76 Mon Sep 17 00:00:00 2001 From: mihaicmn Date: Wed, 25 Jan 2017 09:18:13 +0200 Subject: [PATCH 049/180] migrate i3-config-wizard to draw_util (#2654) --- i3-config-wizard/main.c | 113 +++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index 8eec941c..dd58fd12 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -69,10 +69,16 @@ #include "xcb.h" #include "libi3.h" +#define TEXT_PADDING logical_px(4) +#define WIN_POS_X logical_px(490) +#define WIN_POS_Y logical_px(297) +#define WIN_WIDTH logical_px(300) +#define WIN_HEIGHT (15 * font.height + TEXT_PADDING) + +#define col_x(col) \ + (((col)-1) * char_width + TEXT_PADDING) #define row_y(row) \ - (((row)-1) * font.height + logical_px(4)) -#define window_height() \ - (row_y(15) + font.height) + (((row)-1) * font.height + TEXT_PADDING) enum { STEP_WELCOME, STEP_GENERATE } current_step = STEP_WELCOME; @@ -90,8 +96,7 @@ static i3Font bold_font; static int char_width; static char *socket_path; static xcb_window_t win; -static xcb_pixmap_t pixmap; -static xcb_gcontext_t pixmap_gc; +static surface_t surface; static xcb_key_symbols_t *symbols; xcb_window_t root; static struct xkb_keymap *xkb_keymap; @@ -463,82 +468,73 @@ void errorlog(char *fmt, ...) { void debuglog(char *fmt, ...) { } +static void txt(int col, int row, char *text, color_t fg, color_t bg) { + int x = col_x(col); + int y = row_y(row); + i3String *string = i3string_from_utf8(text); + draw_util_text(string, &surface, fg, bg, x, y, WIN_WIDTH - x - TEXT_PADDING); + i3string_free(string); +} + /* * Handles expose events, that is, draws the window contents. * */ static int handle_expose() { - /* re-draw the background */ - xcb_rectangle_t border = {0, 0, logical_px(300), window_height()}; - xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){get_colorpixel("#000000")}); - xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border); + const color_t black = draw_util_hex_to_color("#000000"); + const color_t white = draw_util_hex_to_color("#FFFFFF"); + const color_t green = draw_util_hex_to_color("#00FF00"); + const color_t red = draw_util_hex_to_color("#FF0000"); + + /* draw background */ + draw_util_clear_surface(&surface, black); set_font(&font); -#define txt(x, row, text) \ - draw_text_ascii(text, pixmap, pixmap_gc, \ - x, row_y(row), logical_px(500) - x * 2) - if (current_step == STEP_WELCOME) { - /* restore font color */ - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000")); - - txt(logical_px(10), 2, "You have not configured i3 yet."); - txt(logical_px(10), 3, "Do you want me to generate a config at"); + txt(2, 2, "You have not configured i3 yet.", white, black); + txt(2, 3, "Do you want me to generate a config at", white, black); char *msg; sasprintf(&msg, "%s?", config_path); - txt(logical_px(10), 4, msg); + txt(2, 4, msg, white, black); free(msg); - txt(logical_px(85), 6, "Yes, generate the config"); - txt(logical_px(85), 8, "No, I will use the defaults"); + txt(13, 6, "Yes, generate the config", white, black); + txt(13, 8, "No, I will use the defaults", white, black); - /* green */ - set_font_colors(pixmap_gc, draw_util_hex_to_color("#00FF00"), draw_util_hex_to_color("#000000")); - txt(logical_px(25), 6, ""); + txt(4, 6, "", green, black); - /* red */ - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FF0000"), draw_util_hex_to_color("#000000")); - txt(logical_px(31), 8, ""); + txt(5, 8, "", red, black); } if (current_step == STEP_GENERATE) { - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000")); - - txt(logical_px(10), 2, "Please choose either:"); - txt(logical_px(85), 4, "Win as default modifier"); - txt(logical_px(85), 5, "Alt as default modifier"); - txt(logical_px(10), 7, "Afterwards, press"); - txt(logical_px(85), 9, "to write the config"); - txt(logical_px(85), 10, "to abort"); + txt(2, 2, "Please choose either:", white, black); + txt(13, 4, "Win as default modifier", white, black); + txt(13, 5, "Alt as default modifier", white, black); + txt(2, 7, "Afterwards, press", white, black); + txt(13, 9, "to write the config", white, black); + txt(13, 10, "to abort", white, black); /* the not-selected modifier */ if (modifier == MOD_Mod4) - txt(logical_px(31), 5, ""); + txt(5, 5, "", white, black); else - txt(logical_px(31), 4, ""); + txt(5, 4, "", white, black); /* the selected modifier */ set_font(&bold_font); - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FFFFFF"), draw_util_hex_to_color("#000000")); if (modifier == MOD_Mod4) - txt(logical_px(10), 4, "-> "); + txt(2, 4, "-> ", white, black); else - txt(logical_px(10), 5, "-> "); + txt(2, 5, "-> ", white, black); - /* green */ set_font(&font); - set_font_colors(pixmap_gc, draw_util_hex_to_color("#00FF00"), draw_util_hex_to_color("#000000")); - txt(logical_px(25), 9, ""); + txt(4, 9, "", green, black); - /* red */ - set_font_colors(pixmap_gc, draw_util_hex_to_color("#FF0000"), draw_util_hex_to_color("#000000")); - txt(logical_px(31), 10, ""); + txt(5, 10, "", red, black); } - /* Copy the contents of the pixmap to the real window */ - xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, logical_px(500), logical_px(500)); xcb_flush(conn); return 1; @@ -625,8 +621,7 @@ static void handle_button_press(xcb_button_press_event_t *event) { if (current_step != STEP_GENERATE) return; - if (event->event_x < logical_px(32) || - event->event_x > (logical_px(32) + char_width * 5)) + if (event->event_x < col_x(5) || event->event_x > col_x(10)) return; if (event->event_y >= row_y(4) && event->event_y <= (row_y(4) + font.height)) { @@ -867,10 +862,10 @@ int main(int argc, char *argv[]) { xcb_create_window( conn, XCB_COPY_FROM_PARENT, - win, /* the window id */ - root, /* parent == root */ - logical_px(490), logical_px(297), logical_px(300), window_height(), /* dimensions */ - 0, /* X11 border = 0, we draw our own */ + win, /* the window id */ + root, /* parent == root */ + WIN_POS_X, WIN_POS_Y, WIN_WIDTH, WIN_HEIGHT, /* dimensions */ + 0, /* X11 border = 0, we draw our own */ XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, @@ -915,11 +910,8 @@ int main(int argc, char *argv[]) { strlen("i3: first configuration"), "i3: first configuration"); - /* Create pixmap */ - pixmap = xcb_generate_id(conn); - pixmap_gc = xcb_generate_id(conn); - xcb_create_pixmap(conn, root_screen->root_depth, pixmap, win, logical_px(500), logical_px(500)); - xcb_create_gc(conn, pixmap_gc, pixmap, 0, 0); + /* Initialize drawable surface */ + draw_util_surface_init(conn, &surface, win, get_visualtype(root_screen), WIN_WIDTH, WIN_HEIGHT); /* Grab the keyboard to get all input */ xcb_flush(conn); @@ -976,5 +968,8 @@ int main(int argc, char *argv[]) { free(event); } + /* Dismiss drawable surface */ + draw_util_surface_free(conn, &surface); + return 0; } From 98f202dd1b2782d11a713513f5dcca2f52daab73 Mon Sep 17 00:00:00 2001 From: Johannes Lange Date: Sun, 5 Feb 2017 10:04:35 +0100 Subject: [PATCH 050/180] restart bar status command on config reload (#2668) Closes #2651 --- i3bar/src/ipc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 4a090ad7..cc5074e5 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -178,6 +178,11 @@ void got_bar_config_update(char *event) { init_xcb_late(config.fontname); init_colors(&(config.colors)); + /* restart status command process */ + kill_child(); + start_child(config.command); + FREE(config.command); + draw_bars(false); } From 492da1c062d7758e162f0edb5262b47b55b48d89 Mon Sep 17 00:00:00 2001 From: Manuel Mendez Date: Sun, 5 Feb 2017 04:07:21 -0500 Subject: [PATCH 051/180] docs: focus_follow_mouse only happens at window border crossings (#2669) see #2666 --- docs/userguide | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/userguide b/docs/userguide index d15aed73..584edc80 100644 --- a/docs/userguide +++ b/docs/userguide @@ -946,12 +946,12 @@ the next section. === Focus follows mouse -By default, window focus follows your mouse movements. However, if you have a -setup where your mouse usually is in your way (like a touchpad on your laptop -which you do not want to disable completely), you might want to disable 'focus -follows mouse' and control focus only by using your keyboard. The mouse will -still be useful inside the currently active window (for example to click on -links in your browser window). +By default, window focus follows your mouse movements as the mouse crosses +window borders. However, if you have a setup where your mouse usually is in your +way (like a touchpad on your laptop which you do not want to disable +completely), you might want to disable 'focus follows mouse' and control focus +only by using your keyboard. The mouse will still be useful inside the +currently active window (for example to click on links in your browser window). *Syntax*: -------------------------- From 55692c166795142419ffc2ce57cbdc0a84a61be7 Mon Sep 17 00:00:00 2001 From: Stefan Hagen Date: Sun, 5 Feb 2017 18:57:44 +0100 Subject: [PATCH 052/180] Explaing the workspace number "1: www" behavior (#2674) The documentation did not explain how workspace number `"1: www"` is working. Related to #2663 Rephrase to cover the creation case --- docs/userguide | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/userguide b/docs/userguide index 584edc80..69eeda35 100644 --- a/docs/userguide +++ b/docs/userguide @@ -2090,6 +2090,23 @@ i3-msg 'rename workspace to "2: mail"' bindsym $mod+r exec i3-input -F 'rename workspace to "%s"' -P 'New name: ' -------------------------------------------------------------------------- +If you want to rename workspaces on demand while keeping the navigation stable, +you can use a setup like this: + +*Example*: +------------------------- +bindsym $mod+1 workspace number "1: www" +bindsym $mod+2 workspace number "2: mail" +... +------------------------- + +If a workspace does not exist, the command +workspace number "1: mail"+ will +create workspace "1: mail". + +If a workspace with number 1 does already exist, the command will switch to this +workspace and ignore the text part. So even when the workspace has been renamed +to "1: web", the above command will still switch to it. + === Moving workspaces to a different screen See <> for how to move a container/workspace to a different From 297e6be5bd3c223c307ac4b5951163e35924bdae Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 6 Feb 2017 10:10:41 -0800 Subject: [PATCH 053/180] document our project governance model (#2675) --- .github/GOVERNANCE.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/GOVERNANCE.md diff --git a/.github/GOVERNANCE.md b/.github/GOVERNANCE.md new file mode 100644 index 00000000..44e13345 --- /dev/null +++ b/.github/GOVERNANCE.md @@ -0,0 +1,30 @@ +# i3 project governance + +## Overview + +The i3 project uses a governance model commonly described as Benevolent +Dictator For Life (BDFL). This document outlines our understanding of what this +means. + +## Roles + +* user: anyone who interacts with the i3 project +* core contributor: a handful of people who have contributed significantly to + the project by any means (issue triage, support, documentation, code, etc.). + Core contributors are recognizable via GitHub’s “Member” badge. +* BDFL: a single individual who makes decisions when consensus cannot be + reached. i3’s current BDFL is [@stapelberg](https://github.com/stapelberg). + +## Decision making process + +In general, we try to reach consensus in discussions. In case consensus cannot +be reached, the BDFL makes a decision. + +For feature requests and code contributions specifically, the values with which +we consider them can be found on the bottom of https://i3wm.org/. These values +are not set in stone and are to be treated as guiding principles, not absolute +rules that must be followed in every case. + +## Contribution process + +Please see [CONTRIBUTING](CONTRIBUTING.md). From ad9c879cbd5a9cc7f41484ea4651cf02c17335f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 12 Feb 2017 20:24:35 +0100 Subject: [PATCH 054/180] Add troubleshooting for title attributes during layout restoring. (#2679) --- docs/layout-saving | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/layout-saving b/docs/layout-saving index 5897036e..6ca08fa2 100644 --- a/docs/layout-saving +++ b/docs/layout-saving @@ -259,3 +259,27 @@ container: ] } -------------------------------------------------------------------------------- + +=== Placeholders using window title matches don't swallow the window + +If you use the +title+ attribute to match a window and find that it doesn't +work or only works sometimes, the reason might be that the application sets the +title only after making the window visible. This will be especially true for +programs running inside terminal emulators, e.g., +urxvt -e irssi+ when +matching on +title: "irssi"+. + +One way to deal with this is to not rely on the title, but instead use, e.g., +the +instance+ attribute and running the program to set this window instance to +that value: + +-------------------------------------------------------------------------------- +# Run irssi via +# urxvt -name "irssi-container" -e irssi + +"swallows": [ + { + "class": "URxvt", + "instance": "irssi-container" + } +] +-------------------------------------------------------------------------------- From 7732971ad86433cc232e5d951564acff448e08a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=83=C2=83=C3=82=C2=BCrk?= Date: Sun, 12 Feb 2017 20:36:42 +0100 Subject: [PATCH 055/180] Introduce named aliases for mouse buttons. This increases readability and allows us to cover up the fact that XCB doesn't define constants for left/right scrolling. --- i3bar/src/xcb.c | 4 ++-- include/libi3.h | 11 +++++++++++ src/click.c | 22 +++++++++++----------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index edef9b7e..0b9d6f81 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -531,7 +531,7 @@ void handle_button(xcb_button_press_event_t *event) { return; } switch (event->detail) { - case 4: + case XCB_BUTTON_SCROLL_UP: /* Mouse wheel up. We select the previous ws, if any. * If there is no more workspace, don’t even send the workspace * command, otherwise (with workspace auto_back_and_forth) we’d end @@ -541,7 +541,7 @@ void handle_button(xcb_button_press_event_t *event) { cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); break; - case 5: + case XCB_BUTTON_SCROLL_DOWN: /* Mouse wheel down. We select the next ws, if any. * If there is no more workspace, don’t even send the workspace * command, otherwise (with workspace auto_back_and_forth) we’d end diff --git a/include/libi3.h b/include/libi3.h index d33d6c71..67094534 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -24,6 +24,17 @@ #define DEFAULT_DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +/** Mouse buttons */ +#define XCB_BUTTON_CLICK_LEFT XCB_BUTTON_INDEX_1 +#define XCB_BUTTON_CLICK_MIDDLE XCB_BUTTON_INDEX_2 +#define XCB_BUTTON_CLICK_RIGHT XCB_BUTTON_INDEX_3 +#define XCB_BUTTON_SCROLL_UP XCB_BUTTON_INDEX_4 +#define XCB_BUTTON_SCROLL_DOWN XCB_BUTTON_INDEX_5 +/* xcb doesn't define constants for these. */ +#define XCB_BUTTON_SCROLL_LEFT 6 +#define XCB_BUTTON_SCROLL_RIGHT 7 + + /** * XCB connection and root screen * diff --git a/src/click.c b/src/click.c index 913741b4..5717b9b0 100644 --- a/src/click.c +++ b/src/click.c @@ -178,8 +178,8 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod if (con->parent->type == CT_DOCKAREA) goto done; - const bool is_left_or_right_click = (event->detail == XCB_BUTTON_INDEX_1 || - event->detail == XCB_BUTTON_INDEX_3); + const bool is_left_or_right_click = (event->detail == XCB_BUTTON_CLICK_LEFT || + event->detail == XCB_BUTTON_CLICK_RIGHT); /* if the user has bound an action to this click, it should override the * default behavior. */ @@ -228,8 +228,8 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod /* 1: see if the user scrolled on the decoration of a stacked/tabbed con */ if (in_stacked && dest == CLICK_DECORATION && - (event->detail == XCB_BUTTON_INDEX_4 || - event->detail == XCB_BUTTON_INDEX_5)) { + (event->detail == XCB_BUTTON_SCROLL_UP || + event->detail == XCB_BUTTON_SCROLL_DOWN)) { DLOG("Scrolling on a window decoration\n"); orientation_t orientation = (con->parent->layout == L_STACKED ? VERT : HORIZ); /* Focus the currently focused container on the same level that the @@ -244,9 +244,9 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod * #557), we first check if scrolling is possible at all. */ bool scroll_prev_possible = (TAILQ_PREV(focused, nodes_head, nodes) != NULL); bool scroll_next_possible = (TAILQ_NEXT(focused, nodes) != NULL); - if (event->detail == XCB_BUTTON_INDEX_4 && scroll_prev_possible) + if (event->detail == XCB_BUTTON_SCROLL_UP && scroll_prev_possible) tree_next('p', orientation); - else if (event->detail == XCB_BUTTON_INDEX_5 && scroll_next_possible) + else if (event->detail == XCB_BUTTON_SCROLL_DOWN && scroll_next_possible) tree_next('n', orientation); goto done; } @@ -261,7 +261,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod floating_raise_con(floatingcon); /* 4: floating_modifier plus left mouse button drags */ - if (mod_pressed && event->detail == XCB_BUTTON_INDEX_1) { + if (mod_pressed && event->detail == XCB_BUTTON_CLICK_LEFT) { floating_drag_window(floatingcon, event); return 1; } @@ -269,7 +269,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod /* 5: resize (floating) if this was a (left or right) click on the * left/right/bottom border, or a right click on the decoration. * also try resizing (tiling) if it was a click on the top */ - if (mod_pressed && event->detail == XCB_BUTTON_INDEX_3) { + if (mod_pressed && event->detail == XCB_BUTTON_CLICK_RIGHT) { DLOG("floating resize due to floatingmodifier\n"); floating_resize_window(floatingcon, proportional, event); return 1; @@ -283,7 +283,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod goto done; } - if (dest == CLICK_DECORATION && event->detail == XCB_BUTTON_INDEX_3) { + if (dest == CLICK_DECORATION && event->detail == XCB_BUTTON_CLICK_RIGHT) { DLOG("floating resize due to decoration right click\n"); floating_resize_window(floatingcon, proportional, event); return 1; @@ -298,7 +298,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod /* 6: dragging, if this was a click on a decoration (which did not lead * to a resize) */ if (!in_stacked && dest == CLICK_DECORATION && - (event->detail == XCB_BUTTON_INDEX_1)) { + (event->detail == XCB_BUTTON_CLICK_LEFT)) { floating_drag_window(floatingcon, event); return 1; } @@ -313,7 +313,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod } /* 7: floating modifier pressed, initiate a resize */ - if (dest == CLICK_INSIDE && mod_pressed && event->detail == XCB_BUTTON_INDEX_3) { + if (dest == CLICK_INSIDE && mod_pressed && event->detail == XCB_BUTTON_CLICK_RIGHT) { if (floating_mod_on_tiled_client(con, event)) return 1; } From 432c4211ea422608645ecb8ef02ac88687adeced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 12 Feb 2017 20:48:44 +0100 Subject: [PATCH 056/180] Allow using left/right scrolling like up/down scrolling. This commit makes left/right scrolling synonyms for up/down scrolling for * scrolling on window decoration * scrolling on i3bar workspaces fixes #2677 --- i3bar/src/xcb.c | 2 ++ include/libi3.h | 1 - src/click.c | 10 +++++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 0b9d6f81..24f91642 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -532,6 +532,7 @@ void handle_button(xcb_button_press_event_t *event) { } switch (event->detail) { case XCB_BUTTON_SCROLL_UP: + case XCB_BUTTON_SCROLL_LEFT: /* Mouse wheel up. We select the previous ws, if any. * If there is no more workspace, don’t even send the workspace * command, otherwise (with workspace auto_back_and_forth) we’d end @@ -542,6 +543,7 @@ void handle_button(xcb_button_press_event_t *event) { cur_ws = TAILQ_PREV(cur_ws, ws_head, tailq); break; case XCB_BUTTON_SCROLL_DOWN: + case XCB_BUTTON_SCROLL_RIGHT: /* Mouse wheel down. We select the next ws, if any. * If there is no more workspace, don’t even send the workspace * command, otherwise (with workspace auto_back_and_forth) we’d end diff --git a/include/libi3.h b/include/libi3.h index 67094534..dbb29e1f 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -34,7 +34,6 @@ #define XCB_BUTTON_SCROLL_LEFT 6 #define XCB_BUTTON_SCROLL_RIGHT 7 - /** * XCB connection and root screen * diff --git a/src/click.c b/src/click.c index 5717b9b0..e989b88d 100644 --- a/src/click.c +++ b/src/click.c @@ -229,7 +229,9 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod if (in_stacked && dest == CLICK_DECORATION && (event->detail == XCB_BUTTON_SCROLL_UP || - event->detail == XCB_BUTTON_SCROLL_DOWN)) { + event->detail == XCB_BUTTON_SCROLL_DOWN || + event->detail == XCB_BUTTON_SCROLL_LEFT || + event->detail == XCB_BUTTON_SCROLL_RIGHT)) { DLOG("Scrolling on a window decoration\n"); orientation_t orientation = (con->parent->layout == L_STACKED ? VERT : HORIZ); /* Focus the currently focused container on the same level that the @@ -244,10 +246,12 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod * #557), we first check if scrolling is possible at all. */ bool scroll_prev_possible = (TAILQ_PREV(focused, nodes_head, nodes) != NULL); bool scroll_next_possible = (TAILQ_NEXT(focused, nodes) != NULL); - if (event->detail == XCB_BUTTON_SCROLL_UP && scroll_prev_possible) + if ((event->detail == XCB_BUTTON_SCROLL_UP || event->detail == XCB_BUTTON_SCROLL_LEFT) && scroll_prev_possible) { tree_next('p', orientation); - else if (event->detail == XCB_BUTTON_SCROLL_DOWN && scroll_next_possible) + } else if ((event->detail == XCB_BUTTON_SCROLL_DOWN || event->detail == XCB_BUTTON_SCROLL_RIGHT) && scroll_next_possible) { tree_next('n', orientation); + } + goto done; } From 8158e4c4155e15ea9442acd960a194376400788b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 17 Feb 2017 09:06:40 +0100 Subject: [PATCH 057/180] Copy the entire window content on Expose events. (#2685) With commit d58dbc3 we started ignoring Expose events in a sequence except for the last one. Since we only copied the affected part of the window in the Expose event handler, this caused incorrectly rendered window decorations. Instead of reverting to the old behavior, we now copy the entire window content on this single, last event with the following rationale: - It's cheaper to copy a larger chunk once than multiple smaller chunks doing one server roundtrip each. - That's how we do it when rendering out decoration on decoration changes as well. fixes #2683 --- src/handlers.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/handlers.c b/src/handlers.c index 315688c4..9fb9040e 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -614,12 +614,9 @@ static void handle_expose_event(xcb_expose_event_t *event) { } /* Since we render to our surface on every change anyways, expose events - * only tell us that the X server lost (parts of) the window contents. We - * can handle that by copying the appropriate part from our surface to the - * window. */ + * only tell us that the X server lost (parts of) the window contents. */ draw_util_copy_surface(&(parent->frame_buffer), &(parent->frame), - event->x, event->y, event->x, event->y, - event->width, event->height); + 0, 0, 0, 0, parent->rect.width, parent->rect.height); xcb_flush(conn); return; } From 3410cb256d3b033c2ca61c78766eb58652dce49f Mon Sep 17 00:00:00 2001 From: s3rb31 Date: Tue, 21 Feb 2017 02:12:39 +0100 Subject: [PATCH 058/180] Implement mapping from string to layout as extra function --- include/util.h | 8 ++++++++ src/commands.c | 15 +-------------- src/util.c | 25 +++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/util.h b/include/util.h index e5ba3341..cbe9778c 100644 --- a/include/util.h +++ b/include/util.h @@ -69,6 +69,14 @@ Rect rect_sub(Rect a, Rect b); */ __attribute__((pure)) bool name_is_digits(const char *name); +/** + * Set 'out' to the layout_t value for the given layout. The function + * returns true on success or false if the passed string is not a valid + * layout name. + * + */ +bool layout_from_name(const char *layout_str, layout_t *out); + /** * Parses the workspace name as a number. Returns -1 if the workspace should be * interpreted as a "named workspace". diff --git a/src/commands.c b/src/commands.c index 2387ddd7..44a5d8a4 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1489,21 +1489,8 @@ void cmd_move_direction(I3_CMD, const char *direction, long move_px) { void cmd_layout(I3_CMD, const char *layout_str) { HANDLE_EMPTY_MATCH; - if (strcmp(layout_str, "stacking") == 0) - layout_str = "stacked"; layout_t layout; - /* default is a special case which will be handled in con_set_layout(). */ - if (strcmp(layout_str, "default") == 0) - layout = L_DEFAULT; - else if (strcmp(layout_str, "stacked") == 0) - layout = L_STACKED; - else if (strcmp(layout_str, "tabbed") == 0) - layout = L_TABBED; - else if (strcmp(layout_str, "splitv") == 0) - layout = L_SPLITV; - else if (strcmp(layout_str, "splith") == 0) - layout = L_SPLITH; - else { + if (!layout_from_name(layout_str, &layout)) { ELOG("Unknown layout \"%s\", this is a mismatch between code and parser spec.\n", layout_str); return; } diff --git a/src/util.c b/src/util.c index cfe4c953..b6f45fde 100644 --- a/src/util.c +++ b/src/util.c @@ -66,6 +66,31 @@ __attribute__((pure)) bool name_is_digits(const char *name) { return true; } +/** + * Set 'out' to the layout_t value for the given layout. The function + * returns true on success or false if the passed string is not a valid + * layout name. + * + */ +bool layout_from_name(const char *layout_str, layout_t *out) { + if (strcmp(layout_str, "default") == 0) { + *out = L_DEFAULT; + } else if (strcasecmp(layout_str, "stacked") == 0 || + strcasecmp(layout_str, "stacking") == 0) { + *out = L_STACKED; + } else if (strcasecmp(layout_str, "tabbed") == 0) { + *out = L_TABBED; + } else if (strcasecmp(layout_str, "splitv") == 0) { + *out = L_SPLITV; + } else if (strcasecmp(layout_str, "splith") == 0) { + *out = L_SPLITH; + } else { + return false; + } + + return true; +} + /* * Parses the workspace name as a number. Returns -1 if the workspace should be * interpreted as a "named workspace". From 37658bd6d7066489cef38dfbb8797975d2024b2a Mon Sep 17 00:00:00 2001 From: s3rb31 Date: Thu, 19 Jan 2017 20:49:56 +0100 Subject: [PATCH 059/180] layout toggle: take any combination of layouts as arguments (#2649) With this PR the 'layout toggle' command can be passed any combination of valid layout keywords as arguments. They will be activated one after another each time you issue the command, advancing from left to right always selecting the layout after the currently active layout or the leftmost layout if the active layout is not in the argument list. This PR also incorporates the feature request from #2476. --- docs/userguide | 18 +++++++++- parser-specs/commands.spec | 2 +- src/con.c | 64 +++++++++++++++++++++++++++-------- src/util.c | 11 +++--- testcases/t/192-layout.t | 68 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 20 deletions(-) diff --git a/docs/userguide b/docs/userguide index 6dc2241b..21d08625 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1802,7 +1802,8 @@ The +toggle+ option will toggle the orientation of the split container if it contains a single window. Otherwise it makes the current window a split container with opposite orientation compared to the parent container. Use +layout toggle split+ to change the layout of any split container from -splitv to splith or vice-versa. +splitv to splith or vice-versa. You can also define a custom sequence of layouts +to cycle through with +layout toggle+, see <>. *Syntax*: -------------------------------- @@ -1822,6 +1823,11 @@ Use +layout toggle split+, +layout stacking+, +layout tabbed+, +layout splitv+ or +layout splith+ to change the current container layout to splith/splitv, stacking, tabbed layout, splitv or splith, respectively. +Specify up to four layouts after +layout toggle+ to cycle through them. Every +time the command is executed, the layout specified after the currently active +one will be applied. If the currently active layout is not in the list, the +first layout in the list will be activated. + To make the current window (!) fullscreen, use +fullscreen enable+ (or +fullscreen enable global+ for the global mode), to leave either fullscreen mode use +fullscreen disable+, and to toggle between these two states use @@ -1834,6 +1840,7 @@ enable+ respectively +floating disable+ (or +floating toggle+): -------------------------------------------- layout default|tabbed|stacking|splitv|splith layout toggle [split|all] +layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]… -------------------------------------------- *Examples*: @@ -1848,6 +1855,15 @@ bindsym $mod+x layout toggle # Toggle between stacking/tabbed/splith/splitv: bindsym $mod+x layout toggle all +# Toggle between stacking/tabbed/splith: +bindsym $mod+x layout toggle stacking tabbed splith + +# Toggle between splitv/tabbed +bindsym $mod+x layout toggle splitv tabbed + +# Toggle between last split layout/tabbed/stacking +bindsym $mod+x layout toggle split tabbed stacking + # Toggle fullscreen bindsym $mod+f fullscreen toggle diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index d4b3dbc6..542ff798 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -110,7 +110,7 @@ state LAYOUT: state LAYOUT_TOGGLE: end -> call cmd_layout_toggle($toggle_mode) - toggle_mode = 'split', 'all' + toggle_mode = string -> call cmd_layout_toggle($toggle_mode) # append_layout diff --git a/src/con.c b/src/con.c index 40924a73..b3f193e6 100644 --- a/src/con.c +++ b/src/con.c @@ -1719,28 +1719,64 @@ void con_toggle_layout(Con *con, const char *toggle_mode) { parent = con->parent; DLOG("con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent); - if (strcmp(toggle_mode, "split") == 0) { - /* Toggle between splits. When the current layout is not a split - * layout, we just switch back to last_split_layout. Otherwise, we - * change to the opposite split layout. */ - if (parent->layout != L_SPLITH && parent->layout != L_SPLITV) - con_set_layout(con, parent->last_split_layout); - else { - if (parent->layout == L_SPLITH) - con_set_layout(con, L_SPLITV); - else - con_set_layout(con, L_SPLITH); + const char delim[] = " "; + + if (strcasecmp(toggle_mode, "split") == 0 || strstr(toggle_mode, delim)) { + /* L_DEFAULT is used as a placeholder value to distinguish if + * the first layout has already been saved. (it can never be L_DEFAULT) */ + layout_t new_layout = L_DEFAULT; + bool current_layout_found = false; + char *tm_dup = sstrdup(toggle_mode); + char *cur_tok = strtok(tm_dup, delim); + + for (layout_t layout; cur_tok != NULL; cur_tok = strtok(NULL, delim)) { + if (strcasecmp(cur_tok, "split") == 0) { + /* Toggle between splits. When the current layout is not a split + * layout, we just switch back to last_split_layout. Otherwise, we + * change to the opposite split layout. */ + if (parent->layout != L_SPLITH && parent->layout != L_SPLITV) { + layout = parent->last_split_layout; + } else { + layout = (parent->layout == L_SPLITH) ? L_SPLITV : L_SPLITH; + } + } else { + bool success = layout_from_name(cur_tok, &layout); + if (!success || layout == L_DEFAULT) { + ELOG("The token '%s' was not recognized and has been skipped.\n", cur_tok); + continue; + } + } + + /* If none of the specified layouts match the current, + * fall back to the first layout in the list */ + if (new_layout == L_DEFAULT) { + new_layout = layout; + } + + /* We found the active layout in the last iteration, so + * now let's activate the current layout (next in list) */ + if (current_layout_found) { + new_layout = layout; + free(tm_dup); + break; + } + + if (parent->layout == layout) { + current_layout_found = true; + } } - } else { + + con_set_layout(con, new_layout); + } else if (strcasecmp(toggle_mode, "all") == 0 || strcasecmp(toggle_mode, "default") == 0) { if (parent->layout == L_STACKED) con_set_layout(con, L_TABBED); else if (parent->layout == L_TABBED) { - if (strcmp(toggle_mode, "all") == 0) + if (strcasecmp(toggle_mode, "all") == 0) con_set_layout(con, L_SPLITH); else con_set_layout(con, parent->last_split_layout); } else if (parent->layout == L_SPLITH || parent->layout == L_SPLITV) { - if (strcmp(toggle_mode, "all") == 0) { + if (strcasecmp(toggle_mode, "all") == 0) { /* When toggling through all modes, we toggle between * splith/splitv, whereas normally we just directly jump to * stacked. */ diff --git a/src/util.c b/src/util.c index b6f45fde..0289ded9 100644 --- a/src/util.c +++ b/src/util.c @@ -66,7 +66,7 @@ __attribute__((pure)) bool name_is_digits(const char *name) { return true; } -/** +/* * Set 'out' to the layout_t value for the given layout. The function * returns true on success or false if the passed string is not a valid * layout name. @@ -75,20 +75,23 @@ __attribute__((pure)) bool name_is_digits(const char *name) { bool layout_from_name(const char *layout_str, layout_t *out) { if (strcmp(layout_str, "default") == 0) { *out = L_DEFAULT; + return true; } else if (strcasecmp(layout_str, "stacked") == 0 || strcasecmp(layout_str, "stacking") == 0) { *out = L_STACKED; + return true; } else if (strcasecmp(layout_str, "tabbed") == 0) { *out = L_TABBED; + return true; } else if (strcasecmp(layout_str, "splitv") == 0) { *out = L_SPLITV; + return true; } else if (strcasecmp(layout_str, "splith") == 0) { *out = L_SPLITH; - } else { - return false; + return true; } - return true; + return false; } /* diff --git a/testcases/t/192-layout.t b/testcases/t/192-layout.t index 6fd6eae8..1d406fc6 100644 --- a/testcases/t/192-layout.t +++ b/testcases/t/192-layout.t @@ -95,4 +95,72 @@ cmd 'layout toggle all'; ($nodes, $focus) = get_ws_content($tmp); is($nodes->[1]->{layout}, 'splitv', 'layout now splitv'); +cmd 'layout toggle splith splitv'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splith', 'layout now splith'); + +cmd 'layout toggle splith splitv'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splitv', 'layout now splitv'); + +cmd 'layout toggle stacked splitv tabbed'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed'); + +cmd 'layout toggle stacking splitv tabbed'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'stacked', 'layout now stacked'); + +cmd 'layout toggle stacking splitv tabbed'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splitv', 'layout now splitv'); + +cmd 'layout toggle splitv i stacking tabbed'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'stacked', 'layout now stacked'); + +cmd 'layout toggle stacked'; +($nodes, $focus) = get_ws_content($tmp); +# this is correct if it does nothing +is($nodes->[1]->{layout}, 'stacked', 'layout now tabbed'); + +cmd 'layout toggle tabbed stacked'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'tabbed', 'layout now stacked'); + +# obsoletes 'split' ;) +cmd 'layout toggle splith splitv'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splith', 'layout now splith'); + +# nonsense but works expectedly +cmd 'layout toggle split split'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splitv', 'layout now splitv'); + +cmd 'layout toggle split split'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splith', 'layout now splith'); + +# testing with arbitrary length and garbage +cmd 'layout toggle stacking splith tabbed splitv stacking'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed'); + +cmd 'layout toggle stacking splith garbage tabbed splitv stacking'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splitv', 'layout now splitv'); + +cmd 'layout toggle stacking splith garbage tabbed splitv stacking'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'stacked', 'layout now stacked'); + +cmd 'layout toggle splitv splith garbage splitv tabbed stacking splitv'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'splitv', 'layout now splitv'); + +cmd 'layout toggle splitv garbage tabbed'; +($nodes, $focus) = get_ws_content($tmp); +is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed'); + done_testing; From dda2ef9716c6025fdfac93d1f5a6e4fe7e252086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Fri, 24 Feb 2017 08:36:31 +0100 Subject: [PATCH 060/180] Fixes a small mixup in the assertion description. (#2692) relates to PR #2649 --- testcases/t/192-layout.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testcases/t/192-layout.t b/testcases/t/192-layout.t index 1d406fc6..c54f27a2 100644 --- a/testcases/t/192-layout.t +++ b/testcases/t/192-layout.t @@ -122,11 +122,11 @@ is($nodes->[1]->{layout}, 'stacked', 'layout now stacked'); cmd 'layout toggle stacked'; ($nodes, $focus) = get_ws_content($tmp); # this is correct if it does nothing -is($nodes->[1]->{layout}, 'stacked', 'layout now tabbed'); +is($nodes->[1]->{layout}, 'stacked', 'layout now stacked'); cmd 'layout toggle tabbed stacked'; ($nodes, $focus) = get_ws_content($tmp); -is($nodes->[1]->{layout}, 'tabbed', 'layout now stacked'); +is($nodes->[1]->{layout}, 'tabbed', 'layout now tabbed'); # obsoletes 'split' ;) cmd 'layout toggle splith splitv'; From 1e1da5a6595dafa479adedf8924c8d81513bbaa3 Mon Sep 17 00:00:00 2001 From: Trevor Merrifield Date: Mon, 6 Mar 2017 01:20:47 -0500 Subject: [PATCH 061/180] docs/ipc: Document the 'primary' flag Resolves #2697 --- docs/ipc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/ipc b/docs/ipc index 466b6596..026e434d 100644 --- a/docs/ipc +++ b/docs/ipc @@ -232,6 +232,8 @@ name (string):: The name of this output (as seen in +xrandr(1)+). Encoded in UTF-8. active (boolean):: Whether this output is currently active (has a valid mode). +primary (boolean):: + Whether this output is currently the primary output. current_workspace (string):: The name of the current workspace that is visible on this output. +null+ if the output is not active. From 2f0f8b16c2755165fc79c5801aedff0428ef03ad Mon Sep 17 00:00:00 2001 From: lebenlechzer Date: Sun, 12 Mar 2017 21:17:12 +0100 Subject: [PATCH 062/180] i3bar: accept 'primary' for output config option --- docs/userguide | 14 +++++++++++++- i3bar/src/ipc.c | 8 +++++++- i3bar/src/outputs.c | 11 ++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/userguide b/docs/userguide index 40e9e3b9..4946a1ba 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1378,7 +1378,7 @@ directive multiple times. *Syntax*: --------------- -output +output primary| --------------- *Example*: @@ -1400,7 +1400,19 @@ bar { statusline #ffffff } } + +# show bar on the primary monitor and on HDMI2 +bar { + output primary + output HDMI2 + status_command i3status +} + ------------------------------- +Note that you might not have a primary output configured yet. To do so, run: +------------------------- +xrandr --output --primary +------------------------- === Tray output diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index cc5074e5..459684ef 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -63,12 +63,18 @@ void got_subscribe_reply(char *reply) { * */ void got_output_reply(char *reply) { + DLOG("Clearing old output configuration...\n"); + i3_output *o_walk; + SLIST_FOREACH(o_walk, outputs, slist) { + destroy_window(o_walk); + } + FREE_SLIST(outputs, i3_output); + DLOG("Parsing outputs JSON...\n"); parse_outputs_json(reply); DLOG("Reconfiguring windows...\n"); reconfig_windows(false); - i3_output *o_walk; SLIST_FOREACH(o_walk, outputs, slist) { kick_tray_clients(o_walk); } diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index 480c00be..e7cd6eeb 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -189,11 +189,12 @@ static int outputs_end_map_cb(void *params_) { if (config.num_outputs > 0) { bool handle_output = false; for (int c = 0; c < config.num_outputs; c++) { - if (strcasecmp(params->outputs_walk->name, config.outputs[c]) != 0) - continue; - - handle_output = true; - break; + if (strcasecmp(params->outputs_walk->name, config.outputs[c]) == 0 || + (strcasecmp(config.outputs[c], "primary") == 0 && + params->outputs_walk->primary)) { + handle_output = true; + break; + } } if (!handle_output) { DLOG("Ignoring output \"%s\", not configured to handle it.\n", From f475b37a3c0bbb46f93ece8806882fcbef6f2109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20K=C3=B6nig?= Date: Sun, 26 Mar 2017 16:05:56 +0200 Subject: [PATCH 063/180] Adding new terminals to i3-sensible-terminal --- i3-sensible-terminal | 2 +- man/i3-sensible-terminal.man | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/i3-sensible-terminal b/i3-sensible-terminal index 4ef1c75f..7ec0f878 100755 --- a/i3-sensible-terminal +++ b/i3-sensible-terminal @@ -8,7 +8,7 @@ # We welcome patches that add distribution-specific mechanisms to find the # preferred terminal emulator. On Debian, there is the x-terminal-emulator # symlink for example. -for terminal in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm uxterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology st qterminal; do +for terminal in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm uxterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology st qterminal lilyterm tilix terminix; do if command -v "$terminal" > /dev/null 2>&1; then exec "$terminal" "$@" fi diff --git a/man/i3-sensible-terminal.man b/man/i3-sensible-terminal.man index b830cd09..5facbac9 100644 --- a/man/i3-sensible-terminal.man +++ b/man/i3-sensible-terminal.man @@ -40,6 +40,9 @@ It tries to start one of the following (in that order): * terminology * st * qterminal +* lilyterm +* tilix +* terminix Please don’t complain about the order: If the user has any preference, they will have $TERMINAL set or modified their i3 configuration file. From 4fa87a0c43eb1d1dbee03ddb4de1017f0068e331 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Sun, 2 Apr 2017 19:26:55 -0500 Subject: [PATCH 064/180] format i3bar src/outputs.c w/ clang-format --- i3bar/src/outputs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index e7cd6eeb..bd056a70 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -190,8 +190,8 @@ static int outputs_end_map_cb(void *params_) { bool handle_output = false; for (int c = 0; c < config.num_outputs; c++) { if (strcasecmp(params->outputs_walk->name, config.outputs[c]) == 0 || - (strcasecmp(config.outputs[c], "primary") == 0 && - params->outputs_walk->primary)) { + (strcasecmp(config.outputs[c], "primary") == 0 && + params->outputs_walk->primary)) { handle_output = true; break; } From 454578b331a8e97cd34df26f753817a6c151a935 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Fri, 7 Apr 2017 09:59:24 -0500 Subject: [PATCH 065/180] add error check and log for xcb_create_window --- src/xcb.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/xcb.c b/src/xcb.c index 726d1e89..bdfb08bc 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -28,16 +28,21 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims, visual = XCB_COPY_FROM_PARENT; } - xcb_create_window(conn, - depth, - result, /* the window id */ - root, /* parent == root */ - dims.x, dims.y, dims.width, dims.height, /* dimensions */ - 0, /* border = 0, we draw our own */ - window_class, - visual, - mask, - values); + xcb_void_cookie_t gc_cookie = xcb_create_window(conn, + depth, + result, /* the window id */ + root, /* parent == root */ + dims.x, dims.y, dims.width, dims.height, /* dimensions */ + 0, /* border = 0, we draw our own */ + window_class, + visual, + mask, + values); + + xcb_generic_error_t *error = xcb_request_check(conn, gc_cookie); + if (error != NULL) { + ELOG("Could not create window. Error code: %d.\n", error->error_code); + } /* Set the cursor */ if (xcursor_supported) { From 52ce8c803d424f395874fa87992eea0cc9f061d3 Mon Sep 17 00:00:00 2001 From: Mihai Coman Date: Thu, 27 Apr 2017 17:50:55 +0300 Subject: [PATCH 066/180] Fix changing of root workspace layout from stacked/tabbed --- src/con.c | 12 +- src/tree.c | 6 +- testcases/t/167-workspace_layout.t | 231 +++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+), 6 deletions(-) diff --git a/src/con.c b/src/con.c index b3f193e6..7b831b36 100644 --- a/src/con.c +++ b/src/con.c @@ -1639,12 +1639,14 @@ void con_set_layout(Con *con, layout_t layout) { * whole workspace into stacked/tabbed mode. To do this and still allow * intuitive operations (like level-up and then opening a new window), we * need to create a new split container. */ - if (con->type == CT_WORKSPACE && - (layout == L_STACKED || layout == L_TABBED)) { + if (con->type == CT_WORKSPACE) { if (con_num_children(con) == 0) { - DLOG("Setting workspace_layout to %d\n", layout); - con->workspace_layout = layout; - } else { + layout_t ws_layout = (layout == L_STACKED || layout == L_TABBED) ? layout : L_DEFAULT; + DLOG("Setting workspace_layout to %d\n", ws_layout); + con->workspace_layout = ws_layout; + DLOG("Setting layout to %d\n", layout); + con->layout = layout; + } else if (layout == L_STACKED || layout == L_TABBED) { DLOG("Creating new split container\n"); /* 1: create a new split container */ Con *new = con_new(NULL, NULL); diff --git a/src/tree.c b/src/tree.c index d2fe4e07..2d4647f8 100644 --- a/src/tree.c +++ b/src/tree.c @@ -383,7 +383,11 @@ void tree_split(Con *con, orientation_t orientation) { if (con->type == CT_WORKSPACE) { if (con_num_children(con) < 2) { - DLOG("Just changing orientation of workspace\n"); + if (con_num_children(con) == 0) { + DLOG("Changing workspace_layout to L_DEFAULT\n"); + con->workspace_layout = L_DEFAULT; + } + DLOG("Changing orientation of workspace\n"); con->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; return; } else { diff --git a/testcases/t/167-workspace_layout.t b/testcases/t/167-workspace_layout.t index 033a31f2..1ed09990 100644 --- a/testcases/t/167-workspace_layout.t +++ b/testcases/t/167-workspace_layout.t @@ -145,6 +145,237 @@ is($x->input_focus, $second->id, 'second window focused'); ok(@content == 1, 'one con at workspace level'); is($content[0]->{layout}, 'stacked', 'layout stacked'); +##################################################################### +# 8: when the workspace is empty check that its layout can be changed +# from stacked to horizontal split using the 'layout splith' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout stacked'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'stacked', 'layout stacked'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'layout splith'; +$first = open_window; +$second = open_window; +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'stacked', 'layout not stacked'); +isnt($content[1]->{layout}, 'stacked', 'layout not stacked'); + +##################################################################### +# 9: when the workspace is empty check that its layout can be changed +# from stacked to vertical split using the 'layout splitv' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout stacked'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'stacked', 'layout stacked'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'layout splitv'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'stacked', 'layout not stacked'); +isnt($content[1]->{layout}, 'stacked', 'layout not stacked'); + +##################################################################### +# 10: when the workspace is empty check that its layout can be changed +# from tabbed to horizontal split using the 'layout splith' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout tabbed'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'tabbed', 'layout tabbed'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'layout splith'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'tabbed', 'layout not tabbed'); +isnt($content[1]->{layout}, 'tabbed', 'layout not tabbed'); + +##################################################################### +# 11: when the workspace is empty check that its layout can be changed +# from tabbed to vertical split using the 'layout splitv' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout tabbed'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'tabbed', 'layout tabbed'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'layout splitv'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'tabbed', 'layout not tabbed'); +isnt($content[1]->{layout}, 'tabbed', 'layout not tabbed'); + +##################################################################### +# 12: when the workspace is empty check that its layout can be changed +# from stacked to horizontal split using the 'split horizontal' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout stacked'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'stacked', 'layout stacked'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'split horizontal'; +$first = open_window; +$second = open_window; +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'stacked', 'layout not stacked'); +isnt($content[1]->{layout}, 'stacked', 'layout not stacked'); + +##################################################################### +# 13: when the workspace is empty check that its layout can be changed +# from stacked to vertical split using the 'split vertical' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout stacked'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'stacked', 'layout stacked'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'split vertical'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'stacked', 'layout not stacked'); +isnt($content[1]->{layout}, 'stacked', 'layout not stacked'); + +##################################################################### +# 14: when the workspace is empty check that its layout can be changed +# from tabbed to horizontal split using the 'split horizontal' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout tabbed'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'tabbed', 'layout tabbed'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'split horizontal'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'tabbed', 'layout not tabbed'); +isnt($content[1]->{layout}, 'tabbed', 'layout not tabbed'); + +##################################################################### +# 15: when the workspace is empty check that its layout can be changed +# from tabbed to vertical split using the 'split vertical' command. +##################################################################### + +$tmp = fresh_workspace; + +cmd 'layout tabbed'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +is($content[0]->{layout}, 'tabbed', 'layout tabbed'); + +cmd '[id="' . $first->id . '"] kill'; +cmd '[id="' . $second->id . '"] kill'; +sync_with_i3; + +ok(@{get_ws_content($tmp)} == 0, 'workspace is empty'); + +cmd 'split vertical'; +$first = open_window; +$second = open_window; + +@content = @{get_ws_content($tmp)}; +ok(@content == 2, 'two containers opened'); +isnt($content[0]->{layout}, 'tabbed', 'layout not tabbed'); +isnt($content[1]->{layout}, 'tabbed', 'layout not tabbed'); + + exit_gracefully($pid); done_testing; From 32175b0a1f2db722a0adc149f1ddc3cbef1f9553 Mon Sep 17 00:00:00 2001 From: Sebastian Larsson Date: Sun, 30 Apr 2017 14:40:04 +0200 Subject: [PATCH 067/180] Fix i3-dmenu-desktop quoted command name According to the Desktop Entry Specification https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables the executable name or path of the executable may be quoted. This is not properly respected when i3-dmenu-desktop extracts the command name from the Exec entry. Examples of values that fail and what they currently result in: - "bar" -> "bar" - "foo/bar" -> bar" - "foo foobar/bar" -> "foo - "foo\sbar" -> "foo\sbar" - foo\sbar -> foo\sbar - "foo\\\\bar" -> "foo\\\\bar" --- i3-dmenu-desktop | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/i3-dmenu-desktop b/i3-dmenu-desktop index 3b81cb20..1d29a69f 100755 --- a/i3-dmenu-desktop +++ b/i3-dmenu-desktop @@ -282,7 +282,31 @@ for my $app (keys %apps) { } if ((scalar grep { $_ eq 'command' } @entry_types) > 0) { - my ($command) = split(' ', $apps{$app}->{Exec}); + my $command = $apps{$app}->{Exec}; + + # Handle escape sequences (should be done for all string values, but does + # matter here). + my %escapes = ( + '\\s' => ' ', + '\\n' => '\n', + '\\t' => '\t', + '\\r' => '\r', + '\\\\' => '\\', + ); + $command =~ s/(\\[sntr\\])/$escapes{$1}/go; + + # Extract executable + if ($command =~ m/^\s*([^\s\"]+)(?:\s|$)/) { + # No quotes + $command = $1; + } elsif ($command =~ m/^\s*\"([^\"\\]*(?:\\.[^\"\\]*)*)\"(?:\s|$)/) { + # Quoted, remove quotes and fix escaped characters + $command = $1; + $command =~ s/\\([\"\`\$\\])/$1/g; + } else { + # Invalid quotes, fallback to whitespace + ($command) = split(' ', $command); + } # Don’t add “geany” if “Geany” is already present. my @keys = map { lc } keys %choices; From d78fd8d91fa714dec5288322098dec6410927f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 2 May 2017 09:08:42 +0200 Subject: [PATCH 068/180] Introduce --exclude-titlebar flag for mouse bindings. (#2703) This introduces the flag --exclude-titlebar for mouse bindings which allows bindings like bindsym --whole-window --border --exclude-titlebar button3 focus fixes #2347 --- docs/userguide | 9 ++++++--- include/bindings.h | 3 ++- include/config_directives.h | 4 ++-- include/data.h | 4 ++++ parser-specs/config.spec | 12 ++++++++++-- src/bindings.c | 4 +++- src/click.c | 2 +- src/config_directives.c | 8 ++++---- testcases/t/201-config-parser.t | 20 ++++++++++++-------- 9 files changed, 44 insertions(+), 22 deletions(-) diff --git a/docs/userguide b/docs/userguide index 4946a1ba..d2ad7d41 100644 --- a/docs/userguide +++ b/docs/userguide @@ -412,9 +412,9 @@ button in the scope of the clicked container (see <>). You can configure mouse bindings in a similar way to key bindings. *Syntax*: -------------------------------------------------------------------------------- -bindsym [--release] [--border] [--whole-window] [+]button command -------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +bindsym [--release] [--border] [--whole-window] [--exclude-titlebar] [+]button command +---------------------------------------------------------------------------------------------------- By default, the binding will only run when you click on the titlebar of the window. If the +--release+ flag is given, it will run when the mouse button @@ -424,6 +424,9 @@ If the +--whole-window+ flag is given, the binding will also run when any part of the window is clicked, with the exception of the border. To have a bind run when the border is clicked, specify the +--border+ flag. +If the +--exclude-titlebar+ flag is given, the titlebar will not be considered +for the keybinding. + *Examples*: -------------------------------- # The middle button over a titlebar kills the window diff --git a/include/bindings.h b/include/bindings.h index 0fcc4df4..df3c32a5 100644 --- a/include/bindings.h +++ b/include/bindings.h @@ -27,7 +27,8 @@ extern const char *DEFAULT_BINDING_MODE; */ Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *border, const char *whole_window, - const char *command, const char *mode, bool pango_markup); + const char *exclude_titlebar, const char *command, const char *mode, + bool pango_markup); /** * Grab the bound keys (tell X to send us keypress events for those keycodes) diff --git a/include/config_directives.h b/include/config_directives.h index 0bf52168..f35666f3 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -67,10 +67,10 @@ CFGFUN(color_single, const char *colorclass, const char *color); CFGFUN(floating_modifier, const char *modifiers); CFGFUN(new_window, const char *windowtype, const char *border, const long width); CFGFUN(workspace, const char *workspace, const char *output); -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command); +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command); CFGFUN(enter_mode, const char *pango_markup, const char *mode); -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command); +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command); CFGFUN(bar_font, const char *font); CFGFUN(bar_separator_symbol, const char *separator); diff --git a/include/data.h b/include/data.h index 3d67e315..69a79ade 100644 --- a/include/data.h +++ b/include/data.h @@ -298,6 +298,10 @@ struct Binding { * title bar (default). */ bool whole_window; + /** If this is true for a mouse binding, the binding should only be + * executed if the button press was not on the titlebar. */ + bool exclude_titlebar; + /** Keycode to bind */ uint32_t keycode; diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 19e2d21a..53828221 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -321,6 +321,8 @@ state BINDING: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', 'Group1', 'Group2', 'Group3', 'Group4', '$mod' -> '+' @@ -335,8 +337,10 @@ state BINDCOMMAND: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> command = string - -> call cfg_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command) + -> call cfg_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $exclude_titlebar, $command) ################################################################################ # Mode configuration @@ -376,6 +380,8 @@ state MODE_BINDING: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', 'Group1', 'Group2', 'Group3', 'Group4', '$mod' -> '+' @@ -390,8 +396,10 @@ state MODE_BINDCOMMAND: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> command = string - -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command); MODE + -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $exclude_titlebar, $command); MODE ################################################################################ # Bar configuration (i3bar) diff --git a/src/bindings.c b/src/bindings.c index bfec27e1..36bcc5d1 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -56,12 +56,14 @@ static struct Mode *mode_from_name(const char *name, bool pango_markup) { */ Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *border, const char *whole_window, - const char *command, const char *modename, bool pango_markup) { + const char *exclude_titlebar, const char *command, const char *modename, + bool pango_markup) { Binding *new_binding = scalloc(1, sizeof(Binding)); DLOG("Binding %p bindtype %s, modifiers %s, input code %s, release %s\n", new_binding, bindtype, modifiers, input_code, release); new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS); new_binding->border = (border != NULL); new_binding->whole_window = (whole_window != NULL); + new_binding->exclude_titlebar = (exclude_titlebar != NULL); if (strcmp(bindtype, "bindsym") == 0) { new_binding->input_type = (strncasecmp(input_code, "button", (sizeof("button") - 1)) == 0 ? B_MOUSE diff --git a/src/click.c b/src/click.c index e989b88d..e5cdc8b2 100644 --- a/src/click.c +++ b/src/click.c @@ -186,7 +186,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod if (dest == CLICK_DECORATION || dest == CLICK_INSIDE || dest == CLICK_BORDER) { Binding *bind = get_binding_from_xcb_event((xcb_generic_event_t *)event); - if (bind != NULL && (dest == CLICK_DECORATION || + if (bind != NULL && ((dest == CLICK_DECORATION && !bind->exclude_titlebar) || (dest == CLICK_INSIDE && bind->whole_window) || (dest == CLICK_BORDER && bind->border))) { CommandResult *result = run_binding(bind, con); diff --git a/src/config_directives.c b/src/config_directives.c index 879d225e..7ca6e102 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -106,8 +106,8 @@ CFGFUN(font, const char *font) { font_pattern = sstrdup(font); } -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) { - configure_binding(bindtype, modifiers, key, release, border, whole_window, command, DEFAULT_BINDING_MODE, false); +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command) { + configure_binding(bindtype, modifiers, key, release, border, whole_window, exclude_titlebar, command, DEFAULT_BINDING_MODE, false); } /******************************************************************************* @@ -117,8 +117,8 @@ CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, co static char *current_mode; static bool current_mode_pango_markup; -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) { - configure_binding(bindtype, modifiers, key, release, border, whole_window, command, current_mode, current_mode_pango_markup); +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command) { + configure_binding(bindtype, modifiers, key, release, border, whole_window, exclude_titlebar, command, current_mode, current_mode_pango_markup); } CFGFUN(enter_mode, const char *pango_markup, const char *modename) { diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 1de86c65..159de046 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -49,18 +49,22 @@ mode "meh" { bindsym --release --whole-window button3 nop bindsym --border button3 nop bindsym --release --border button3 nop + bindsym --exclude-titlebar button3 nop + bindsym --whole-window --border --exclude-titlebar button3 nop } EOT my $expected = <<'EOT'; cfg_enter_mode((null), meh) -cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), (null), resize grow) -cfg_mode_binding(bindcode, Mod1, 44, (null), (null), (null), resize shrink) -cfg_mode_binding(bindsym, Mod1, x, --release, (null), (null), exec foo) -cfg_mode_binding(bindsym, (null), button3, (null), (null), --whole-window, nop) -cfg_mode_binding(bindsym, (null), button3, --release, (null), --whole-window, nop) -cfg_mode_binding(bindsym, (null), button3, (null), --border, (null), nop) -cfg_mode_binding(bindsym, (null), button3, --release, --border, (null), nop) +cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), (null), (null), resize grow) +cfg_mode_binding(bindcode, Mod1, 44, (null), (null), (null), (null), resize shrink) +cfg_mode_binding(bindsym, Mod1, x, --release, (null), (null), (null), exec foo) +cfg_mode_binding(bindsym, (null), button3, (null), (null), --whole-window, (null), nop) +cfg_mode_binding(bindsym, (null), button3, --release, (null), --whole-window, (null), nop) +cfg_mode_binding(bindsym, (null), button3, (null), --border, (null), (null), nop) +cfg_mode_binding(bindsym, (null), button3, --release, --border, (null), (null), nop) +cfg_mode_binding(bindsym, (null), button3, (null), (null), (null), --exclude-titlebar, nop) +cfg_mode_binding(bindsym, (null), button3, (null), --border, --whole-window, --exclude-titlebar, nop) EOT is(parser_calls($config), @@ -674,7 +678,7 @@ EOT $expected = <<'EOT'; cfg_enter_mode((null), yo) -cfg_mode_binding(bindsym, (null), x, (null), (null), (null), resize shrink left) +cfg_mode_binding(bindsym, (null), x, (null), (null), (null), (null), resize shrink left) ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', '}' ERROR: CONFIG: (in file ) ERROR: CONFIG: Line 1: mode "yo" { From c826fc0e44c2fccb5ffc4c70c761cdf6807e9920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 2 May 2017 09:11:35 +0200 Subject: [PATCH 069/180] Query workspaces again in i3bar when an output change occured. (#2760) As of 2f0f8b1, i3bar will properly clean up on output change events. However, this requires us to query the workspaces again to avoid a display error in i3bar. fixes #2740 fixes #2743 --- i3bar/src/ipc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i3bar/src/ipc.c b/i3bar/src/ipc.c index 459684ef..042e230a 100644 --- a/i3bar/src/ipc.c +++ b/i3bar/src/ipc.c @@ -79,6 +79,10 @@ void got_output_reply(char *reply) { kick_tray_clients(o_walk); } + if (!config.disable_ws) { + i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } + draw_bars(false); } From a3c6a89e6e1d7b14d8df80d19fe4d1246d8dc447 Mon Sep 17 00:00:00 2001 From: Maarten Dirkse Date: Tue, 2 May 2017 13:12:25 +0200 Subject: [PATCH 070/180] Change golang ipc lib reference to one that is maintained. --- docs/ipc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ipc b/docs/ipc index 026e434d..7268c2ed 100644 --- a/docs/ipc +++ b/docs/ipc @@ -861,7 +861,7 @@ C:: C++:: * https://github.com/drmgc/i3ipcpp Go:: - * https://github.com/proxypoke/i3ipc + * https://github.com/mdirkse/i3ipc-go JavaScript:: * https://github.com/acrisci/i3ipc-gjs Lua:: From e428bf02fb071b74df41adf8b7ac463afabca2fd Mon Sep 17 00:00:00 2001 From: Maarten Dirkse Date: Thu, 4 May 2017 00:36:44 +0200 Subject: [PATCH 071/180] Fix invalid JSON --- docs/ipc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ipc b/docs/ipc index 026e434d..2e223801 100644 --- a/docs/ipc +++ b/docs/ipc @@ -264,7 +264,7 @@ rect (map):: "y": 0, "width": 1280, "height": 1024 - }, + } } ] ------------------- @@ -392,7 +392,7 @@ JSON dump: "y": 0, "width": 1280, "height": 0 - }, + } }, { From b56cb84e16a342766d9a0b43e74bdadca22931bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 4 May 2017 23:08:51 +0200 Subject: [PATCH 072/180] Added a hint about the required config v4 version hint. (#2759) fixes #2751 --- docs/userguide | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/userguide b/docs/userguide index d2ad7d41..068ecd87 100644 --- a/docs/userguide +++ b/docs/userguide @@ -297,6 +297,15 @@ keyboard layout. To start the wizard, use the command +i3-config-wizard+. Please note that you must not have +~/.i3/config+, otherwise the wizard will exit. +Since i3 4.0, a new configuration format is used. i3 will try to automatically +detect the format version of a config file based on a few different keywords, +but if you want to make sure that your config is read with the new format, +include the following line in your config file: + +--------------------- +# i3 config file (v4) +--------------------- + === Comments It is possible and recommended to use comments in your configuration file to From 9bc504ebdb92e56e1a34047f8ab7c70f6b67eb90 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Fri, 7 Apr 2017 09:59:24 -0500 Subject: [PATCH 073/180] add error check and log for xcb_create_window --- src/xcb.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/xcb.c b/src/xcb.c index 726d1e89..bdfb08bc 100644 --- a/src/xcb.c +++ b/src/xcb.c @@ -28,16 +28,21 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims, visual = XCB_COPY_FROM_PARENT; } - xcb_create_window(conn, - depth, - result, /* the window id */ - root, /* parent == root */ - dims.x, dims.y, dims.width, dims.height, /* dimensions */ - 0, /* border = 0, we draw our own */ - window_class, - visual, - mask, - values); + xcb_void_cookie_t gc_cookie = xcb_create_window(conn, + depth, + result, /* the window id */ + root, /* parent == root */ + dims.x, dims.y, dims.width, dims.height, /* dimensions */ + 0, /* border = 0, we draw our own */ + window_class, + visual, + mask, + values); + + xcb_generic_error_t *error = xcb_request_check(conn, gc_cookie); + if (error != NULL) { + ELOG("Could not create window. Error code: %d.\n", error->error_code); + } /* Set the cursor */ if (xcursor_supported) { From 2fe9d7bbd262f663e91f27b1876d26224950b2b2 Mon Sep 17 00:00:00 2001 From: Max Fisher Date: Sun, 7 May 2017 23:40:19 +1000 Subject: [PATCH 074/180] i3-nagbar: add button flag to execute action with /bin/sh directly. Fixes #2765. --- i3-nagbar/main.c | 116 +++++++++++++++++++++++++++------------------- man/i3-nagbar.man | 14 ++++-- 2 files changed, 78 insertions(+), 52 deletions(-) diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c index 7d38f731..6ec4294f 100644 --- a/i3-nagbar/main.c +++ b/i3-nagbar/main.c @@ -50,6 +50,7 @@ static char *argv0 = NULL; typedef struct { i3String *label; char *action; + bool exec_in_terminal; int16_t x; uint16_t width; } button_t; @@ -123,6 +124,51 @@ static void start_application(const char *command) { wait(0); } +static void execute_in_terminal(const char *command) { + /* We need to create a custom script containing our actual command + * since not every terminal emulator which is contained in + * i3-sensible-terminal supports -e with multiple arguments (and not + * all of them support -e with one quoted argument either). + * + * NB: The paths need to be unique, that is, don’t assume users close + * their nagbars at any point in time (and they still need to work). + * */ + char *script_path = get_process_filename("nagbar-cmd"); + + int fd = open(script_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd == -1) { + warn("Could not create temporary script to store the nagbar command"); + return; + } + FILE *script = fdopen(fd, "w"); + if (script == NULL) { + warn("Could not fdopen() temporary script to store the nagbar command"); + return; + } + fprintf(script, "#!/bin/sh\nrm %s\n%s", script_path, command); + /* Also closes fd */ + fclose(script); + + char *link_path; + char *exe_path = get_exe_path(argv0); + sasprintf(&link_path, "%s.nagbar_cmd", script_path); + if (symlink(exe_path, link_path) == -1) { + err(EXIT_FAILURE, "Failed to symlink %s to %s", link_path, exe_path); + } + + char *terminal_cmd; + sasprintf(&terminal_cmd, "i3-sensible-terminal -e %s", link_path); + printf("argv0 = %s\n", argv0); + printf("terminal_cmd = %s\n", terminal_cmd); + + start_application(terminal_cmd); + + free(link_path); + free(terminal_cmd); + free(script_path); + free(exe_path); +} + static button_t *get_button_at(int16_t x, int16_t y) { for (int c = 0; c < buttoncnt; c++) if (x >= (buttons[c].x) && x <= (buttons[c].x + buttons[c].width)) @@ -149,51 +195,15 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve if (event->event_x >= btn_close.x && event->event_x < btn_close.x + btn_close.width) exit(0); button_t *button = get_button_at(event->event_x, event->event_y); - if (!button) - return; - - /* We need to create a custom script containing our actual command - * since not every terminal emulator which is contained in - * i3-sensible-terminal supports -e with multiple arguments (and not - * all of them support -e with one quoted argument either). - * - * NB: The paths need to be unique, that is, don’t assume users close - * their nagbars at any point in time (and they still need to work). - * */ - char *script_path = get_process_filename("nagbar-cmd"); - - int fd = open(script_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd == -1) { - warn("Could not create temporary script to store the nagbar command"); + if (!button) { return; } - FILE *script = fdopen(fd, "w"); - if (script == NULL) { - warn("Could not fdopen() temporary script to store the nagbar command"); - return; + + if (button->exec_in_terminal) { + execute_in_terminal(button->action); + } else { + start_application(button->action); } - fprintf(script, "#!/bin/sh\nrm %s\n%s", script_path, button->action); - /* Also closes fd */ - fclose(script); - - char *link_path; - char *exe_path = get_exe_path(argv0); - sasprintf(&link_path, "%s.nagbar_cmd", script_path); - if (symlink(exe_path, link_path) == -1) { - err(EXIT_FAILURE, "Failed to symlink %s to %s", link_path, exe_path); - } - - char *terminal_cmd; - sasprintf(&terminal_cmd, "i3-sensible-terminal -e %s", link_path); - printf("argv0 = %s\n", argv0); - printf("terminal_cmd = %s\n", terminal_cmd); - - start_application(terminal_cmd); - - free(link_path); - free(terminal_cmd); - free(script_path); - free(exe_path); /* TODO: unset flag, re-render */ } @@ -358,12 +368,13 @@ int main(int argc, char *argv[]) { {"version", no_argument, 0, 'v'}, {"font", required_argument, 0, 'f'}, {"button", required_argument, 0, 'b'}, + {"button-sh", required_argument, 0, 'B'}, {"help", no_argument, 0, 'h'}, {"message", required_argument, 0, 'm'}, {"type", required_argument, 0, 't'}, {0, 0, 0, 0}}; - char *options_string = "b:f:m:t:vh"; + char *options_string = "B:b:f:m:t:vh"; prompt = i3string_from_utf8("Please do not run this program."); @@ -385,15 +396,26 @@ int main(int argc, char *argv[]) { break; case 'h': printf("i3-nagbar " I3_VERSION "\n"); - printf("i3-nagbar [-m ] [-b