/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ /** \file ghost/intern/GHOST_WindowX11.cpp * \ingroup GHOST */ #include #include "GHOST_WindowX11.h" #include "GHOST_SystemX11.h" #include "STR_String.h" #include "GHOST_Debug.h" #ifdef WITH_XDND #include "GHOST_DropTargetX11.h" #endif /* For standard X11 cursors */ #include #include #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) #include #endif #include #include #include #include /* For obscure full screen mode stuff * lifted verbatim from blut. */ typedef struct { long flags; long functions; long decorations; long input_mode; } MotifWmHints; // Workaround for MESA bug #54080 // https://bugs.freedesktop.org/show_bug.cgi?id=54080() #define SWAP_INTERVALS_WORKAROUND #ifdef SWAP_INTERVALS_WORKAROUND static bool g_swap_interval_disabled = false; #endif // SWAP_INTERVALS_WORKAROUND #define MWM_HINTS_DECORATIONS (1L << 1) // #define GHOST_X11_GRAB /* * A Client can't change the window property, that is * the work of the window manager. In case, we send * a ClientMessage to the RootWindow with the property * and the Action (WM-spec define this): */ #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 // #define _NET_WM_STATE_TOGGLE 2 // UNUSED /* * import bpy * ima = bpy.data.images["blender.png"] * w, h = ima.size * print("%d,%d," % (w, h)) * for y in range(h - 1, -1, -1): * px = [] * for x in range(w): * p = ((y * w) + x) * 4 * rgba = ima.pixels[p : p + 4] * rgba = rgba[2], rgba[1], rgba[0], rgba[3] * px.append(sum((int(p * 255) << (8 * i)) for i, p in enumerate(rgba))) * print(", ".join([str(p) for p in px]), end=",\n") */ /* See the python script above to regenerate the 48x48 icon within blender */ static long BLENDER_ICON_48x48x32[] = { 48,48, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 131820800, 1305304320, 2547014912, 1808620800, 432823296, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 3218103552, 4074070530, 4276450320, 4124995601, 4090518785, 1624202496, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1053710848, 4140916224, 4294348072, 4294483011, 4294483268, 4294153273, 4107626765, 2765053184, 146759680, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 282025984, 4124007680, 4293884685, 4294482752, 4294483785, 4294483785, 4294417734, 4141905692, 3671088640, 600596224, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1573804544, 4124073472, 4293555207, 4294416700, 4294484558, 4294484558, 4294484558, 4260005935, 4073807875, 1355766784, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 936140032, 3973012736, 4192300034, 4294415154, 4294485331, 4294485074, 4294485074, 4294088514, 4107560459, 2463128832, 79642624, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 399726848, 3452984576, 4107887616, 4294281765, 4294485590, 4294485591, 4294485590, 4294418767, 4124931612, 3469762048, 449730560, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 97281536, 2597412096, 4107427584, 4293951767, 4294485590, 4294551642, 4294486105, 4294485847, 4226320176, 4023344642, 1120754944, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1389190400, 2949668096, 4073741568, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4291714048, 4158482693, 4294484301, 4294552415, 4294552157, 4294551899, 4294486105, 4293957442, 4124206089, 2144427008, 33488896, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1171217408, 4107361792, 4293425685, 4294218035, 4294482753, 4294483268, 4294483783, 4294484043, 4294484558, 4294484817, 4294485331, 4294485591, 4294486105, 4294551899, 4294552157, 4294552415, 4294552672, 4294552673, 4294552930, 4294552674, 4294552674, 4294553188, 4294553190, 4294552932, 4294552674, 4294552415, 4294552156, 4294551642, 4294287696, 4124733464, 3234946560, 315970816, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 3838860800, 4293620999, 4294416700, 4294482753, 4294483269, 4294483784, 4294484300, 4294484816, 4294485331, 4294485591, 4294551642, 4294552157, 4294552672, 4294552931, 4294553446, 4294553704, 4294553962, 4294554220, 4294554221, 4294554221, 4294554220, 4294554220, 4294553962, 4294553704, 4294553190, 4294552931, 4294552416, 4294552157, 4294551642, 4294485590, 4192502315, 3939458305, 919624192, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 3838860800, 4293751810, 4294415669, 4294482753, 4294483268, 4294483784, 4294484300, 4294484816, 4294485331, 4294485591, 4294551642, 4294552157, 4294552932, 4294553447, 4294553962, 4294554220, 4294554479, 4294554737, 4294554994, 4294554994, 4294554994, 4294554737, 4294554479, 4294554220, 4294553705, 4294553446, 4294552931, 4294552416, 4294552156, 4294486105, 4294485589, 4293824827, 4124140038, 1741708800, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 2463128832, 4191905024, 4294145792, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294345234, 4294553447, 4294554221, 4294554736, 4294620787, 4294621045, 4294621047, 4294621303, 4294621047, 4294621045, 4294554995, 4294554737, 4294554220, 4294553705, 4294553190, 4294552930, 4294552414, 4294551899, 4294485847, 4294485590, 4294155594, 4141050128, 1573936384, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 248011520, 2983288320, 4191116288, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4174405120, 4207959552, 4294214422, 4294554220, 4294554736, 4294620787, 4294621046, 4294621562, 4294621820, 4294690967, 4294761660, 4294830292, 4294899180, 4294966780, 4294898406, 4294829002, 4294759597, 4294621304, 4294552416, 4294551900, 4294485848, 4294485332, 4294485590, 4294221646, 4140984079, 1204641024, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 79642624, 282025984, 282025984, 282025984, 282025984, 282025984, 282025984, 1540316160, 4124007680, 4226185237, 4294552156, 4294554221, 4294554737, 4294620789, 4294621561, 4294623367, 4294829774, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294966778, 4294759856, 4294552674, 4294486105, 4294485589, 4294484817, 4294551127, 4294089804, 4090651658, 885939456, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 97281536, 2513394688, 4124139264, 4293888040, 4294552931, 4294553705, 4294554478, 4294554737, 4294621045, 4294692513, 4294900470, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294898922, 4294621046, 4294485589, 4294484817, 4294484558, 4294551383, 4293891393, 4023344385, 432823296, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 583752192, 3604045056, 4124796420, 4294285115, 4294552672, 4294553189, 4294553704, 4294554220, 4294554736, 4294623367, 4294769142, 4294835709, 4294835709, 4294835709, 4293192946, 4289446870, 4287803851, 4286620866, 4287738058, 4289446871, 4293850103, 4294901502, 4294901502, 4294901502, 4294898406, 4294552157, 4294484816, 4294484301, 4294484299, 4294486105, 4192502057, 2530172416, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1473075968, 4090518784, 4259673101, 4294484042, 4294551899, 4294552415, 4294552931, 4294553447, 4294553962, 4294554995, 4294700770, 4294704123, 4294704123, 4294769916, 4290169563, 4286555330, 4286423745, 4286292416, 4286095038, 4285897917, 4285635259, 4285766844, 4291155427, 4294769916, 4294769916, 4294769916, 4294628011, 4294278923, 4294278408, 4294278149, 4294279181, 4294149404, 4140784896, 365846784, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 163992832, 2731564288, 4124205057, 4293952286, 4294484816, 4294485590, 4294551642, 4294552157, 4294552673, 4294553188, 4294553704, 4294561702, 4294572537, 4294572537, 4294638330, 4291023841, 4286226623, 4286226623, 4286160831, 4286029502, 4285832381, 4285700795, 4284977846, 4282414755, 4280706199, 4290629597, 4294572537, 4294572537, 4294572537, 4294350393, 4294277376, 4294277376, 4294277633, 4294413864, 4158482692, 1875663872, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 718166784, 3738197248, 4141705477, 4294283568, 4294484815, 4294484816, 4294485332, 4294485848, 4294551899, 4294552158, 4294552673, 4294553188, 4294500036, 4294440951, 4294506744, 4294243830, 4286292159, 4285963709, 4285898173, 4285832381, 4285766588, 4285372345, 4282349219, 4279391885, 4279063179, 4279063179, 4281954719, 4294375158, 4294375158, 4294375158, 4294357617, 4294277376, 4294277376, 4294277376, 4294346781, 4293557270, 3218103552, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 1691311104, 4124007936, 4276647182, 4294416701, 4294483784, 4294484043, 4294484558, 4294485073, 4294485332, 4294485848, 4294551899, 4294552158, 4294552672, 4294372579, 4294375158, 4294375158, 4291943654, 4285569467, 4285635003, 4285569467, 4285503674, 4282875047, 4279654800, 4279063179, 4279063179, 4279063179, 4279063179, 4279128971, 4292732137, 4294177779, 4294177779, 4294233511, 4294277376, 4294277376, 4294277376, 4294344717, 4294217516, 4140784640, 50298880, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 232284672, 2949668096, 4107559426, 4294017820, 4294416960, 4294482753, 4294483268, 4294416959, 4294413348, 4294347296, 4294417474, 4294485332, 4294485848, 4294551642, 4294487137, 4294177779, 4294243572, 4294243572, 4290958047, 4285306552, 4285306553, 4284583603, 4280509077, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4291417567, 4293980400, 4294046193, 4294107085, 4294277376, 4294277376, 4294277376, 4294277376, 4294416185, 4207959811, 232284672, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 852253696, 3855638016, 4158614278, 4294348586, 4294416701, 4294416443, 4294416958, 4294415411, 4294280731, 4108283403, 4243290129, 4294414638, 4294484817, 4294485331, 4294485590, 4294485848, 4294174941, 4294111986, 4294111986, 4292206309, 4284977846, 4283137961, 4279457678, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279457422, 4293454571, 4293848814, 4293848814, 4294035617, 4294277376, 4294277376, 4294277376, 4294277376, 4294416443, 4140916998, 365846784, 4671303, 4671303, 4671303, 4671303, 4671303, 1909480704, 4124073472, 4293490704, 4294415154, 4294415669, 4294415669, 4294416184, 4294414123, 4294083611, 4090914310, 4040055808, 4293161999, 4294414379, 4294484557, 4294484815, 4294485074, 4294485331, 4294104247, 4293914607, 4293914607, 4293783279, 4283334569, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4284057260, 4293585642, 4293651435, 4293651435, 4293962857, 4294277376, 4294277376, 4294277376, 4294277376, 4294416959, 4124205832, 499800064, 4671303, 4671303, 4671303, 298998272, 3150929152, 4107690755, 4294018076, 4294415410, 4294414636, 4294414638, 4294415153, 4294413606, 4293886234, 4124205059, 2110675968, 2060409856, 4225921807, 4294414895, 4294483785, 4294484043, 4294484557, 4294484815, 4294164622, 4293783021, 4293717228, 4293388263, 4290299602, 4279326093, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4280245907, 4292205535, 4293454056, 4293454056, 4293454056, 4294086704, 4294277376, 4294277376, 4294277376, 4294277891, 4294417992, 4207894017, 97281536, 4671303, 4671303, 50298880, 3503250688, 4192169224, 4294282278, 4294414381, 4294347813, 4294413865, 4294414122, 4294348070, 4259937303, 4090519041, 1305304320, 4671303, 1238260480, 4024002053, 4294415926, 4294483269, 4294483527, 4294483784, 4294484043, 4294419022, 4293712069, 4293190884, 4293059298, 4293059298, 4289905102, 4281297305, 4279063179, 4279063179, 4279063179, 4279063179, 4279063179, 4282677154, 4291351001, 4293256677, 4293256677, 4293256677, 4293639310, 4294277376, 4294277376, 4294277376, 4294277376, 4294345490, 4294022463, 3671088640, 4671303, 4671303, 4671303, 2077187328, 4107822598, 4294348586, 4294347555, 4294347039, 4294347554, 4294348069, 4294348327, 4175590163, 3872349440, 718166784, 4671303, 4671303, 449730560, 4124073472, 4294414379, 4294417217, 4294483010, 4294483268, 4294483269, 4294415927, 4294084898, 4292925905, 4292861919, 4292861919, 4292927712, 4292533470, 4288656582, 4286094006, 4284517036, 4286685370, 4289379531, 4292927713, 4293059298, 4293059298, 4293059298, 4293251260, 4294212873, 4294277376, 4294277376, 4294277376, 4294277376, 4294414896, 4259939884, 2681167104, 4671303, 4671303, 97281536, 4191116288, 4294084386, 4294413347, 4294346265, 4294346780, 4294413091, 4294282281, 4124732172, 3335609856, 315970816, 4671303, 4671303, 4671303, 16777216, 3452853504, 4293624609, 4294415670, 4294416702, 4294416959, 4294414121, 4294277634, 4294277376, 4293825597, 4292793547, 4292664540, 4292730333, 4292730333, 4292730333, 4292730333, 4292796126, 4292796126, 4292796126, 4292796126, 4292861919, 4292861919, 4293120190, 4294085156, 4294277376, 4294277376, 4294277376, 4294277376, 4294278149, 4294485332, 4074071305, 969825792, 4671303, 4671303, 198270208, 4224605184, 4294282535, 4294413347, 4294346524, 4294348070, 4294085417, 4107559687, 2563792384, 79642624, 4671303, 4671303, 83886080, 184549376, 268435456, 1605258752, 4074137355, 4294416185, 4294346522, 4294278666, 4294277376, 4294277376, 4294277376, 4294277376, 4294213647, 4293243263, 4292532696, 4292532954, 4292532954, 4292598747, 4292598747, 4292598747, 4292598747, 4292664540, 4292794579, 4293568616, 4294212357, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294414895, 4293890877, 3570425344, 4671303, 4671303, 4671303, 4671303, 3352387072, 4192301839, 4294282279, 4294019626, 4192302873, 4124139523, 1708088576, 4671303, 4671303, 67108864, 184549376, 285212672, 385875968, 486539264, 638387968, 3888864256, 4276847393, 4294414896, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4293954086, 4293502050, 4293179274, 4292855728, 4292662218, 4292920489, 4293243778, 4293501275, 4294083608, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294345491, 4294420571, 4107626251, 1322146816, 4671303, 4671303, 4671303, 4671303, 382819584, 3134217472, 4191116288, 3939458560, 2211470592, 533617152, 4671303, 4671303, 117440512, 218103808, 335544320, 436207616, 553648128, 654311424, 771751936, 1534079488, 4157496833, 4294219326, 4294346523, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294278150, 4294485590, 4175527207, 2932497152, 117440512, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 50298880, 33488896, 4671303, 4671303, 4671303, 83886080, 201326592, 318767104, 436207616, 553648128, 671088640, 788529152, 889192448, 1006632960, 2493203712, 4157958415, 4294352457, 4294347039, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294278924, 4294486105, 4260073533, 3872218112, 525476096, 218103808, 100663296, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 16777216, 134217728, 251658240, 369098752, 486539264, 603979776, 721420288, 855638016, 973078528, 1090519040, 1207959552, 2930002688, 4174604044, 4294221386, 4294414637, 4294277634, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294346522, 4294552931, 4226189107, 3888929792, 997536768, 385875968, 251658240, 150994944, 16777216, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 16777216, 134217728, 251658240, 369098752, 486539264, 603979776, 721420288, 855638016, 956301312, 1073741824, 1191182336, 1325400064, 2693873664, 4191117319, 4293891393, 4294485073, 4294347296, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294344717, 4294484299, 4294421863, 4208884260, 3687340544, 910958848, 503316480, 385875968, 251658240, 134217728, 16777216, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 83886080, 201326592, 318767104, 436207616, 536870912, 671088640, 771751936, 889192448, 989855744, 1107296256, 1207959552, 1325400064, 2187996928, 3972487680, 4191711513, 4294156111, 4294485591, 4294415926, 4294346007, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294277376, 4294278408, 4294414379, 4294484817, 4294554221, 4259941691, 4157628420, 2746568960, 807735296, 553648128, 436207616, 318767104, 218103808, 83886080, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 100663296, 218103808, 318767104, 436207616, 536870912, 637534208, 754974720, 855638016, 956301312, 1040187392, 1140850688, 1224736768, 1342833408, 2677293568, 4174142464, 4157959447, 4276718648, 4294288986, 4294554220, 4294552415, 4294485074, 4294484300, 4294551641, 4294553705, 4294554738, 4294025043, 4175528237, 4174405895, 3384956928, 1264790528, 654311424, 553648128, 436207616, 335544320, 218103808, 117440512, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 50331648, 167772160, 268435456, 385875968, 469762048, 553648128, 654311424, 738197504, 822083584, 905969664, 973078528, 1023410176, 1090519040, 1208878848, 2054632960, 3165868032, 4123810816, 4224671493, 4157762069, 4124604196, 4141644844, 4124471839, 4174538769, 4241448451, 3586611712, 2275493888, 1078731776, 671088640, 570425344, 486539264, 385875968, 285212672, 184549376, 67108864, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 67108864, 167772160, 251658240, 335544320, 419430400, 503316480, 570425344, 637534208, 704643072, 738197504, 788529152, 822083584, 855638016, 872415232, 889192448, 1042616320, 1365125376, 1702770688, 1821064448, 1467299072, 1095443200, 738985472, 637534208, 587202560, 503316480, 436207616, 352321536, 268435456, 184549376, 67108864, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 16777216, 67108864, 150994944, 234881024, 301989888, 352321536, 402653184, 452984832, 486539264, 520093696, 536870912, 553648128, 570425344, 570425344, 553648128, 536870912, 520093696, 486539264, 452984832, 402653184, 352321536, 301989888, 234881024, 167772160, 67108864, 16777216, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 50331648, 83886080, 134217728, 167772160, 201326592, 218103808, 234881024, 251658240, 251658240, 234881024, 218103808, 201326592, 167772160, 134217728, 83886080, 50331648, 16777216, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, }; GLXContext GHOST_WindowX11::s_firstContext = NULL; GHOST_WindowX11:: GHOST_WindowX11( GHOST_SystemX11 *system, Display *display, const STR_String& title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, const GHOST_TEmbedderWindowID parentWindow, GHOST_TDrawingContextType type, const bool stereoVisual, const bool exclusive, const GHOST_TUns16 numOfAASamples) : GHOST_Window(width, height, state, type, stereoVisual, exclusive, numOfAASamples), m_context(NULL), m_display(display), m_normal_state(GHOST_kWindowStateNormal), m_system(system), m_valid_setup(false), m_invalid_window(false), m_empty_cursor(None), m_custom_cursor(None), m_visible_cursor(None) { /* Set up the minimum attributes that we require and see if * X can find us a visual matching those requirements. */ int attributes[40], i, samples; int natom; int glxVersionMajor, glxVersionMinor; /* As in GLX major.minor */ m_visual = NULL; if (!glXQueryVersion(m_display, &glxVersionMajor, &glxVersionMinor)) { printf("%s:%d: X11 glXQueryVersion() failed, verify working openGL system!\n", __FILE__, __LINE__); /* exit if this is the first window */ if (s_firstContext == NULL) { printf("initial window could not find the GLX extension, exit!\n"); exit(1); } return; } /* Find the display with highest samples, starting at level requested */ for (samples = m_numOfAASamples; samples >= 0; samples--) { i = 0; /* Reusing attributes array, so reset counter */ if (m_stereoVisual) attributes[i++] = GLX_STEREO; attributes[i++] = GLX_RGBA; attributes[i++] = GLX_DOUBLEBUFFER; attributes[i++] = GLX_RED_SIZE; attributes[i++] = 1; attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1; attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1; attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1; #ifdef GHOST_OPENGL_ALPHA attributes[i++] = GLX_ALPHA_SIZE; attributes[i++] = 1; #endif /* GLX >= 1.4 required for multi-sample */ if (samples && (glxVersionMajor >= 1) && (glxVersionMinor >= 4)) { attributes[i++] = GLX_SAMPLE_BUFFERS; attributes[i++] = 1; attributes[i++] = GLX_SAMPLES; attributes[i++] = samples; } attributes[i] = None; m_visual = glXChooseVisual(m_display, DefaultScreen(m_display), attributes); /* Any sample level or even zero, which means oversampling disabled, is good * but we need a valid visual to continue */ if (m_visual == NULL) { if (samples == 0) { /* All options exhausted, cannot continue */ printf("%s:%d: X11 glXChooseVisual() failed, verify working openGL system!\n", __FILE__, __LINE__); if (s_firstContext == NULL) { printf("initial window could not find the GLX extension, exit!\n"); exit(1); } return; } } else { if (m_numOfAASamples && (m_numOfAASamples > samples)) { printf("%s:%d: oversampling requested %i but using %i samples\n", __FILE__, __LINE__, m_numOfAASamples, samples); } break; } } /* Create a bunch of attributes needed to create an X window. */ /* First create a colormap for the window and visual. * This seems pretty much a legacy feature as we are in rgba mode anyway. */ XSetWindowAttributes xattributes; unsigned int xattributes_valuemask = (CWBorderPixel | CWColormap | CWEventMask); memset(&xattributes, 0, sizeof(xattributes)); xattributes.colormap = XCreateColormap(m_display, RootWindow(m_display, m_visual->screen), m_visual->visual, AllocNone ); xattributes.border_pixel = 0; /* Specify which events we are interested in hearing. */ xattributes.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | PropertyChangeMask | KeymapStateMask; if (exclusive) { xattributes_valuemask |= CWOverrideRedirect; xattributes.override_redirect = True; } /* create the window! */ if (parentWindow == 0) { m_window = XCreateWindow(m_display, RootWindow(m_display, m_visual->screen), left, top, width, height, 0, /* no border. */ m_visual->depth, InputOutput, m_visual->visual, xattributes_valuemask, &xattributes ); } else { Window root_return; int x_return, y_return; unsigned int w_return, h_return, border_w_return, depth_return; XGetGeometry(m_display, parentWindow, &root_return, &x_return, &y_return, &w_return, &h_return, &border_w_return, &depth_return); left = 0; top = 0; width = w_return; height = h_return; m_window = XCreateWindow(m_display, parentWindow, /* reparent against embedder */ left, top, width, height, 0, /* no border. */ m_visual->depth, InputOutput, m_visual->visual, xattributes_valuemask, &xattributes ); XSelectInput(m_display, parentWindow, SubstructureNotifyMask); } #ifdef WITH_XDND /* initialize drop target for newly created window */ m_dropTarget = new GHOST_DropTargetX11(this, m_system); GHOST_PRINT("Set drop target\n"); #endif if (state == GHOST_kWindowStateMaximized || state == GHOST_kWindowStateFullScreen) { Atom _NET_WM_STATE = XInternAtom(m_display, "_NET_WM_STATE", False); Atom _NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); Atom _NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(m_display, "_NET_WM_STATE_FULLSCREEN", False); Atom atoms[2]; int count = 0; if (state == GHOST_kWindowStateMaximized) { atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT; atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ; } else { atoms[count++] = _NET_WM_STATE_FULLSCREEN; } XChangeProperty(m_display, m_window, _NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, count); m_post_init = False; } /* * One of the problem with WM-spec is that can't set a property * to a window that isn't mapped. That is why we can't "just * call setState" here. * * To fix this, we first need know that the window is really * map waiting for the MapNotify event. * * So, m_post_init indicate that we need wait for the MapNotify * event and then set the Window state to the m_post_state. */ else if ((state != GHOST_kWindowStateNormal) && (state != GHOST_kWindowStateMinimized)) { m_post_init = True; m_post_state = state; } else { m_post_init = False; m_post_state = GHOST_kWindowStateNormal; } /* Create some hints for the window manager on how * we want this window treated. */ XSizeHints *xsizehints = XAllocSizeHints(); xsizehints->flags = PPosition | PSize | PMinSize | PMaxSize; xsizehints->x = left; xsizehints->y = top; xsizehints->width = width; xsizehints->height = height; xsizehints->min_width = 320; /* size hints, could be made apart of the ghost api */ xsizehints->min_height = 240; /* limits are also arbitrary, but should not allow 1x1 window */ xsizehints->max_width = 65535; xsizehints->max_height = 65535; XSetWMNormalHints(m_display, m_window, xsizehints); XFree(xsizehints); XClassHint *xclasshint = XAllocClassHint(); const int len = title.Length() + 1; char *wmclass = (char *)malloc(sizeof(char) * len); strncpy(wmclass, (const char *)title, sizeof(char) * len); xclasshint->res_name = wmclass; xclasshint->res_class = wmclass; XSetClassHint(m_display, m_window, xclasshint); free(wmclass); XFree(xclasshint); /* The basic for a good ICCCM "work" */ if (m_system->m_atom.WM_PROTOCOLS) { Atom atoms[2]; natom = 0; if (m_system->m_atom.WM_DELETE_WINDOW) { atoms[natom] = m_system->m_atom.WM_DELETE_WINDOW; natom++; } if (m_system->m_atom.WM_TAKE_FOCUS) { atoms[natom] = m_system->m_atom.WM_TAKE_FOCUS; natom++; } if (natom) { /* printf("Register atoms: %d\n", natom); */ XSetWMProtocols(m_display, m_window, atoms, natom); } } #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) m_xic = NULL; #endif /* Set the window hints */ XWMHints *xwmhints = XAllocWMHints(); xwmhints->initial_state = NormalState; xwmhints->input = True; xwmhints->flags = InputHint | StateHint; XSetWMHints(display, m_window, xwmhints); XFree(xwmhints); /* done setting the hints */ /* set the icon */ Atom _NET_WM_ICON = XInternAtom(m_display, "_NET_WM_ICON", False); XChangeProperty(m_display, m_window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)BLENDER_ICON_48x48x32, BLENDER_ICON_48x48x32[0] * BLENDER_ICON_48x48x32[1] + 2); /* done setting the icon */ setTitle(title); #ifdef WITH_X11_XINPUT initXInputDevices(); m_tabletData.Active = GHOST_kTabletModeNone; #endif /* now set up the rendering context. */ if (installDrawingContext(type) == GHOST_kSuccess) { m_valid_setup = true; GHOST_PRINT("Created window\n"); } if (exclusive) { XMapRaised(m_display, m_window); } else { XMapWindow(m_display, m_window); } GHOST_PRINT("Mapped window\n"); XFlush(m_display); } #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) static void destroyICCallback(XIC xic, XPointer ptr, XPointer data) { GHOST_PRINT("XIM input context destroyed\n"); if (ptr) { *(XIC *)ptr = NULL; } } bool GHOST_WindowX11::createX11_XIC() { XIM xim = m_system->getX11_XIM(); if (!xim) return false; XICCallback destroy; destroy.callback = (XICProc)destroyICCallback; destroy.client_data = (XPointer)&m_xic; m_xic = XCreateIC(xim, XNClientWindow, m_window, XNFocusWindow, m_window, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNResourceName, GHOST_X11_RES_NAME, XNResourceClass, GHOST_X11_RES_CLASS, XNDestroyCallback, &destroy, NULL); if (!m_xic) return false; unsigned long fevent; XGetICValues(m_xic, XNFilterEvents, &fevent, NULL); XSelectInput(m_display, m_window, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | PropertyChangeMask | KeymapStateMask | fevent); return true; } #endif #ifdef WITH_X11_XINPUT void GHOST_WindowX11::initXInputDevices() { XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); if (version && (version != (XExtensionVersion *)NoSuchExtension)) { if (version->present) { GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); XEventClass xevents[10], ev; int dcount = 0; if (xtablet.StylusDevice) { DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); if (ev) xevents[dcount++] = ev; ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); if (ev) xevents[dcount++] = ev; ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); if (ev) xevents[dcount++] = ev; } if (xtablet.EraserDevice) { DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEvent, ev); if (ev) xevents[dcount++] = ev; ProximityIn(xtablet.EraserDevice, xtablet.ProxInEvent, ev); if (ev) xevents[dcount++] = ev; ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEvent, ev); if (ev) xevents[dcount++] = ev; } XSelectExtensionEvent(m_display, m_window, xevents, dcount); } XFree(version); } } #endif /* WITH_X11_XINPUT */ Window GHOST_WindowX11:: getXWindow() { return m_window; } bool GHOST_WindowX11:: getValid() const { return m_valid_setup; } void GHOST_WindowX11:: setTitle( const STR_String& title) { Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0); Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0); XChangeProperty(m_display, m_window, name, utf8str, 8, PropModeReplace, (const unsigned char *) title.ReadPtr(), title.Length()); /* This should convert to valid x11 string * and getTitle would need matching change */ XStoreName(m_display, m_window, title); XFlush(m_display); } void GHOST_WindowX11:: getTitle( STR_String& title) const { char *name = NULL; XFetchName(m_display, m_window, &name); title = name ? name : "untitled"; XFree(name); } void GHOST_WindowX11:: getWindowBounds( GHOST_Rect& bounds) const { /* Getting the window bounds under X11 is not * really supported (nor should it be desired). */ getClientBounds(bounds); } void GHOST_WindowX11:: getClientBounds( GHOST_Rect& bounds) const { Window root_return; int x_return, y_return; unsigned int w_return, h_return, border_w_return, depth_return; GHOST_TInt32 screen_x, screen_y; XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return, &w_return, &h_return, &border_w_return, &depth_return); clientToScreen(0, 0, screen_x, screen_y); bounds.m_l = screen_x; bounds.m_r = bounds.m_l + w_return; bounds.m_t = screen_y; bounds.m_b = bounds.m_t + h_return; } GHOST_TSuccess GHOST_WindowX11:: setClientWidth( GHOST_TUns32 width) { XWindowChanges values; unsigned int value_mask = CWWidth; values.width = width; XConfigureWindow(m_display, m_window, value_mask, &values); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setClientHeight( GHOST_TUns32 height) { XWindowChanges values; unsigned int value_mask = CWHeight; values.height = height; XConfigureWindow(m_display, m_window, value_mask, &values); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setClientSize( GHOST_TUns32 width, GHOST_TUns32 height) { XWindowChanges values; unsigned int value_mask = CWWidth | CWHeight; values.width = width; values.height = height; XConfigureWindow(m_display, m_window, value_mask, &values); return GHOST_kSuccess; } void GHOST_WindowX11:: screenToClient( GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const { /* This is correct! */ int ax, ay; Window temp; XTranslateCoordinates(m_display, RootWindow(m_display, m_visual->screen), m_window, inX, inY, &ax, &ay, &temp); outX = ax; outY = ay; } void GHOST_WindowX11:: clientToScreen( GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const { int ax, ay; Window temp; XTranslateCoordinates( m_display, m_window, RootWindow(m_display, m_visual->screen), inX, inY, &ax, &ay, &temp); outX = ax; outY = ay; } void GHOST_WindowX11::icccmSetState(int state) { XEvent xev; if (state != IconicState) return; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.display = m_display; xev.xclient.window = m_window; xev.xclient.format = 32; xev.xclient.message_type = m_system->m_atom.WM_CHANGE_STATE; xev.xclient.data.l[0] = state; XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); } int GHOST_WindowX11::icccmGetState(void) const { unsigned char *prop_ret; unsigned long bytes_after, num_ret; Atom type_ret; int format_ret, st; prop_ret = NULL; st = XGetWindowProperty(m_display, m_window, m_system->m_atom.WM_STATE, 0, 0x7fffffff, False, m_system->m_atom.WM_STATE, &type_ret, &format_ret, &num_ret, &bytes_after, &prop_ret); if ((st == Success) && (prop_ret) && (num_ret == 2)) st = prop_ret[0]; else st = NormalState; if (prop_ret) XFree(prop_ret); return (st); } void GHOST_WindowX11::netwmMaximized(bool set) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = m_window; xev.xclient.message_type = m_system->m_atom._NET_WM_STATE; xev.xclient.format = 32; if (set == True) xev.xclient.data.l[0] = _NET_WM_STATE_ADD; else xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE; xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ; xev.xclient.data.l[2] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } bool GHOST_WindowX11::netwmIsMaximized(void) const { unsigned char *prop_ret; unsigned long bytes_after, num_ret, i; Atom type_ret; bool st; int format_ret, ret, count; prop_ret = NULL; st = False; ret = XGetWindowProperty(m_display, m_window, m_system->m_atom._NET_WM_STATE, 0, 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret, &num_ret, &bytes_after, &prop_ret); if ((ret == Success) && (prop_ret) && (format_ret == 32)) { count = 0; for (i = 0; i < num_ret; i++) { if (((unsigned long *) prop_ret)[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ) count++; if (((unsigned long *) prop_ret)[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT) count++; if (count == 2) { st = True; break; } } } if (prop_ret) XFree(prop_ret); return (st); } void GHOST_WindowX11::netwmFullScreen(bool set) { XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = m_window; xev.xclient.message_type = m_system->m_atom._NET_WM_STATE; xev.xclient.format = 32; if (set == True) xev.xclient.data.l[0] = _NET_WM_STATE_ADD; else xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE; xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_FULLSCREEN; xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } bool GHOST_WindowX11::netwmIsFullScreen(void) const { unsigned char *prop_ret; unsigned long bytes_after, num_ret, i; Atom type_ret; bool st; int format_ret, ret; prop_ret = NULL; st = False; ret = XGetWindowProperty(m_display, m_window, m_system->m_atom._NET_WM_STATE, 0, 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret, &num_ret, &bytes_after, &prop_ret); if ((ret == Success) && (prop_ret) && (format_ret == 32)) { for (i = 0; i < num_ret; i++) { if (((unsigned long *) prop_ret)[i] == m_system->m_atom._NET_WM_STATE_FULLSCREEN) { st = True; break; } } } if (prop_ret) XFree(prop_ret); return (st); } void GHOST_WindowX11::motifFullScreen(bool set) { MotifWmHints hints; hints.flags = MWM_HINTS_DECORATIONS; if (set == True) hints.decorations = 0; else hints.decorations = 1; XChangeProperty(m_display, m_window, m_system->m_atom._MOTIF_WM_HINTS, m_system->m_atom._MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char *) &hints, 4); } bool GHOST_WindowX11::motifIsFullScreen(void) const { unsigned char *prop_ret; unsigned long bytes_after, num_ret; MotifWmHints *hints; Atom type_ret; bool state; int format_ret, st; prop_ret = NULL; state = False; st = XGetWindowProperty(m_display, m_window, m_system->m_atom._MOTIF_WM_HINTS, 0, 0x7fffffff, False, m_system->m_atom._MOTIF_WM_HINTS, &type_ret, &format_ret, &num_ret, &bytes_after, &prop_ret); if ((st == Success) && (prop_ret)) { hints = (MotifWmHints *) prop_ret; if (hints->flags & MWM_HINTS_DECORATIONS) { if (!hints->decorations) state = True; } } if (prop_ret) XFree(prop_ret); return (state); } GHOST_TWindowState GHOST_WindowX11::getState() const { GHOST_TWindowState state_ret; int state; state_ret = GHOST_kWindowStateNormal; state = icccmGetState(); /* * In the Iconic and Withdrawn state, the window * is unmaped, so only need return a Minimized state. */ if ((state == IconicState) || (state == WithdrawnState)) state_ret = GHOST_kWindowStateMinimized; else if (netwmIsFullScreen() == True) state_ret = GHOST_kWindowStateFullScreen; else if (motifIsFullScreen() == True) state_ret = GHOST_kWindowStateFullScreen; else if (netwmIsMaximized() == True) state_ret = GHOST_kWindowStateMaximized; return (state_ret); } GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state) { GHOST_TWindowState cur_state; bool is_max, is_full, is_motif_full; cur_state = getState(); if (state == (int)cur_state) return GHOST_kSuccess; if (cur_state != GHOST_kWindowStateMinimized) { /* * The window don't have this property's * if it's not mapped. */ is_max = netwmIsMaximized(); is_full = netwmIsFullScreen(); } else { is_max = False; is_full = False; } is_motif_full = motifIsFullScreen(); if (state == GHOST_kWindowStateNormal) state = m_normal_state; if (state == GHOST_kWindowStateNormal) { if (is_max == True) netwmMaximized(False); if (is_full == True) netwmFullScreen(False); if (is_motif_full == True) motifFullScreen(False); icccmSetState(NormalState); return (GHOST_kSuccess); } if (state == GHOST_kWindowStateFullScreen) { /* * We can't change to full screen if the window * isn't mapped. */ if (cur_state == GHOST_kWindowStateMinimized) return (GHOST_kFailure); m_normal_state = cur_state; if (is_max == True) netwmMaximized(False); if (is_full == False) netwmFullScreen(True); if (is_motif_full == False) motifFullScreen(True); return (GHOST_kSuccess); } if (state == GHOST_kWindowStateMaximized) { /* * We can't change to Maximized if the window * isn't mapped. */ if (cur_state == GHOST_kWindowStateMinimized) return (GHOST_kFailure); if (is_full == True) netwmFullScreen(False); if (is_motif_full == True) motifFullScreen(False); if (is_max == False) netwmMaximized(True); return (GHOST_kSuccess); } if (state == GHOST_kWindowStateMinimized) { /* * The window manager need save the current state of * the window (maximized, full screen, etc). */ icccmSetState(IconicState); return (GHOST_kSuccess); } return (GHOST_kFailure); } #include GHOST_TSuccess GHOST_WindowX11:: setOrder( GHOST_TWindowOrder order) { if (order == GHOST_kWindowOrderTop) { XWindowAttributes attr; Atom atom; /* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some * window managers ignore the former (e.g. kwin from kde) and others * don't implement the latter (e.g. fluxbox pre 0.9.9) */ XRaiseWindow(m_display, m_window); atom = XInternAtom(m_display, "_NET_ACTIVE_WINDOW", True); if (atom != None) { Window root; XEvent xev; long eventmask; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.window = m_window; xev.xclient.message_type = atom; xev.xclient.format = 32; xev.xclient.data.l[0] = 1; xev.xclient.data.l[1] = CurrentTime; xev.xclient.data.l[2] = m_window; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; root = RootWindow(m_display, m_visual->screen), eventmask = SubstructureRedirectMask | SubstructureNotifyMask; XSendEvent(m_display, root, False, eventmask, &xev); } XGetWindowAttributes(m_display, m_window, &attr); /* iconized windows give bad match error */ if (attr.map_state == IsViewable) XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); XFlush(m_display); } else if (order == GHOST_kWindowOrderBottom) { XLowerWindow(m_display, m_window); XFlush(m_display); } else { return GHOST_kFailure; } return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: swapBuffers() { if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) { glXSwapBuffers(m_display, m_window); return GHOST_kSuccess; } else { return GHOST_kFailure; } } GHOST_TSuccess GHOST_WindowX11:: activateDrawingContext() { if (m_context != NULL) { glXMakeCurrent(m_display, m_window, m_context); /* Disable AA by default */ if (m_numOfAASamples > 0) { glDisable(GL_MULTISAMPLE_ARB); } return GHOST_kSuccess; } return GHOST_kFailure; } GHOST_TSuccess GHOST_WindowX11:: invalidate() { /* So the idea of this function is to generate an expose event * for the window. * Unfortunately X does not handle expose events for you and * it is the client's job to refresh the dirty part of the window. * We need to queue up invalidate calls and generate GHOST events * for them in the system. * * We implement this by setting a boolean in this class to concatenate * all such calls into a single event for this window. * * At the same time we queue the dirty windows in the system class * and generate events for them at the next processEvents call. */ if (m_invalid_window == false) { m_system->addDirtyWindow(this); m_invalid_window = true; } return GHOST_kSuccess; } /** * called by the X11 system implementation when expose events * for the window have been pushed onto the GHOST queue */ void GHOST_WindowX11:: validate() { m_invalid_window = false; } /** * Destructor. * Closes the window and disposes resources allocated. */ GHOST_WindowX11:: ~GHOST_WindowX11() { static Atom Primary_atom, Clipboard_atom; Window p_owner, c_owner; /*Change the owner of the Atoms to None if we are the owner*/ Primary_atom = XInternAtom(m_display, "PRIMARY", False); Clipboard_atom = XInternAtom(m_display, "CLIPBOARD", False); p_owner = XGetSelectionOwner(m_display, Primary_atom); c_owner = XGetSelectionOwner(m_display, Clipboard_atom); std::map::iterator it = m_standard_cursors.begin(); for (; it != m_standard_cursors.end(); ++it) { XFreeCursor(m_display, it->second); } if (m_empty_cursor) { XFreeCursor(m_display, m_empty_cursor); } if (m_custom_cursor) { XFreeCursor(m_display, m_custom_cursor); } if (m_context != s_firstContext) { glXDestroyContext(m_display, m_context); } if (p_owner == m_window) { XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime); } if (c_owner == m_window) { XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime); } #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) if (m_xic) { XDestroyIC(m_xic); } #endif #ifdef WITH_XDND delete m_dropTarget; #endif XDestroyWindow(m_display, m_window); XFree(m_visual); } /** * Tries to install a rendering context in this window. * \param type The type of rendering context installed. * \return Indication as to whether installation has succeeded. */ GHOST_TSuccess GHOST_WindowX11:: installDrawingContext( GHOST_TDrawingContextType type) { /* only support openGL for now. */ GHOST_TSuccess success; switch (type) { case GHOST_kDrawingContextTypeOpenGL: { #ifdef WITH_X11_XINPUT /* use our own event handlers to avoid exiting blender, * this would happen for eg: * if you open blender, unplug a tablet, then open a new window. */ XErrorHandler old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler); XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); #endif m_context = glXCreateContext(m_display, m_visual, s_firstContext, True); if (m_context != NULL) { if (!s_firstContext) { s_firstContext = m_context; } glXMakeCurrent(m_display, m_window, m_context); glClearColor(0.447, 0.447, 0.447, 0); glClear(GL_COLOR_BUFFER_BIT); success = GHOST_kSuccess; } else { success = GHOST_kFailure; } #ifdef WITH_X11_XINPUT /* Restore handler */ (void) XSetErrorHandler(old_handler); (void) XSetIOErrorHandler(old_handler_io); #endif break; } case GHOST_kDrawingContextTypeNone: { success = GHOST_kSuccess; break; } default: success = GHOST_kFailure; } return success; } /** * Removes the current drawing context. * \return Indication as to whether removal has succeeded. */ GHOST_TSuccess GHOST_WindowX11:: removeDrawingContext() { GHOST_TSuccess success; if (m_context != NULL) { glXDestroyContext(m_display, m_context); success = GHOST_kSuccess; } else { success = GHOST_kFailure; } return success; } Cursor GHOST_WindowX11:: getStandardCursor( GHOST_TStandardCursor g_cursor) { unsigned int xcursor_id; #define GtoX(gcurs, xcurs) case gcurs: xcursor_id = xcurs switch (g_cursor) { GtoX(GHOST_kStandardCursorRightArrow, XC_arrow); break; GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow); break; GtoX(GHOST_kStandardCursorInfo, XC_hand1); break; GtoX(GHOST_kStandardCursorDestroy, XC_pirate); break; GtoX(GHOST_kStandardCursorHelp, XC_question_arrow); break; GtoX(GHOST_kStandardCursorCycle, XC_exchange); break; GtoX(GHOST_kStandardCursorSpray, XC_spraycan); break; GtoX(GHOST_kStandardCursorWait, XC_watch); break; GtoX(GHOST_kStandardCursorText, XC_xterm); break; GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair); break; GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow); break; GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow); break; GtoX(GHOST_kStandardCursorTopSide, XC_top_side); break; GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side); break; GtoX(GHOST_kStandardCursorLeftSide, XC_left_side); break; GtoX(GHOST_kStandardCursorRightSide, XC_right_side); break; GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner); break; GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner); break; GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner); break; GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner); break; GtoX(GHOST_kStandardCursorPencil, XC_pencil); break; GtoX(GHOST_kStandardCursorCopy, XC_arrow); break; default: xcursor_id = 0; } #undef GtoX if (xcursor_id) { Cursor xcursor = m_standard_cursors[xcursor_id]; if (!xcursor) { xcursor = XCreateFontCursor(m_display, xcursor_id); m_standard_cursors[xcursor_id] = xcursor; } return xcursor; } else { return None; } } Cursor GHOST_WindowX11:: getEmptyCursor( ) { if (!m_empty_cursor) { Pixmap blank; XColor dummy; char data[1] = {0}; /* make a blank cursor */ blank = XCreateBitmapFromData( m_display, RootWindow(m_display, DefaultScreen(m_display)), data, 1, 1 ); m_empty_cursor = XCreatePixmapCursor(m_display, blank, blank, &dummy, &dummy, 0, 0); XFreePixmap(m_display, blank); } return m_empty_cursor; } GHOST_TSuccess GHOST_WindowX11:: setWindowCursorVisibility( bool visible) { Cursor xcursor; if (visible) { if (m_visible_cursor) xcursor = m_visible_cursor; else xcursor = getStandardCursor(getCursorShape() ); } else { xcursor = getEmptyCursor(); } XDefineCursor(m_display, m_window, xcursor); XFlush(m_display); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setWindowCursorGrab( GHOST_TGrabCursorMode mode) { if (mode != GHOST_kGrabDisable) { if (mode != GHOST_kGrabNormal) { m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); setCursorGrabAccum(0, 0); if (mode == GHOST_kGrabHide) setWindowCursorVisibility(false); } #ifdef GHOST_X11_GRAB XGrabPointer(m_display, m_window, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); #endif } else { if (m_cursorGrab == GHOST_kGrabHide) { m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); setWindowCursorVisibility(true); } if (m_cursorGrab != GHOST_kGrabNormal) { /* use to generate a mouse move event, otherwise the last event * blender gets can be outside the screen causing menus not to show * properly unless the user moves the mouse */ XWarpPointer(m_display, None, None, 0, 0, 0, 0, 0, 0); } /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ setCursorGrabAccum(0, 0); m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */ #ifdef GHOST_X11_GRAB XUngrabPointer(m_display, CurrentTime); #endif } XFlush(m_display); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setWindowCursorShape( GHOST_TStandardCursor shape) { Cursor xcursor = getStandardCursor(shape); m_visible_cursor = xcursor; XDefineCursor(m_display, m_window, xcursor); XFlush(m_display); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setWindowCustomCursorShape( GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY) { setWindowCustomCursorShape((GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, 16, 16, hotX, hotY, 0, 1); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setWindowCustomCursorShape( GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) { Colormap colormap = DefaultColormap(m_display, DefaultScreen(m_display)); Pixmap bitmap_pix, mask_pix; XColor fg, bg; if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) return GHOST_kFailure; if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) return GHOST_kFailure; if (m_custom_cursor) { XFreeCursor(m_display, m_custom_cursor); } bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char *) bitmap, sizex, sizey); mask_pix = XCreateBitmapFromData(m_display, m_window, (char *) mask, sizex, sizey); m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY); XDefineCursor(m_display, m_window, m_custom_cursor); XFlush(m_display); m_visible_cursor = m_custom_cursor; XFreePixmap(m_display, bitmap_pix); XFreePixmap(m_display, mask_pix); XFreeColors(m_display, colormap, &fg.pixel, 1, 0L); XFreeColors(m_display, colormap, &bg.pixel, 1, 0L); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: beginFullScreen() const { { Window root_return; int x_return, y_return; unsigned int w_return, h_return, border_w_return, depth_return; XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return, &w_return, &h_return, &border_w_return, &depth_return); m_system->setCursorPosition(w_return / 2, h_return / 2); } /* Grab Keyboard & Mouse */ int err; err = XGrabKeyboard(m_display, m_window, False, GrabModeAsync, GrabModeAsync, CurrentTime); if (err != GrabSuccess) printf("XGrabKeyboard failed %d\n", err); err = XGrabPointer(m_display, m_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); if (err != GrabSuccess) printf("XGrabPointer failed %d\n", err); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: endFullScreen() const { XUngrabKeyboard(m_display, CurrentTime); XUngrabPointer(m_display, CurrentTime); return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowX11:: setSwapInterval(int interval) { if (!GLX_EXT_swap_control || !glXSwapIntervalEXT #ifdef SWAP_INTERVALS_WORKAROUND || g_swap_interval_disabled #endif // SWAP_INTERVALS_WORKAROUND ) { return GHOST_kFailure; } glXSwapIntervalEXT(m_display, m_window, interval); return GHOST_kSuccess; } #ifdef SWAP_INTERVALS_WORKAROUND static int QueryDrawable_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) { fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", theEvent->error_code, theEvent->request_code); if (!g_swap_interval_disabled) { fprintf(stderr, "Disabling SWAP INTERVALS extension\n"); g_swap_interval_disabled = true; } return 0; } static int QueryDrawable_ApplicationIOErrorHandler(Display *display) { fprintf(stderr, "Ignoring Xlib error: error IO\n"); if (!g_swap_interval_disabled) { fprintf(stderr, "Disabling SWAP INTERVALS extension\n"); g_swap_interval_disabled = true; } return 0; } #endif // SWAP_INTERVALS_WORKAROUND int GHOST_WindowX11:: getSwapInterval() { if (GLX_EXT_swap_control) { #ifdef SWAP_INTERVALS_WORKAROUND /* XXX: Current MESA driver will give GLXBadDrawable for all * the glXQueryDrawable requests with direct contexts. * * To prevent crashes and unexpected behaviors, we will * disable swap intervals extension if query fails here. * (because if we will override interval without having * old value we couldn't restore it properly). */ XErrorHandler old_handler = XSetErrorHandler(QueryDrawable_ApplicationErrorHandler); XIOErrorHandler old_handler_io = XSetIOErrorHandler(QueryDrawable_ApplicationIOErrorHandler); #endif // SWAP_INTERVALS_WORKAROUND unsigned int value = 0; glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &value); #ifdef SWAP_INTERVALS_WORKAROUND /* Restore handler */ (void) XSetErrorHandler(old_handler); (void) XSetIOErrorHandler(old_handler_io); #endif // SWAP_INTERVALS_WORKAROUND return (int)value; } return 0; }