xcompmgr.c 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379
  1. /*
  2. * Copyright © 2003 Keith Packard
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that
  7. * copyright notice and this permission notice appear in supporting
  8. * documentation, and that the name of Keith Packard not be used in
  9. * advertising or publicity pertaining to distribution of the software without
  10. * specific, written prior permission. Keith Packard makes no
  11. * representations about the suitability of this software for any purpose. It
  12. * is provided "as is" without express or implied warranty.
  13. *
  14. * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20. * PERFORMANCE OF THIS SOFTWARE.
  21. */
  22. /* Modified by Matthew Hawn. I don't know what to say here so follow what it
  23. says above. Not that I can really do anything about it
  24. */
  25. #ifdef HAVE_CONFIG_H
  26. #include "config.h"
  27. #endif
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <math.h>
  32. #include <sys/poll.h>
  33. #include <sys/time.h>
  34. #include <time.h>
  35. #include <unistd.h>
  36. #include <getopt.h>
  37. #include <X11/Xlib.h>
  38. #include <X11/Xutil.h>
  39. #include <X11/Xatom.h>
  40. #include <X11/extensions/Xcomposite.h>
  41. #include <X11/extensions/Xdamage.h>
  42. #include <X11/extensions/Xrender.h>
  43. #include <X11/extensions/shape.h>
  44. #if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2
  45. #define HAS_NAME_WINDOW_PIXMAP 1
  46. #endif
  47. #define CAN_DO_USABLE 0
  48. typedef struct _ignore {
  49. struct _ignore *next;
  50. unsigned long sequence;
  51. } ignore;
  52. typedef struct _win {
  53. struct _win *next;
  54. Window id;
  55. #if HAS_NAME_WINDOW_PIXMAP
  56. Pixmap pixmap;
  57. #endif
  58. XWindowAttributes a;
  59. #if CAN_DO_USABLE
  60. Bool usable; /* mapped and all damaged at one point */
  61. XRectangle damage_bounds; /* bounds of damage */
  62. #endif
  63. int mode;
  64. int damaged;
  65. Damage damage;
  66. Picture picture;
  67. Picture alphaPict;
  68. Picture shadowPict;
  69. XserverRegion borderSize;
  70. XserverRegion extents;
  71. Picture shadow;
  72. int shadow_dx;
  73. int shadow_dy;
  74. int shadow_width;
  75. int shadow_height;
  76. unsigned int opacity;
  77. Atom windowType;
  78. unsigned long damage_sequence; /* sequence when damage was created */
  79. Bool shaped;
  80. XRectangle shape_bounds;
  81. /* for drawing translucent windows */
  82. XserverRegion borderClip;
  83. struct _win *prev_trans;
  84. } win;
  85. typedef struct _conv {
  86. int size;
  87. double *data;
  88. } conv;
  89. typedef struct _fade {
  90. struct _fade *next;
  91. win *w;
  92. double cur;
  93. double finish;
  94. double step;
  95. void (*callback) (Display *dpy, win *w, Bool gone);
  96. Display *dpy;
  97. Bool gone;
  98. } fade;
  99. static win *list;
  100. static fade *fades;
  101. static int scr;
  102. static Window root;
  103. static Picture rootPicture;
  104. static Picture rootBuffer;
  105. static Picture blackPicture;
  106. static Picture transBlackPicture;
  107. static Picture rootTile;
  108. static XserverRegion allDamage;
  109. static Bool clipChanged;
  110. #if HAS_NAME_WINDOW_PIXMAP
  111. static Bool hasNamePixmap;
  112. #endif
  113. static int root_height, root_width;
  114. static ignore *ignore_head, **ignore_tail = &ignore_head;
  115. static int xfixes_event, xfixes_error;
  116. static int damage_event, damage_error;
  117. static int composite_event, composite_error;
  118. static int render_event, render_error;
  119. static int xshape_event, xshape_error;
  120. static Bool synchronize;
  121. static int composite_opcode;
  122. /* find these once and be done with it */
  123. static Atom opacityAtom;
  124. static Atom winTypeAtom;
  125. static Atom winDesktopAtom;
  126. static Atom winDockAtom;
  127. static Atom winToolbarAtom;
  128. static Atom winMenuAtom;
  129. static Atom winUtilAtom;
  130. static Atom winSplashAtom;
  131. static Atom winDialogAtom;
  132. static Atom winNormalAtom;
  133. /* opacity property name; sometime soon I'll write up an EWMH spec for it */
  134. #define OPACITY_PROP "_NET_WM_WINDOW_OPACITY"
  135. #define TRANSLUCENT 0xe0000000
  136. #define OPAQUE 0xffffffff
  137. static conv *gaussianMap;
  138. #define WINDOW_SOLID 0
  139. #define WINDOW_TRANS 1
  140. #define WINDOW_ARGB 2
  141. #define TRANS_OPACITY 0.75
  142. #define DEBUG_REPAINT 0
  143. #define DEBUG_EVENTS 0
  144. #define DEBUG_SHAPE 0
  145. #define MONITOR_REPAINT 0
  146. #define SHADOWS 1
  147. #define SHARP_SHADOW 0
  148. typedef enum _compMode {
  149. CompSimple, /* looks like a regular X server */
  150. CompServerShadows, /* use window alpha for shadow; sharp, but precise */
  151. CompClientShadows, /* use window extents for shadow, blurred */
  152. } CompMode;
  153. static void
  154. determine_mode(Display *dpy, win *w);
  155. static double
  156. get_opacity_percent(Display *dpy, win *w, double def);
  157. static XserverRegion
  158. win_extents (Display *dpy, win *w);
  159. static CompMode compMode = CompSimple;
  160. static int shadowRadius = 12;
  161. static int shadowOffsetX = -15;
  162. static int shadowOffsetY = -15;
  163. static double shadowOpacity = .75;
  164. static double fade_in_step = 0.028;
  165. static double fade_out_step = 0.03;
  166. static int fade_delta = 10;
  167. static int fade_time = 0;
  168. static Bool fadeWindows = False;
  169. static Bool excludeDockShadows = False;
  170. static Bool fadeTrans = False;
  171. static Bool autoRedirect = False;
  172. /* For shadow precomputation */
  173. static int Gsize = -1;
  174. static unsigned char *shadowCorner = NULL;
  175. static unsigned char *shadowTop = NULL;
  176. static int
  177. get_time_in_milliseconds (void)
  178. {
  179. struct timeval tv;
  180. gettimeofday (&tv, NULL);
  181. return tv.tv_sec * 1000 + tv.tv_usec / 1000;
  182. }
  183. static fade *
  184. find_fade (win *w)
  185. {
  186. fade *f;
  187. for (f = fades; f; f = f->next)
  188. {
  189. if (f->w == w)
  190. return f;
  191. }
  192. return NULL;
  193. }
  194. static void
  195. dequeue_fade (Display *dpy, fade *f)
  196. {
  197. fade **prev;
  198. for (prev = &fades; *prev; prev = &(*prev)->next)
  199. if (*prev == f)
  200. {
  201. *prev = f->next;
  202. if (f->callback)
  203. (*f->callback) (dpy, f->w, f->gone);
  204. free (f);
  205. break;
  206. }
  207. }
  208. static void
  209. cleanup_fade (Display *dpy, win *w)
  210. {
  211. fade *f = find_fade (w);
  212. if (f)
  213. dequeue_fade (dpy, f);
  214. }
  215. static void
  216. enqueue_fade (Display *dpy, fade *f)
  217. {
  218. if (!fades)
  219. fade_time = get_time_in_milliseconds () + fade_delta;
  220. f->next = fades;
  221. fades = f;
  222. }
  223. static void
  224. set_fade (Display *dpy, win *w, double start, double finish, double step,
  225. void (*callback) (Display *dpy, win *w, Bool gone),
  226. Bool gone, Bool exec_callback, Bool override)
  227. {
  228. fade *f;
  229. f = find_fade (w);
  230. if (!f)
  231. {
  232. f = malloc (sizeof (fade));
  233. f->next = NULL;
  234. f->w = w;
  235. f->cur = start;
  236. enqueue_fade (dpy, f);
  237. }
  238. else if(!override)
  239. return;
  240. else
  241. {
  242. if (exec_callback)
  243. if (f->callback)
  244. (*f->callback)(dpy, f->w, f->gone);
  245. }
  246. if (finish < 0)
  247. finish = 0;
  248. if (finish > 1)
  249. finish = 1;
  250. f->finish = finish;
  251. if (f->cur < finish)
  252. f->step = step;
  253. else if (f->cur > finish)
  254. f->step = -step;
  255. f->callback = callback;
  256. f->gone = gone;
  257. w->opacity = f->cur * OPAQUE;
  258. #if 0
  259. printf ("set_fade start %g step %g\n", f->cur, f->step);
  260. #endif
  261. determine_mode (dpy, w);
  262. if (w->shadow)
  263. {
  264. XRenderFreePicture (dpy, w->shadow);
  265. w->shadow = None;
  266. w->extents = win_extents (dpy, w);
  267. }
  268. }
  269. static int
  270. fade_timeout (void)
  271. {
  272. int now;
  273. int delta;
  274. if (!fades)
  275. return -1;
  276. now = get_time_in_milliseconds();
  277. delta = fade_time - now;
  278. if (delta < 0)
  279. delta = 0;
  280. /* printf ("timeout %d\n", delta); */
  281. return delta;
  282. }
  283. static void
  284. run_fades (Display *dpy)
  285. {
  286. int now = get_time_in_milliseconds();
  287. fade *next = fades;
  288. int steps;
  289. Bool need_dequeue;
  290. #if 0
  291. printf ("run fades\n");
  292. #endif
  293. if (fade_time - now > 0)
  294. return;
  295. steps = 1 + (now - fade_time) / fade_delta;
  296. while (next)
  297. {
  298. fade *f = next;
  299. win *w = f->w;
  300. next = f->next;
  301. f->cur += f->step * steps;
  302. if (f->cur >= 1)
  303. f->cur = 1;
  304. else if (f->cur < 0)
  305. f->cur = 0;
  306. #if 0
  307. printf ("opacity now %g\n", f->cur);
  308. #endif
  309. w->opacity = f->cur * OPAQUE;
  310. need_dequeue = False;
  311. if (f->step > 0)
  312. {
  313. if (f->cur >= f->finish)
  314. {
  315. w->opacity = f->finish*OPAQUE;
  316. need_dequeue = True;
  317. }
  318. }
  319. else
  320. {
  321. if (f->cur <= f->finish)
  322. {
  323. w->opacity = f->finish*OPAQUE;
  324. need_dequeue = True;
  325. }
  326. }
  327. determine_mode (dpy, w);
  328. if (w->shadow)
  329. {
  330. XRenderFreePicture (dpy, w->shadow);
  331. w->shadow = None;
  332. w->extents = win_extents(dpy, w);
  333. }
  334. /* Must do this last as it might destroy f->w in callbacks */
  335. if (need_dequeue)
  336. dequeue_fade (dpy, f);
  337. }
  338. fade_time = now + fade_delta;
  339. }
  340. static double
  341. gaussian (double r, double x, double y)
  342. {
  343. return ((1 / (sqrt (2 * M_PI * r))) *
  344. exp ((- (x * x + y * y)) / (2 * r * r)));
  345. }
  346. static conv *
  347. make_gaussian_map (Display *dpy, double r)
  348. {
  349. conv *c;
  350. int size = ((int) ceil ((r * 3)) + 1) & ~1;
  351. int center = size / 2;
  352. int x, y;
  353. double t;
  354. double g;
  355. c = malloc (sizeof (conv) + size * size * sizeof (double));
  356. c->size = size;
  357. c->data = (double *) (c + 1);
  358. t = 0.0;
  359. for (y = 0; y < size; y++)
  360. for (x = 0; x < size; x++)
  361. {
  362. g = gaussian (r, (double) (x - center), (double) (y - center));
  363. t += g;
  364. c->data[y * size + x] = g;
  365. }
  366. /* printf ("gaussian total %f\n", t); */
  367. for (y = 0; y < size; y++)
  368. for (x = 0; x < size; x++)
  369. {
  370. c->data[y*size + x] /= t;
  371. }
  372. return c;
  373. }
  374. /*
  375. * A picture will help
  376. *
  377. * -center 0 width width+center
  378. * -center +-----+-------------------+-----+
  379. * | | | |
  380. * | | | |
  381. * 0 +-----+-------------------+-----+
  382. * | | | |
  383. * | | | |
  384. * | | | |
  385. * height +-----+-------------------+-----+
  386. * | | | |
  387. * height+ | | | |
  388. * center +-----+-------------------+-----+
  389. */
  390. static unsigned char
  391. sum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
  392. {
  393. int fx, fy;
  394. double *g_data;
  395. double *g_line = map->data;
  396. int g_size = map->size;
  397. int center = g_size / 2;
  398. int fx_start, fx_end;
  399. int fy_start, fy_end;
  400. double v;
  401. /*
  402. * Compute set of filter values which are "in range",
  403. * that's the set with:
  404. * 0 <= x + (fx-center) && x + (fx-center) < width &&
  405. * 0 <= y + (fy-center) && y + (fy-center) < height
  406. *
  407. * 0 <= x + (fx - center) x + fx - center < width
  408. * center - x <= fx fx < width + center - x
  409. */
  410. fx_start = center - x;
  411. if (fx_start < 0)
  412. fx_start = 0;
  413. fx_end = width + center - x;
  414. if (fx_end > g_size)
  415. fx_end = g_size;
  416. fy_start = center - y;
  417. if (fy_start < 0)
  418. fy_start = 0;
  419. fy_end = height + center - y;
  420. if (fy_end > g_size)
  421. fy_end = g_size;
  422. g_line = g_line + fy_start * g_size + fx_start;
  423. v = 0;
  424. for (fy = fy_start; fy < fy_end; fy++)
  425. {
  426. g_data = g_line;
  427. g_line += g_size;
  428. for (fx = fx_start; fx < fx_end; fx++)
  429. v += *g_data++;
  430. }
  431. if (v > 1)
  432. v = 1;
  433. return ((unsigned char) (v * opacity * 255.0));
  434. }
  435. /* precompute shadow corners and sides to save time for large windows */
  436. static void
  437. presum_gaussian (conv *map)
  438. {
  439. int center = map->size/2;
  440. int opacity, x, y;
  441. Gsize = map->size;
  442. if (shadowCorner)
  443. free ((void *)shadowCorner);
  444. if (shadowTop)
  445. free ((void *)shadowTop);
  446. shadowCorner = (unsigned char *)(malloc ((Gsize + 1) * (Gsize + 1) * 26));
  447. shadowTop = (unsigned char *)(malloc ((Gsize + 1) * 26));
  448. for (x = 0; x <= Gsize; x++)
  449. {
  450. shadowTop[25 * (Gsize + 1) + x] = sum_gaussian (map, 1, x - center, center, Gsize * 2, Gsize * 2);
  451. for(opacity = 0; opacity < 25; opacity++)
  452. shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25;
  453. for(y = 0; y <= x; y++)
  454. {
  455. shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
  456. = sum_gaussian (map, 1, x - center, y - center, Gsize * 2, Gsize * 2);
  457. shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
  458. = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
  459. for(opacity = 0; opacity < 25; opacity++)
  460. shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
  461. = shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
  462. = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25;
  463. }
  464. }
  465. }
  466. static XImage *
  467. make_shadow (Display *dpy, double opacity, int width, int height)
  468. {
  469. XImage *ximage;
  470. unsigned char *data;
  471. int gsize = gaussianMap->size;
  472. int ylimit, xlimit;
  473. int swidth = width + gsize;
  474. int sheight = height + gsize;
  475. int center = gsize / 2;
  476. int x, y;
  477. unsigned char d;
  478. int x_diff;
  479. int opacity_int = (int)(opacity * 25);
  480. data = malloc (swidth * sheight * sizeof (unsigned char));
  481. if (!data)
  482. return NULL;
  483. ximage = XCreateImage (dpy,
  484. DefaultVisual(dpy, DefaultScreen(dpy)),
  485. 8,
  486. ZPixmap,
  487. 0,
  488. (char *) data,
  489. swidth, sheight, 8, swidth * sizeof (unsigned char));
  490. if (!ximage)
  491. {
  492. free (data);
  493. return NULL;
  494. }
  495. /*
  496. * Build the gaussian in sections
  497. */
  498. /*
  499. * center (fill the complete data array)
  500. */
  501. if (Gsize > 0)
  502. d = shadowTop[opacity_int * (Gsize + 1) + Gsize];
  503. else
  504. d = sum_gaussian (gaussianMap, opacity, center, center, width, height);
  505. memset(data, d, sheight * swidth);
  506. /*
  507. * corners
  508. */
  509. ylimit = gsize;
  510. if (ylimit > sheight / 2)
  511. ylimit = (sheight + 1) / 2;
  512. xlimit = gsize;
  513. if (xlimit > swidth / 2)
  514. xlimit = (swidth + 1) / 2;
  515. for (y = 0; y < ylimit; y++)
  516. for (x = 0; x < xlimit; x++)
  517. {
  518. if (xlimit == Gsize && ylimit == Gsize)
  519. d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
  520. else
  521. d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height);
  522. data[y * swidth + x] = d;
  523. data[(sheight - y - 1) * swidth + x] = d;
  524. data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
  525. data[y * swidth + (swidth - x - 1)] = d;
  526. }
  527. /*
  528. * top/bottom
  529. */
  530. x_diff = swidth - (gsize * 2);
  531. if (x_diff > 0 && ylimit > 0)
  532. {
  533. for (y = 0; y < ylimit; y++)
  534. {
  535. if (ylimit == Gsize)
  536. d = shadowTop[opacity_int * (Gsize + 1) + y];
  537. else
  538. d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height);
  539. memset (&data[y * swidth + gsize], d, x_diff);
  540. memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
  541. }
  542. }
  543. /*
  544. * sides
  545. */
  546. for (x = 0; x < xlimit; x++)
  547. {
  548. if (xlimit == Gsize)
  549. d = shadowTop[opacity_int * (Gsize + 1) + x];
  550. else
  551. d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height);
  552. for (y = gsize; y < sheight - gsize; y++)
  553. {
  554. data[y * swidth + x] = d;
  555. data[y * swidth + (swidth - x - 1)] = d;
  556. }
  557. }
  558. return ximage;
  559. }
  560. static Picture
  561. shadow_picture (Display *dpy, double opacity, Picture alpha_pict, int width, int height, int *wp, int *hp)
  562. {
  563. XImage *shadowImage;
  564. Pixmap shadowPixmap;
  565. Picture shadowPicture;
  566. GC gc;
  567. shadowImage = make_shadow (dpy, opacity, width, height);
  568. if (!shadowImage)
  569. return None;
  570. shadowPixmap = XCreatePixmap (dpy, root,
  571. shadowImage->width,
  572. shadowImage->height,
  573. 8);
  574. if (!shadowPixmap)
  575. {
  576. XDestroyImage (shadowImage);
  577. return None;
  578. }
  579. shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
  580. XRenderFindStandardFormat (dpy, PictStandardA8),
  581. 0, NULL);
  582. if (!shadowPicture)
  583. {
  584. XDestroyImage (shadowImage);
  585. XFreePixmap (dpy, shadowPixmap);
  586. return (Picture)None;
  587. }
  588. gc = XCreateGC (dpy, shadowPixmap, 0, NULL);
  589. if (!gc)
  590. {
  591. XDestroyImage (shadowImage);
  592. XFreePixmap (dpy, shadowPixmap);
  593. XRenderFreePicture (dpy, shadowPicture);
  594. return (Picture)None;
  595. }
  596. XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
  597. shadowImage->width,
  598. shadowImage->height);
  599. *wp = shadowImage->width;
  600. *hp = shadowImage->height;
  601. XFreeGC (dpy, gc);
  602. XDestroyImage (shadowImage);
  603. XFreePixmap (dpy, shadowPixmap);
  604. return shadowPicture;
  605. }
  606. static Picture
  607. solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b)
  608. {
  609. Pixmap pixmap;
  610. Picture picture;
  611. XRenderPictureAttributes pa;
  612. XRenderColor c;
  613. pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8);
  614. if (!pixmap)
  615. return None;
  616. pa.repeat = True;
  617. picture = XRenderCreatePicture (dpy, pixmap,
  618. XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8),
  619. CPRepeat,
  620. &pa);
  621. if (!picture)
  622. {
  623. XFreePixmap (dpy, pixmap);
  624. return None;
  625. }
  626. c.alpha = a * 0xffff;
  627. c.red = r * 0xffff;
  628. c.green = g * 0xffff;
  629. c.blue = b * 0xffff;
  630. XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
  631. XFreePixmap (dpy, pixmap);
  632. return picture;
  633. }
  634. static void
  635. discard_ignore (Display *dpy, unsigned long sequence)
  636. {
  637. while (ignore_head)
  638. {
  639. if ((long) (sequence - ignore_head->sequence) > 0)
  640. {
  641. ignore *next = ignore_head->next;
  642. free (ignore_head);
  643. ignore_head = next;
  644. if (!ignore_head)
  645. ignore_tail = &ignore_head;
  646. }
  647. else
  648. break;
  649. }
  650. }
  651. static void
  652. set_ignore (Display *dpy, unsigned long sequence)
  653. {
  654. ignore *i = malloc (sizeof (ignore));
  655. if (!i)
  656. return;
  657. i->sequence = sequence;
  658. i->next = NULL;
  659. *ignore_tail = i;
  660. ignore_tail = &i->next;
  661. }
  662. static int
  663. should_ignore (Display *dpy, unsigned long sequence)
  664. {
  665. discard_ignore (dpy, sequence);
  666. return ignore_head && ignore_head->sequence == sequence;
  667. }
  668. static win *
  669. find_win (Display *dpy, Window id)
  670. {
  671. win *w;
  672. for (w = list; w; w = w->next)
  673. if (w->id == id)
  674. return w;
  675. return NULL;
  676. }
  677. static const char *backgroundProps[] = {
  678. "_XROOTPMAP_ID",
  679. "_XSETROOT_ID",
  680. NULL,
  681. };
  682. static Picture
  683. root_tile (Display *dpy)
  684. {
  685. Picture picture;
  686. Atom actual_type;
  687. Pixmap pixmap;
  688. int actual_format;
  689. unsigned long nitems;
  690. unsigned long bytes_after;
  691. unsigned char *prop;
  692. Bool fill;
  693. XRenderPictureAttributes pa;
  694. int p;
  695. pixmap = None;
  696. for (p = 0; backgroundProps[p]; p++)
  697. {
  698. if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False),
  699. 0, 4, False, AnyPropertyType,
  700. &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
  701. actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
  702. {
  703. memcpy (&pixmap, prop, 4);
  704. XFree (prop);
  705. fill = False;
  706. break;
  707. }
  708. }
  709. if (!pixmap)
  710. {
  711. pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
  712. fill = True;
  713. }
  714. pa.repeat = True;
  715. picture = XRenderCreatePicture (dpy, pixmap,
  716. XRenderFindVisualFormat (dpy,
  717. DefaultVisual (dpy, scr)),
  718. CPRepeat, &pa);
  719. if (fill)
  720. {
  721. XRenderColor c;
  722. c.red = c.green = c.blue = 0x8080;
  723. c.alpha = 0xffff;
  724. XRenderFillRectangle (dpy, PictOpSrc, picture, &c,
  725. 0, 0, 1, 1);
  726. }
  727. return picture;
  728. }
  729. static void
  730. paint_root (Display *dpy)
  731. {
  732. if (!rootTile)
  733. rootTile = root_tile (dpy);
  734. XRenderComposite (dpy, PictOpSrc,
  735. rootTile, None, rootBuffer,
  736. 0, 0, 0, 0, 0, 0, root_width, root_height);
  737. }
  738. static XserverRegion
  739. win_extents (Display *dpy, win *w)
  740. {
  741. XRectangle r;
  742. r.x = w->a.x;
  743. r.y = w->a.y;
  744. r.width = w->a.width + w->a.border_width * 2;
  745. r.height = w->a.height + w->a.border_width * 2;
  746. if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows))
  747. {
  748. if (compMode == CompServerShadows || w->mode != WINDOW_ARGB)
  749. {
  750. XRectangle sr;
  751. if (compMode == CompServerShadows)
  752. {
  753. w->shadow_dx = 2;
  754. w->shadow_dy = 7;
  755. w->shadow_width = w->a.width;
  756. w->shadow_height = w->a.height;
  757. }
  758. else
  759. {
  760. w->shadow_dx = shadowOffsetX;
  761. w->shadow_dy = shadowOffsetY;
  762. if (!w->shadow)
  763. {
  764. double opacity = shadowOpacity;
  765. if (w->mode == WINDOW_TRANS)
  766. opacity = opacity * ((double)w->opacity)/((double)OPAQUE);
  767. w->shadow = shadow_picture (dpy, opacity, w->alphaPict,
  768. w->a.width + w->a.border_width * 2,
  769. w->a.height + w->a.border_width * 2,
  770. &w->shadow_width, &w->shadow_height);
  771. }
  772. }
  773. sr.x = w->a.x + w->shadow_dx;
  774. sr.y = w->a.y + w->shadow_dy;
  775. sr.width = w->shadow_width;
  776. sr.height = w->shadow_height;
  777. if (sr.x < r.x)
  778. {
  779. r.width = (r.x + r.width) - sr.x;
  780. r.x = sr.x;
  781. }
  782. if (sr.y < r.y)
  783. {
  784. r.height = (r.y + r.height) - sr.y;
  785. r.y = sr.y;
  786. }
  787. if (sr.x + sr.width > r.x + r.width)
  788. r.width = sr.x + sr.width - r.x;
  789. if (sr.y + sr.height > r.y + r.height)
  790. r.height = sr.y + sr.height - r.y;
  791. }
  792. }
  793. return XFixesCreateRegion (dpy, &r, 1);
  794. }
  795. static XserverRegion
  796. border_size (Display *dpy, win *w)
  797. {
  798. XserverRegion border;
  799. /*
  800. * if window doesn't exist anymore, this will generate an error
  801. * as well as not generate a region. Perhaps a better XFixes
  802. * architecture would be to have a request that copies instead
  803. * of creates, that way you'd just end up with an empty region
  804. * instead of an invalid XID.
  805. */
  806. set_ignore (dpy, NextRequest (dpy));
  807. border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
  808. /* translate this */
  809. set_ignore (dpy, NextRequest (dpy));
  810. XFixesTranslateRegion (dpy, border,
  811. w->a.x + w->a.border_width,
  812. w->a.y + w->a.border_width);
  813. return border;
  814. }
  815. static void
  816. paint_all (Display *dpy, XserverRegion region)
  817. {
  818. win *w;
  819. win *t = NULL;
  820. if (!region)
  821. {
  822. XRectangle r;
  823. r.x = 0;
  824. r.y = 0;
  825. r.width = root_width;
  826. r.height = root_height;
  827. region = XFixesCreateRegion (dpy, &r, 1);
  828. }
  829. #if MONITOR_REPAINT
  830. rootBuffer = rootPicture;
  831. #else
  832. if (!rootBuffer)
  833. {
  834. Pixmap rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
  835. DefaultDepth (dpy, scr));
  836. rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
  837. XRenderFindVisualFormat (dpy,
  838. DefaultVisual (dpy, scr)),
  839. 0, NULL);
  840. XFreePixmap (dpy, rootPixmap);
  841. }
  842. #endif
  843. XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
  844. #if MONITOR_REPAINT
  845. XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture,
  846. 0, 0, 0, 0, 0, 0, root_width, root_height);
  847. #endif
  848. #if DEBUG_REPAINT
  849. printf ("paint:");
  850. #endif
  851. for (w = list; w; w = w->next)
  852. {
  853. #if CAN_DO_USABLE
  854. if (!w->usable)
  855. continue;
  856. #endif
  857. /* never painted, ignore it */
  858. if (!w->damaged)
  859. continue;
  860. /* if invisible, ignore it */
  861. if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1
  862. || w->a.x >= root_width || w->a.y >= root_height)
  863. continue;
  864. if (!w->picture)
  865. {
  866. XRenderPictureAttributes pa;
  867. XRenderPictFormat *format;
  868. Drawable draw = w->id;
  869. #if HAS_NAME_WINDOW_PIXMAP
  870. if (hasNamePixmap && !w->pixmap)
  871. w->pixmap = XCompositeNameWindowPixmap (dpy, w->id);
  872. if (w->pixmap)
  873. draw = w->pixmap;
  874. #endif
  875. format = XRenderFindVisualFormat (dpy, w->a.visual);
  876. pa.subwindow_mode = IncludeInferiors;
  877. w->picture = XRenderCreatePicture (dpy, draw,
  878. format,
  879. CPSubwindowMode,
  880. &pa);
  881. }
  882. #if DEBUG_REPAINT
  883. printf (" 0x%x", w->id);
  884. #endif
  885. if (clipChanged)
  886. {
  887. if (w->borderSize)
  888. {
  889. set_ignore (dpy, NextRequest (dpy));
  890. XFixesDestroyRegion (dpy, w->borderSize);
  891. w->borderSize = None;
  892. }
  893. if (w->extents)
  894. {
  895. XFixesDestroyRegion (dpy, w->extents);
  896. w->extents = None;
  897. }
  898. if (w->borderClip)
  899. {
  900. XFixesDestroyRegion (dpy, w->borderClip);
  901. w->borderClip = None;
  902. }
  903. }
  904. if (!w->borderSize)
  905. w->borderSize = border_size (dpy, w);
  906. if (!w->extents)
  907. w->extents = win_extents (dpy, w);
  908. if (w->mode == WINDOW_SOLID)
  909. {
  910. int x, y, wid, hei;
  911. #if HAS_NAME_WINDOW_PIXMAP
  912. x = w->a.x;
  913. y = w->a.y;
  914. wid = w->a.width + w->a.border_width * 2;
  915. hei = w->a.height + w->a.border_width * 2;
  916. #else
  917. x = w->a.x + w->a.border_width;
  918. y = w->a.y + w->a.border_width;
  919. wid = w->a.width;
  920. hei = w->a.height;
  921. #endif
  922. XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
  923. set_ignore (dpy, NextRequest (dpy));
  924. XFixesSubtractRegion (dpy, region, region, w->borderSize);
  925. set_ignore (dpy, NextRequest (dpy));
  926. XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
  927. 0, 0, 0, 0,
  928. x, y, wid, hei);
  929. }
  930. if (!w->borderClip)
  931. {
  932. w->borderClip = XFixesCreateRegion (dpy, NULL, 0);
  933. XFixesCopyRegion (dpy, w->borderClip, region);
  934. XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize);
  935. }
  936. w->prev_trans = t;
  937. t = w;
  938. }
  939. #if DEBUG_REPAINT
  940. printf ("\n");
  941. fflush (stdout);
  942. #endif
  943. XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
  944. paint_root (dpy);
  945. for (w = t; w; w = w->prev_trans)
  946. {
  947. XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
  948. switch (compMode) {
  949. case CompSimple:
  950. break;
  951. case CompServerShadows:
  952. /* dont' bother drawing shadows on desktop windows */
  953. if (w->windowType == winDesktopAtom)
  954. break;
  955. set_ignore (dpy, NextRequest (dpy));
  956. if (w->opacity != OPAQUE && !w->shadowPict)
  957. w->shadowPict = solid_picture (dpy, True,
  958. (double) w->opacity / OPAQUE * 0.3,
  959. 0, 0, 0);
  960. XRenderComposite (dpy, PictOpOver,
  961. w->shadowPict ? w->shadowPict : transBlackPicture,
  962. w->picture, rootBuffer,
  963. 0, 0, 0, 0,
  964. w->a.x + w->shadow_dx,
  965. w->a.y + w->shadow_dy,
  966. w->shadow_width, w->shadow_height);
  967. break;
  968. case CompClientShadows:
  969. /* don't bother drawing shadows on desktop windows */
  970. if (w->shadow && w->windowType != winDesktopAtom)
  971. {
  972. XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
  973. 0, 0, 0, 0,
  974. w->a.x + w->shadow_dx,
  975. w->a.y + w->shadow_dy,
  976. w->shadow_width, w->shadow_height);
  977. }
  978. break;
  979. }
  980. if (w->opacity != OPAQUE && !w->alphaPict)
  981. w->alphaPict = solid_picture (dpy, False,
  982. (double) w->opacity / OPAQUE, 0, 0, 0);
  983. if (w->mode == WINDOW_TRANS)
  984. {
  985. int x, y, wid, hei;
  986. #if HAS_NAME_WINDOW_PIXMAP
  987. x = w->a.x;
  988. y = w->a.y;
  989. wid = w->a.width + w->a.border_width * 2;
  990. hei = w->a.height + w->a.border_width * 2;
  991. #else
  992. x = w->a.x + w->a.border_width;
  993. y = w->a.y + w->a.border_width;
  994. wid = w->a.width;
  995. hei = w->a.height;
  996. #endif
  997. set_ignore (dpy, NextRequest (dpy));
  998. XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
  999. 0, 0, 0, 0,
  1000. x, y, wid, hei);
  1001. }
  1002. else if (w->mode == WINDOW_ARGB)
  1003. {
  1004. int x, y, wid, hei;
  1005. #if HAS_NAME_WINDOW_PIXMAP
  1006. x = w->a.x;
  1007. y = w->a.y;
  1008. wid = w->a.width + w->a.border_width * 2;
  1009. hei = w->a.height + w->a.border_width * 2;
  1010. #else
  1011. x = w->a.x + w->a.border_width;
  1012. y = w->a.y + w->a.border_width;
  1013. wid = w->a.width;
  1014. hei = w->a.height;
  1015. #endif
  1016. set_ignore (dpy, NextRequest (dpy));
  1017. XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
  1018. 0, 0, 0, 0,
  1019. x, y, wid, hei);
  1020. }
  1021. XFixesDestroyRegion (dpy, w->borderClip);
  1022. w->borderClip = None;
  1023. }
  1024. XFixesDestroyRegion (dpy, region);
  1025. if (rootBuffer != rootPicture)
  1026. {
  1027. XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
  1028. XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
  1029. 0, 0, 0, 0, 0, 0, root_width, root_height);
  1030. }
  1031. }
  1032. static void
  1033. add_damage (Display *dpy, XserverRegion damage)
  1034. {
  1035. if (allDamage)
  1036. {
  1037. XFixesUnionRegion (dpy, allDamage, allDamage, damage);
  1038. XFixesDestroyRegion (dpy, damage);
  1039. }
  1040. else
  1041. allDamage = damage;
  1042. }
  1043. static void
  1044. repair_win (Display *dpy, win *w)
  1045. {
  1046. XserverRegion parts;
  1047. if (!w->damaged)
  1048. {
  1049. parts = win_extents (dpy, w);
  1050. set_ignore (dpy, NextRequest (dpy));
  1051. XDamageSubtract (dpy, w->damage, None, None);
  1052. }
  1053. else
  1054. {
  1055. XserverRegion o;
  1056. parts = XFixesCreateRegion (dpy, NULL, 0);
  1057. set_ignore (dpy, NextRequest (dpy));
  1058. XDamageSubtract (dpy, w->damage, None, parts);
  1059. XFixesTranslateRegion (dpy, parts,
  1060. w->a.x + w->a.border_width,
  1061. w->a.y + w->a.border_width);
  1062. if (compMode == CompServerShadows)
  1063. {
  1064. o = XFixesCreateRegion (dpy, NULL, 0);
  1065. XFixesCopyRegion (dpy, o, parts);
  1066. XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy);
  1067. XFixesUnionRegion (dpy, parts, parts, o);
  1068. XFixesDestroyRegion (dpy, o);
  1069. }
  1070. }
  1071. add_damage (dpy, parts);
  1072. w->damaged = 1;
  1073. }
  1074. static unsigned int
  1075. get_opacity_prop (Display *dpy, win *w, unsigned int def);
  1076. static void
  1077. map_win (Display *dpy, Window id, unsigned long sequence, Bool fade)
  1078. {
  1079. win *w = find_win (dpy, id);
  1080. if (!w)
  1081. return;
  1082. w->a.map_state = IsViewable;
  1083. /* This needs to be here or else we lose transparency messages */
  1084. XSelectInput (dpy, id, PropertyChangeMask);
  1085. /* This needs to be here since we don't get PropertyNotify when unmapped */
  1086. w->opacity = get_opacity_prop (dpy, w, OPAQUE);
  1087. determine_mode (dpy, w);
  1088. #if CAN_DO_USABLE
  1089. w->damage_bounds.x = w->damage_bounds.y = 0;
  1090. w->damage_bounds.width = w->damage_bounds.height = 0;
  1091. #endif
  1092. w->damaged = 0;
  1093. if (fade && fadeWindows)
  1094. set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, NULL, False, True, True);
  1095. }
  1096. static void
  1097. finish_unmap_win (Display *dpy, win *w)
  1098. {
  1099. w->damaged = 0;
  1100. #if CAN_DO_USABLE
  1101. w->usable = False;
  1102. #endif
  1103. if (w->extents != None)
  1104. {
  1105. add_damage (dpy, w->extents); /* destroys region */
  1106. w->extents = None;
  1107. }
  1108. #if HAS_NAME_WINDOW_PIXMAP
  1109. if (w->pixmap)
  1110. {
  1111. XFreePixmap (dpy, w->pixmap);
  1112. w->pixmap = None;
  1113. }
  1114. #endif
  1115. if (w->picture)
  1116. {
  1117. set_ignore (dpy, NextRequest (dpy));
  1118. XRenderFreePicture (dpy, w->picture);
  1119. w->picture = None;
  1120. }
  1121. /* don't care about properties anymore */
  1122. set_ignore (dpy, NextRequest (dpy));
  1123. XSelectInput(dpy, w->id, 0);
  1124. if (w->borderSize)
  1125. {
  1126. set_ignore (dpy, NextRequest (dpy));
  1127. XFixesDestroyRegion (dpy, w->borderSize);
  1128. w->borderSize = None;
  1129. }
  1130. if (w->shadow)
  1131. {
  1132. XRenderFreePicture (dpy, w->shadow);
  1133. w->shadow = None;
  1134. }
  1135. if (w->borderClip)
  1136. {
  1137. XFixesDestroyRegion (dpy, w->borderClip);
  1138. w->borderClip = None;
  1139. }
  1140. clipChanged = True;
  1141. }
  1142. #if HAS_NAME_WINDOW_PIXMAP
  1143. static void
  1144. unmap_callback (Display *dpy, win *w, Bool gone)
  1145. {
  1146. finish_unmap_win (dpy, w);
  1147. }
  1148. #endif
  1149. static void
  1150. unmap_win (Display *dpy, Window id, Bool fade)
  1151. {
  1152. win *w = find_win (dpy, id);
  1153. if (!w)
  1154. return;
  1155. w->a.map_state = IsUnmapped;
  1156. #if HAS_NAME_WINDOW_PIXMAP
  1157. if (w->pixmap && fade && fadeWindows)
  1158. set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, True);
  1159. else
  1160. #endif
  1161. finish_unmap_win (dpy, w);
  1162. }
  1163. /* Get the opacity prop from window
  1164. not found: default
  1165. otherwise the value
  1166. */
  1167. static unsigned int
  1168. get_opacity_prop(Display *dpy, win *w, unsigned int def)
  1169. {
  1170. Atom actual;
  1171. int format;
  1172. unsigned long n, left;
  1173. unsigned char *data;
  1174. int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False,
  1175. XA_CARDINAL, &actual, &format,
  1176. &n, &left, &data);
  1177. if (result == Success && data != NULL)
  1178. {
  1179. unsigned int i;
  1180. memcpy (&i, data, sizeof (unsigned int));
  1181. XFree( (void *) data);
  1182. return i;
  1183. }
  1184. return def;
  1185. }
  1186. /* Get the opacity property from the window in a percent format
  1187. not found: default
  1188. otherwise: the value
  1189. */
  1190. static double
  1191. get_opacity_percent(Display *dpy, win *w, double def)
  1192. {
  1193. unsigned int opacity = get_opacity_prop (dpy, w, (unsigned int)(OPAQUE*def));
  1194. return opacity*1.0/OPAQUE;
  1195. }
  1196. /* determine mode for window all in one place.
  1197. Future might check for menu flag and other cool things
  1198. */
  1199. static Atom
  1200. get_wintype_prop(Display * dpy, Window w)
  1201. {
  1202. Atom actual;
  1203. int format;
  1204. unsigned long n, left;
  1205. unsigned char *data;
  1206. int result = XGetWindowProperty (dpy, w, winTypeAtom, 0L, 1L, False,
  1207. XA_ATOM, &actual, &format,
  1208. &n, &left, &data);
  1209. if (result == Success && data != (unsigned char *)None)
  1210. {
  1211. Atom a;
  1212. memcpy (&a, data, sizeof (Atom));
  1213. XFree ( (void *) data);
  1214. return a;
  1215. }
  1216. return winNormalAtom;
  1217. }
  1218. static void
  1219. determine_mode(Display *dpy, win *w)
  1220. {
  1221. int mode;
  1222. XRenderPictFormat *format;
  1223. /* if trans prop == -1 fall back on previous tests*/
  1224. if (w->alphaPict)
  1225. {
  1226. XRenderFreePicture (dpy, w->alphaPict);
  1227. w->alphaPict = None;
  1228. }
  1229. if (w->shadowPict)
  1230. {
  1231. XRenderFreePicture (dpy, w->shadowPict);
  1232. w->shadowPict = None;
  1233. }
  1234. if (w->a.class == InputOnly)
  1235. {
  1236. format = NULL;
  1237. }
  1238. else
  1239. {
  1240. format = XRenderFindVisualFormat (dpy, w->a.visual);
  1241. }
  1242. if (format && format->type == PictTypeDirect && format->direct.alphaMask)
  1243. {
  1244. mode = WINDOW_ARGB;
  1245. }
  1246. else if (w->opacity != OPAQUE)
  1247. {
  1248. mode = WINDOW_TRANS;
  1249. }
  1250. else
  1251. {
  1252. mode = WINDOW_SOLID;
  1253. }
  1254. w->mode = mode;
  1255. if (w->extents)
  1256. {
  1257. XserverRegion damage;
  1258. damage = XFixesCreateRegion (dpy, NULL, 0);
  1259. XFixesCopyRegion (dpy, damage, w->extents);
  1260. add_damage (dpy, damage);
  1261. }
  1262. }
  1263. static Atom
  1264. determine_wintype (Display *dpy, Window w)
  1265. {
  1266. Window root_return, parent_return;
  1267. Window *children = NULL;
  1268. unsigned int nchildren, i;
  1269. Atom type;
  1270. type = get_wintype_prop (dpy, w);
  1271. if (type != winNormalAtom)
  1272. return type;
  1273. if (!XQueryTree (dpy, w, &root_return, &parent_return, &children,
  1274. &nchildren))
  1275. {
  1276. /* XQueryTree failed. */
  1277. if (children)
  1278. XFree ((void *)children);
  1279. return winNormalAtom;
  1280. }
  1281. for (i = 0;i < nchildren;i++)
  1282. {
  1283. type = determine_wintype (dpy, children[i]);
  1284. if (type != winNormalAtom)
  1285. return type;
  1286. }
  1287. if (children)
  1288. XFree ((void *)children);
  1289. return winNormalAtom;
  1290. }
  1291. static void
  1292. add_win (Display *dpy, Window id, Window prev)
  1293. {
  1294. win *new = malloc (sizeof (win));
  1295. win **p;
  1296. if (!new)
  1297. return;
  1298. if (prev)
  1299. {
  1300. for (p = &list; *p; p = &(*p)->next)
  1301. if ((*p)->id == prev)
  1302. break;
  1303. }
  1304. else
  1305. p = &list;
  1306. new->id = id;
  1307. set_ignore (dpy, NextRequest (dpy));
  1308. if (!XGetWindowAttributes (dpy, id, &new->a))
  1309. {
  1310. free (new);
  1311. return;
  1312. }
  1313. new->shaped = False;
  1314. new->shape_bounds.x = new->a.x;
  1315. new->shape_bounds.y = new->a.y;
  1316. new->shape_bounds.width = new->a.width;
  1317. new->shape_bounds.height = new->a.height;
  1318. new->damaged = 0;
  1319. #if CAN_DO_USABLE
  1320. new->usable = False;
  1321. #endif
  1322. #if HAS_NAME_WINDOW_PIXMAP
  1323. new->pixmap = None;
  1324. #endif
  1325. new->picture = None;
  1326. if (new->a.class == InputOnly)
  1327. {
  1328. new->damage_sequence = 0;
  1329. new->damage = None;
  1330. }
  1331. else
  1332. {
  1333. new->damage_sequence = NextRequest (dpy);
  1334. new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
  1335. XShapeSelectInput (dpy, id, ShapeNotifyMask);
  1336. }
  1337. new->alphaPict = None;
  1338. new->shadowPict = None;
  1339. new->borderSize = None;
  1340. new->extents = None;
  1341. new->shadow = None;
  1342. new->shadow_dx = 0;
  1343. new->shadow_dy = 0;
  1344. new->shadow_width = 0;
  1345. new->shadow_height = 0;
  1346. new->opacity = OPAQUE;
  1347. new->borderClip = None;
  1348. new->prev_trans = NULL;
  1349. new->windowType = determine_wintype (dpy, new->id);
  1350. new->next = *p;
  1351. *p = new;
  1352. if (new->a.map_state == IsViewable)
  1353. map_win (dpy, id, new->damage_sequence - 1, True);
  1354. }
  1355. static void
  1356. restack_win (Display *dpy, win *w, Window new_above)
  1357. {
  1358. Window old_above;
  1359. if (w->next)
  1360. old_above = w->next->id;
  1361. else
  1362. old_above = None;
  1363. if (old_above != new_above)
  1364. {
  1365. win **prev;
  1366. /* unhook */
  1367. for (prev = &list; *prev; prev = &(*prev)->next)
  1368. if ((*prev) == w)
  1369. break;
  1370. *prev = w->next;
  1371. /* rehook */
  1372. for (prev = &list; *prev; prev = &(*prev)->next)
  1373. {
  1374. if ((*prev)->id == new_above)
  1375. break;
  1376. }
  1377. w->next = *prev;
  1378. *prev = w;
  1379. }
  1380. }
  1381. static void
  1382. configure_win (Display *dpy, XConfigureEvent *ce)
  1383. {
  1384. win *w = find_win (dpy, ce->window);
  1385. XserverRegion damage = None;
  1386. if (!w)
  1387. {
  1388. if (ce->window == root)
  1389. {
  1390. if (rootBuffer)
  1391. {
  1392. XRenderFreePicture (dpy, rootBuffer);
  1393. rootBuffer = None;
  1394. }
  1395. root_width = ce->width;
  1396. root_height = ce->height;
  1397. }
  1398. return;
  1399. }
  1400. #if CAN_DO_USABLE
  1401. if (w->usable)
  1402. #endif
  1403. {
  1404. damage = XFixesCreateRegion (dpy, NULL, 0);
  1405. if (w->extents != None)
  1406. XFixesCopyRegion (dpy, damage, w->extents);
  1407. }
  1408. w->shape_bounds.x -= w->a.x;
  1409. w->shape_bounds.y -= w->a.y;
  1410. w->a.x = ce->x;
  1411. w->a.y = ce->y;
  1412. if (w->a.width != ce->width || w->a.height != ce->height)
  1413. {
  1414. #if HAS_NAME_WINDOW_PIXMAP
  1415. if (w->pixmap)
  1416. {
  1417. XFreePixmap (dpy, w->pixmap);
  1418. w->pixmap = None;
  1419. if (w->picture)
  1420. {
  1421. XRenderFreePicture (dpy, w->picture);
  1422. w->picture = None;
  1423. }
  1424. }
  1425. #endif
  1426. if (w->shadow)
  1427. {
  1428. XRenderFreePicture (dpy, w->shadow);
  1429. w->shadow = None;
  1430. }
  1431. }
  1432. w->a.width = ce->width;
  1433. w->a.height = ce->height;
  1434. w->a.border_width = ce->border_width;
  1435. w->a.override_redirect = ce->override_redirect;
  1436. restack_win (dpy, w, ce->above);
  1437. if (damage)
  1438. {
  1439. XserverRegion extents = win_extents (dpy, w);
  1440. XFixesUnionRegion (dpy, damage, damage, extents);
  1441. XFixesDestroyRegion (dpy, extents);
  1442. add_damage (dpy, damage);
  1443. }
  1444. w->shape_bounds.x += w->a.x;
  1445. w->shape_bounds.y += w->a.y;
  1446. if (!w->shaped)
  1447. {
  1448. w->shape_bounds.width = w->a.width;
  1449. w->shape_bounds.height = w->a.height;
  1450. }
  1451. clipChanged = True;
  1452. }
  1453. static void
  1454. circulate_win (Display *dpy, XCirculateEvent *ce)
  1455. {
  1456. win *w = find_win (dpy, ce->window);
  1457. Window new_above;
  1458. if (!w)
  1459. return;
  1460. if (ce->place == PlaceOnTop)
  1461. new_above = list->id;
  1462. else
  1463. new_above = None;
  1464. restack_win (dpy, w, new_above);
  1465. clipChanged = True;
  1466. }
  1467. static void
  1468. finish_destroy_win (Display *dpy, Window id, Bool gone)
  1469. {
  1470. win **prev, *w;
  1471. for (prev = &list; (w = *prev); prev = &w->next)
  1472. if (w->id == id)
  1473. {
  1474. if (gone)
  1475. finish_unmap_win (dpy, w);
  1476. *prev = w->next;
  1477. if (w->picture)
  1478. {
  1479. set_ignore (dpy, NextRequest (dpy));
  1480. XRenderFreePicture (dpy, w->picture);
  1481. w->picture = None;
  1482. }
  1483. if (w->alphaPict)
  1484. {
  1485. XRenderFreePicture (dpy, w->alphaPict);
  1486. w->alphaPict = None;
  1487. }
  1488. if (w->shadowPict)
  1489. {
  1490. XRenderFreePicture (dpy, w->shadowPict);
  1491. w->shadowPict = None;
  1492. }
  1493. if (w->shadow)
  1494. {
  1495. XRenderFreePicture (dpy, w->shadow);
  1496. w->shadow = None;
  1497. }
  1498. if (w->damage != None)
  1499. {
  1500. set_ignore (dpy, NextRequest (dpy));
  1501. XDamageDestroy (dpy, w->damage);
  1502. w->damage = None;
  1503. }
  1504. cleanup_fade (dpy, w);
  1505. free (w);
  1506. break;
  1507. }
  1508. }
  1509. #if HAS_NAME_WINDOW_PIXMAP
  1510. static void
  1511. destroy_callback (Display *dpy, win *w, Bool gone)
  1512. {
  1513. finish_destroy_win (dpy, w->id, gone);
  1514. }
  1515. #endif
  1516. static void
  1517. destroy_win (Display *dpy, Window id, Bool gone, Bool fade)
  1518. {
  1519. win *w = find_win (dpy, id);
  1520. #if HAS_NAME_WINDOW_PIXMAP
  1521. if (w && w->pixmap && fade && fadeWindows)
  1522. set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True);
  1523. else
  1524. #endif
  1525. {
  1526. finish_destroy_win (dpy, id, gone);
  1527. }
  1528. }
  1529. /*
  1530. static void
  1531. dump_win (win *w)
  1532. {
  1533. printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
  1534. w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
  1535. }
  1536. static void
  1537. dump_wins (void)
  1538. {
  1539. win *w;
  1540. printf ("windows:\n");
  1541. for (w = list; w; w = w->next)
  1542. dump_win (w);
  1543. }
  1544. */
  1545. static void
  1546. damage_win (Display *dpy, XDamageNotifyEvent *de)
  1547. {
  1548. win *w = find_win (dpy, de->drawable);
  1549. if (!w)
  1550. return;
  1551. #if CAN_DO_USABLE
  1552. if (!w->usable)
  1553. {
  1554. if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0)
  1555. {
  1556. w->damage_bounds = de->area;
  1557. }
  1558. else
  1559. {
  1560. if (de->area.x < w->damage_bounds.x)
  1561. {
  1562. w->damage_bounds.width += (w->damage_bounds.x - de->area.x);
  1563. w->damage_bounds.x = de->area.x;
  1564. }
  1565. if (de->area.y < w->damage_bounds.y)
  1566. {
  1567. w->damage_bounds.height += (w->damage_bounds.y - de->area.y);
  1568. w->damage_bounds.y = de->area.y;
  1569. }
  1570. if (de->area.x + de->area.width > w->damage_bounds.x + w->damage_bounds.width)
  1571. w->damage_bounds.width = de->area.x + de->area.width - w->damage_bounds.x;
  1572. if (de->area.y + de->area.height > w->damage_bounds.y + w->damage_bounds.height)
  1573. w->damage_bounds.height = de->area.y + de->area.height - w->damage_bounds.y;
  1574. }
  1575. #if 0
  1576. printf ("unusable damage %d, %d: %d x %d bounds %d, %d: %d x %d\n",
  1577. de->area.x,
  1578. de->area.y,
  1579. de->area.width,
  1580. de->area.height,
  1581. w->damage_bounds.x,
  1582. w->damage_bounds.y,
  1583. w->damage_bounds.width,
  1584. w->damage_bounds.height);
  1585. #endif
  1586. if (w->damage_bounds.x <= 0 &&
  1587. w->damage_bounds.y <= 0 &&
  1588. w->a.width <= w->damage_bounds.x + w->damage_bounds.width &&
  1589. w->a.height <= w->damage_bounds.y + w->damage_bounds.height)
  1590. {
  1591. clipChanged = True;
  1592. if (fadeWindows)
  1593. set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, 0, False, True, True);
  1594. w->usable = True;
  1595. }
  1596. }
  1597. if (w->usable)
  1598. #endif
  1599. repair_win (dpy, w);
  1600. }
  1601. #if DEBUG_SHAPE
  1602. static const char *
  1603. shape_kind(int kind)
  1604. {
  1605. static char buf[128];
  1606. switch(kind){
  1607. case ShapeBounding:
  1608. return "ShapeBounding";
  1609. case ShapeClip:
  1610. return "ShapeClip";
  1611. case ShapeInput:
  1612. return "ShapeInput";
  1613. default:
  1614. sprintf (buf, "Shape %d", kind);
  1615. return buf;
  1616. }
  1617. }
  1618. #endif
  1619. static void
  1620. shape_win (Display *dpy, XShapeEvent *se)
  1621. {
  1622. win *w = find_win (dpy, se->window);
  1623. if (!w)
  1624. return;
  1625. if (se->kind == ShapeClip || se->kind == ShapeBounding)
  1626. {
  1627. XserverRegion region0;
  1628. XserverRegion region1;
  1629. #if DEBUG_SHAPE
  1630. printf("win 0x%lx %s:%s %ux%u+%d+%d\n",
  1631. (unsigned long) se->window,
  1632. shape_kind(se->kind),
  1633. (se->shaped == True) ? "true" : "false",
  1634. se->width, se->height,
  1635. se->x, se->y);
  1636. #endif
  1637. clipChanged = True;
  1638. region0 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
  1639. if (se->shaped == True)
  1640. {
  1641. w->shaped = True;
  1642. w->shape_bounds.x = w->a.x + se->x;
  1643. w->shape_bounds.y = w->a.y + se->y;
  1644. w->shape_bounds.width = se->width;
  1645. w->shape_bounds.height = se->height;
  1646. }
  1647. else
  1648. {
  1649. w->shaped = False;
  1650. w->shape_bounds.x = w->a.x;
  1651. w->shape_bounds.y = w->a.y;
  1652. w->shape_bounds.width = w->a.width;
  1653. w->shape_bounds.height = w->a.height;
  1654. }
  1655. region1 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
  1656. XFixesUnionRegion (dpy, region0, region0, region1);
  1657. XFixesDestroyRegion (dpy, region1);
  1658. /* ask for repaint of the old and new region */
  1659. paint_all (dpy, region0);
  1660. }
  1661. }
  1662. static int
  1663. error (Display *dpy, XErrorEvent *ev)
  1664. {
  1665. int o;
  1666. const char *name = NULL;
  1667. static char buffer[256];
  1668. if (should_ignore (dpy, ev->serial))
  1669. return 0;
  1670. if (ev->request_code == composite_opcode &&
  1671. ev->minor_code == X_CompositeRedirectSubwindows)
  1672. {
  1673. fprintf (stderr, "Another composite manager is already running\n");
  1674. exit (1);
  1675. }
  1676. o = ev->error_code - xfixes_error;
  1677. switch (o) {
  1678. case BadRegion: name = "BadRegion"; break;
  1679. default: break;
  1680. }
  1681. o = ev->error_code - damage_error;
  1682. switch (o) {
  1683. case BadDamage: name = "BadDamage"; break;
  1684. default: break;
  1685. }
  1686. o = ev->error_code - render_error;
  1687. switch (o) {
  1688. case BadPictFormat: name ="BadPictFormat"; break;
  1689. case BadPicture: name ="BadPicture"; break;
  1690. case BadPictOp: name ="BadPictOp"; break;
  1691. case BadGlyphSet: name ="BadGlyphSet"; break;
  1692. case BadGlyph: name ="BadGlyph"; break;
  1693. default: break;
  1694. }
  1695. if (name == NULL)
  1696. {
  1697. buffer[0] = '\0';
  1698. XGetErrorText (dpy, ev->error_code, buffer, sizeof (buffer));
  1699. name = buffer;
  1700. }
  1701. fprintf (stderr, "error %d: %s request %d minor %d serial %lu\n",
  1702. ev->error_code, (strlen (name) > 0) ? name : "unknown",
  1703. ev->request_code, ev->minor_code, ev->serial);
  1704. /* abort (); this is just annoying to most people */
  1705. return 0;
  1706. }
  1707. static void
  1708. expose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
  1709. {
  1710. XserverRegion region = XFixesCreateRegion (dpy, rects, nrects);
  1711. add_damage (dpy, region);
  1712. }
  1713. #if DEBUG_EVENTS
  1714. static int
  1715. ev_serial (XEvent *ev)
  1716. {
  1717. if (ev->type & 0x7f != KeymapNotify)
  1718. return ev->xany.serial;
  1719. return NextRequest (ev->xany.display);
  1720. }
  1721. static char *
  1722. ev_name (XEvent *ev)
  1723. {
  1724. static char buf[128];
  1725. switch (ev->type & 0x7f) {
  1726. case Expose:
  1727. return "Expose";
  1728. case MapNotify:
  1729. return "Map";
  1730. case UnmapNotify:
  1731. return "Unmap";
  1732. case ReparentNotify:
  1733. return "Reparent";
  1734. case CirculateNotify:
  1735. return "Circulate";
  1736. default:
  1737. if (ev->type == damage_event + XDamageNotify)
  1738. {
  1739. return "Damage";
  1740. }
  1741. else if (ev->type == xshape_event + ShapeNotify)
  1742. {
  1743. return "Shape";
  1744. }
  1745. sprintf (buf, "Event %d", ev->type);
  1746. return buf;
  1747. }
  1748. }
  1749. static Window
  1750. ev_window (XEvent *ev)
  1751. {
  1752. switch (ev->type) {
  1753. case Expose:
  1754. return ev->xexpose.window;
  1755. case MapNotify:
  1756. return ev->xmap.window;
  1757. case UnmapNotify:
  1758. return ev->xunmap.window;
  1759. case ReparentNotify:
  1760. return ev->xreparent.window;
  1761. case CirculateNotify:
  1762. return ev->xcirculate.window;
  1763. default:
  1764. if (ev->type == damage_event + XDamageNotify)
  1765. {
  1766. return ((XDamageNotifyEvent *) ev)->drawable;
  1767. }
  1768. else if (ev->type == xshape_event + ShapeNotify)
  1769. {
  1770. return ((XShapeEvent *) ev)->window;
  1771. }
  1772. return 0;
  1773. }
  1774. }
  1775. #endif
  1776. static void
  1777. usage (const char *program)
  1778. {
  1779. fprintf (stderr, "%s v%s\n", program, PACKAGE_VERSION);
  1780. fprintf (stderr, "usage: %s [options]\n%s\n", program,
  1781. "Options:\n"
  1782. " -d display\n"
  1783. " Specifies which display should be managed.\n"
  1784. " -r radius\n"
  1785. " Specifies the blur radius for client-side shadows. (default 12)\n"
  1786. " -o opacity\n"
  1787. " Specifies the translucency for client-side shadows. (default .75)\n"
  1788. " -l left-offset\n"
  1789. " Specifies the left offset for client-side shadows. (default -15)\n"
  1790. " -t top-offset\n"
  1791. " Specifies the top offset for clinet-side shadows. (default -15)\n"
  1792. " -I fade-in-step\n"
  1793. " Specifies the opacity change between steps while fading in. (default 0.028)\n"
  1794. " -O fade-out-step\n"
  1795. " Specifies the opacity change between steps while fading out. (default 0.03)\n"
  1796. " -D fade-delta-time\n"
  1797. " Specifies the time between steps in a fade in milliseconds. (default 10)\n"
  1798. " -a\n"
  1799. " Use automatic server-side compositing. Faster, but no special effects.\n"
  1800. " -c\n"
  1801. " Draw client-side shadows with fuzzy edges.\n"
  1802. " -C\n"
  1803. " Avoid drawing shadows on dock/panel windows.\n"
  1804. " -f\n"
  1805. " Fade windows in/out when opening/closing.\n"
  1806. " -F\n"
  1807. " Fade windows during opacity changes.\n"
  1808. " -n\n"
  1809. " Normal client-side compositing with transparency support\n"
  1810. " -s\n"
  1811. " Draw server-side shadows with sharp edges.\n"
  1812. " -S\n"
  1813. " Enable synchronous operation (for debugging).\n"
  1814. );
  1815. exit (1);
  1816. }
  1817. static Bool
  1818. register_cm (Display *dpy)
  1819. {
  1820. Window w;
  1821. Atom a;
  1822. static char net_wm_cm[] = "_NET_WM_CM_Sxx";
  1823. snprintf (net_wm_cm, sizeof (net_wm_cm), "_NET_WM_CM_S%d", scr);
  1824. a = XInternAtom (dpy, net_wm_cm, False);
  1825. w = XGetSelectionOwner (dpy, a);
  1826. if (w != None)
  1827. {
  1828. XTextProperty tp;
  1829. char **strs;
  1830. int count;
  1831. Atom winNameAtom = XInternAtom (dpy, "_NET_WM_NAME", False);
  1832. if (!XGetTextProperty (dpy, w, &tp, winNameAtom) &&
  1833. !XGetTextProperty (dpy, w, &tp, XA_WM_NAME))
  1834. {
  1835. fprintf (stderr,
  1836. "Another composite manager is already running (0x%lx)\n",
  1837. (unsigned long) w);
  1838. return False;
  1839. }
  1840. if (XmbTextPropertyToTextList (dpy, &tp, &strs, &count) == Success)
  1841. {
  1842. fprintf (stderr,
  1843. "Another composite manager is already running (%s)\n",
  1844. strs[0]);
  1845. XFreeStringList (strs);
  1846. }
  1847. XFree (tp.value);
  1848. return False;
  1849. }
  1850. w = XCreateSimpleWindow (dpy, RootWindow (dpy, scr), 0, 0, 1, 1, 0, None,
  1851. None);
  1852. Xutf8SetWMProperties (dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL,
  1853. NULL);
  1854. XSetSelectionOwner (dpy, a, w, 0);
  1855. return True;
  1856. }
  1857. int
  1858. main (int argc, char **argv)
  1859. {
  1860. Display *dpy;
  1861. XEvent ev;
  1862. Window root_return, parent_return;
  1863. Window *children;
  1864. unsigned int nchildren;
  1865. int i;
  1866. XRenderPictureAttributes pa;
  1867. XRectangle *expose_rects = NULL;
  1868. int size_expose = 0;
  1869. int n_expose = 0;
  1870. struct pollfd ufd;
  1871. int p;
  1872. int composite_major, composite_minor;
  1873. char *display = NULL;
  1874. int o;
  1875. while ((o = getopt (argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1)
  1876. {
  1877. switch (o) {
  1878. case 'd':
  1879. display = optarg;
  1880. break;
  1881. case 'D':
  1882. fade_delta = atoi (optarg);
  1883. if (fade_delta < 1)
  1884. fade_delta = 10;
  1885. break;
  1886. case 'I':
  1887. fade_in_step = atof (optarg);
  1888. if (fade_in_step <= 0)
  1889. fade_in_step = 0.01;
  1890. break;
  1891. case 'O':
  1892. fade_out_step = atof (optarg);
  1893. if (fade_out_step <= 0)
  1894. fade_out_step = 0.01;
  1895. break;
  1896. case 's':
  1897. compMode = CompServerShadows;
  1898. break;
  1899. case 'c':
  1900. compMode = CompClientShadows;
  1901. break;
  1902. case 'C':
  1903. excludeDockShadows = True;
  1904. break;
  1905. case 'n':
  1906. compMode = CompSimple;
  1907. break;
  1908. case 'f':
  1909. fadeWindows = True;
  1910. break;
  1911. case 'F':
  1912. fadeTrans = True;
  1913. break;
  1914. case 'a':
  1915. autoRedirect = True;
  1916. break;
  1917. case 'S':
  1918. synchronize = True;
  1919. break;
  1920. case 'r':
  1921. shadowRadius = atoi (optarg);
  1922. break;
  1923. case 'o':
  1924. shadowOpacity = atof (optarg);
  1925. break;
  1926. case 'l':
  1927. shadowOffsetX = atoi (optarg);
  1928. break;
  1929. case 't':
  1930. shadowOffsetY = atoi (optarg);
  1931. break;
  1932. default:
  1933. usage (argv[0]);
  1934. break;
  1935. }
  1936. }
  1937. dpy = XOpenDisplay (display);
  1938. if (!dpy)
  1939. {
  1940. fprintf (stderr, "Can't open display\n");
  1941. exit (1);
  1942. }
  1943. XSetErrorHandler (error);
  1944. if (synchronize)
  1945. XSynchronize (dpy, 1);
  1946. scr = DefaultScreen (dpy);
  1947. root = RootWindow (dpy, scr);
  1948. if (!XRenderQueryExtension (dpy, &render_event, &render_error))
  1949. {
  1950. fprintf (stderr, "No render extension\n");
  1951. exit (1);
  1952. }
  1953. if (!XQueryExtension (dpy, COMPOSITE_NAME, &composite_opcode,
  1954. &composite_event, &composite_error))
  1955. {
  1956. fprintf (stderr, "No composite extension\n");
  1957. exit (1);
  1958. }
  1959. XCompositeQueryVersion (dpy, &composite_major, &composite_minor);
  1960. #if HAS_NAME_WINDOW_PIXMAP
  1961. if (composite_major > 0 || composite_minor >= 2)
  1962. hasNamePixmap = True;
  1963. #endif
  1964. if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
  1965. {
  1966. fprintf (stderr, "No damage extension\n");
  1967. exit (1);
  1968. }
  1969. if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
  1970. {
  1971. fprintf (stderr, "No XFixes extension\n");
  1972. exit (1);
  1973. }
  1974. if (!XShapeQueryExtension (dpy, &xshape_event, &xshape_error))
  1975. {
  1976. fprintf (stderr, "No XShape extension\n");
  1977. exit (1);
  1978. }
  1979. if (!register_cm(dpy))
  1980. {
  1981. exit (1);
  1982. }
  1983. /* get atoms */
  1984. opacityAtom = XInternAtom (dpy, OPACITY_PROP, False);
  1985. winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False);
  1986. winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
  1987. winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
  1988. winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
  1989. winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
  1990. winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
  1991. winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
  1992. winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
  1993. winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
  1994. pa.subwindow_mode = IncludeInferiors;
  1995. if (compMode == CompClientShadows)
  1996. {
  1997. gaussianMap = make_gaussian_map(dpy, shadowRadius);
  1998. presum_gaussian (gaussianMap);
  1999. }
  2000. root_width = DisplayWidth (dpy, scr);
  2001. root_height = DisplayHeight (dpy, scr);
  2002. rootPicture = XRenderCreatePicture (dpy, root,
  2003. XRenderFindVisualFormat (dpy,
  2004. DefaultVisual (dpy, scr)),
  2005. CPSubwindowMode,
  2006. &pa);
  2007. blackPicture = solid_picture (dpy, True, 1, 0, 0, 0);
  2008. if (compMode == CompServerShadows)
  2009. transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
  2010. allDamage = None;
  2011. clipChanged = True;
  2012. XGrabServer (dpy);
  2013. if (autoRedirect)
  2014. XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic);
  2015. else
  2016. {
  2017. XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
  2018. XSelectInput (dpy, root,
  2019. SubstructureNotifyMask|
  2020. ExposureMask|
  2021. StructureNotifyMask|
  2022. PropertyChangeMask);
  2023. XShapeSelectInput (dpy, root, ShapeNotifyMask);
  2024. XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
  2025. for (i = 0; i < nchildren; i++)
  2026. add_win (dpy, children[i], i ? children[i-1] : None);
  2027. XFree (children);
  2028. }
  2029. XUngrabServer (dpy);
  2030. ufd.fd = ConnectionNumber (dpy);
  2031. ufd.events = POLLIN;
  2032. if (!autoRedirect)
  2033. paint_all (dpy, None);
  2034. for (;;)
  2035. {
  2036. /* dump_wins (); */
  2037. do {
  2038. if (autoRedirect)
  2039. XFlush (dpy);
  2040. if (!QLength (dpy))
  2041. {
  2042. if (poll (&ufd, 1, fade_timeout()) == 0)
  2043. {
  2044. run_fades (dpy);
  2045. break;
  2046. }
  2047. }
  2048. XNextEvent (dpy, &ev);
  2049. if ((ev.type & 0x7f) != KeymapNotify)
  2050. discard_ignore (dpy, ev.xany.serial);
  2051. #if DEBUG_EVENTS
  2052. printf ("event %10.10s serial 0x%08x window 0x%08x\n",
  2053. ev_name(&ev), ev_serial (&ev), ev_window (&ev));
  2054. #endif
  2055. if (!autoRedirect) switch (ev.type) {
  2056. case CreateNotify:
  2057. add_win (dpy, ev.xcreatewindow.window, 0);
  2058. break;
  2059. case ConfigureNotify:
  2060. configure_win (dpy, &ev.xconfigure);
  2061. break;
  2062. case DestroyNotify:
  2063. destroy_win (dpy, ev.xdestroywindow.window, True, True);
  2064. break;
  2065. case MapNotify:
  2066. map_win (dpy, ev.xmap.window, ev.xmap.serial, True);
  2067. break;
  2068. case UnmapNotify:
  2069. unmap_win (dpy, ev.xunmap.window, True);
  2070. break;
  2071. case ReparentNotify:
  2072. if (ev.xreparent.parent == root)
  2073. add_win (dpy, ev.xreparent.window, 0);
  2074. else
  2075. destroy_win (dpy, ev.xreparent.window, False, True);
  2076. break;
  2077. case CirculateNotify:
  2078. circulate_win (dpy, &ev.xcirculate);
  2079. break;
  2080. case Expose:
  2081. if (ev.xexpose.window == root)
  2082. {
  2083. int more = ev.xexpose.count + 1;
  2084. if (n_expose == size_expose)
  2085. {
  2086. if (expose_rects)
  2087. {
  2088. expose_rects = realloc (expose_rects,
  2089. (size_expose + more) *
  2090. sizeof (XRectangle));
  2091. size_expose += more;
  2092. }
  2093. else
  2094. {
  2095. expose_rects = malloc (more * sizeof (XRectangle));
  2096. size_expose = more;
  2097. }
  2098. }
  2099. expose_rects[n_expose].x = ev.xexpose.x;
  2100. expose_rects[n_expose].y = ev.xexpose.y;
  2101. expose_rects[n_expose].width = ev.xexpose.width;
  2102. expose_rects[n_expose].height = ev.xexpose.height;
  2103. n_expose++;
  2104. if (ev.xexpose.count == 0)
  2105. {
  2106. expose_root (dpy, root, expose_rects, n_expose);
  2107. n_expose = 0;
  2108. }
  2109. }
  2110. break;
  2111. case PropertyNotify:
  2112. for (p = 0; backgroundProps[p]; p++)
  2113. {
  2114. if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False))
  2115. {
  2116. if (rootTile)
  2117. {
  2118. XClearArea (dpy, root, 0, 0, 0, 0, True);
  2119. XRenderFreePicture (dpy, rootTile);
  2120. rootTile = None;
  2121. break;
  2122. }
  2123. }
  2124. }
  2125. /* check if Trans property was changed */
  2126. if (ev.xproperty.atom == opacityAtom)
  2127. {
  2128. /* reset mode and redraw window */
  2129. win * w = find_win(dpy, ev.xproperty.window);
  2130. if (w)
  2131. {
  2132. if (fadeTrans)
  2133. set_fade (dpy, w, w->opacity*1.0/OPAQUE, get_opacity_percent (dpy, w, 1.0),
  2134. fade_out_step, NULL, False, True, False);
  2135. else
  2136. {
  2137. w->opacity = get_opacity_prop(dpy, w, OPAQUE);
  2138. determine_mode(dpy, w);
  2139. if (w->shadow)
  2140. {
  2141. XRenderFreePicture (dpy, w->shadow);
  2142. w->shadow = None;
  2143. w->extents = win_extents (dpy, w);
  2144. }
  2145. }
  2146. }
  2147. }
  2148. break;
  2149. default:
  2150. if (ev.type == damage_event + XDamageNotify)
  2151. {
  2152. damage_win (dpy, (XDamageNotifyEvent *) &ev);
  2153. }
  2154. else if (ev.type == xshape_event + ShapeNotify)
  2155. {
  2156. shape_win (dpy, (XShapeEvent *) &ev);
  2157. }
  2158. break;
  2159. }
  2160. } while (QLength (dpy));
  2161. if (allDamage && !autoRedirect)
  2162. {
  2163. static int paint;
  2164. paint_all (dpy, allDamage);
  2165. paint++;
  2166. XSync (dpy, False);
  2167. allDamage = None;
  2168. clipChanged = False;
  2169. }
  2170. }
  2171. }