PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/xcm-0.5.0/src/xcm/xcm.c

#
C | 461 lines | 386 code | 54 blank | 21 comment | 77 complexity | f3c4d606ecb9a26c9974609e8baffdd9 MD5 | raw file
  1. /** xcm.c
  2. *
  3. * A X Color Management specification compatible information tool for server
  4. * based per window color management.
  5. *
  6. * @par License:
  7. * MIT <http://www.opensource.org/licenses/mit-license.php>
  8. * @par Copyright:
  9. * (c) 2011 - Kai-Uwe Behrmann <ku.b@gmx.de>
  10. *
  11. * gcc -Wall -g -I../.. xcm.c -o xcm `pkg-config --cflags --libs x11 xcm oyranos`
  12. */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <unistd.h> /* sleep() */
  17. #include <X11/Xcm/Xcm.h>
  18. #include <X11/Xcm/XcmEvents.h>
  19. #include <X11/extensions/Xfixes.h> /* XserverRegion */
  20. #include <X11/Xcm/Xcm.h> /* XcolorRegion */
  21. #include "xcm_version.h"
  22. #include "xcm_macros.h"
  23. #define OY_DBG_FORMAT_ "%s:%d %s() "
  24. #define OY_DBG_ARGS_ __FILE__,__LINE__,strrchr(__func__,'/')?strrchr(__func__,'/')+1:__func__
  25. int XcolorRegionFind(XcolorRegion * old_regions, unsigned long old_regions_n, Display * dpy, Window win, XRectangle * rectangle);
  26. void printfHelp(int argc, char ** argv)
  27. {
  28. fprintf( stderr, "\n");
  29. fprintf( stderr, "%s %s\n", argv[0],
  30. _("is a X11 color management client tool"));
  31. fprintf( stderr, " Xcm v%s config: %s devel period: %s\n",
  32. XCM_TOOLS_VERSION_NAME,
  33. XCM_TOOLS_CONFIG_DATE, XCM_TOOLS_DATE );
  34. fprintf( stderr, "\n");
  35. fprintf( stderr, "%s\n", _("Usage"));
  36. fprintf( stderr, " %s\n", _("List available windows:"));
  37. fprintf( stderr, " %s -l [--window-name]\n", argv[0]);
  38. fprintf( stderr, " --window-name %s\n", _("show window name"));
  39. fprintf( stderr, "\n");
  40. fprintf( stderr, " %s\n", _("Print infos about a window:"));
  41. fprintf( stderr, " %s -p --id=window_id\n", argv[0]);
  42. fprintf( stderr, "\n");
  43. fprintf( stderr, " %s\n", _("Set window region:"));
  44. fprintf( stderr, " %s -r\n",argv[0]);
  45. fprintf( stderr, " [-x pos_x -y pos_y --width width --height height|\n"
  46. " --geometry width_x_height_+_x_+_y]\n");
  47. fprintf( stderr, " --id=window_id [--profile filename.icc]\n");
  48. fprintf( stderr, "\n");
  49. fprintf( stderr, " %s\n", _("Delete window region:"));
  50. fprintf( stderr, " %s -d\n",argv[0]);
  51. fprintf( stderr, " [-x pos_x -y pos_y --width width --height height|\n"
  52. " --geometry width_x_height_+_x_+_y]\n");
  53. fprintf( stderr, " --id=window_id\n");
  54. fprintf( stderr, "\n");
  55. fprintf( stderr, " %s\n", _("Print a help text:"));
  56. fprintf( stderr, " %s -h\n", argv[0]);
  57. fprintf( stderr, "\n");
  58. fprintf( stderr, " %s\n", _("General options:"));
  59. fprintf( stderr, " --display=:0.0 %s\n", _("X11 display name"));
  60. fprintf( stderr, " -v %s\n", _("verbose"));
  61. fprintf( stderr, "\n");
  62. fprintf( stderr, "\n");
  63. }
  64. int main(int argc, char ** argv)
  65. {
  66. int id = 0;
  67. int print = 0;
  68. int print_window_name = 0;
  69. int list_windows = 0;
  70. int count = 0;
  71. const char * display = NULL;
  72. const char * geometry = NULL;
  73. Display * dpy = NULL;
  74. int screen = 0;
  75. Window win = 0,
  76. root;
  77. int place_region = 0;
  78. int delete_region = 0;
  79. int x = 0, y = 0, width = 0, height = 0;
  80. const char * profile_name = NULL;
  81. int verbose = 0;
  82. int result = 0;
  83. XserverRegion reg = 0;
  84. XcolorRegion region;
  85. int error;
  86. XRectangle rec[2] = { { 0,0,0,0 }, { 0,0,0,0 } };
  87. #ifdef HAVE_OY
  88. char * blob = 0;
  89. size_t size = 0;
  90. oyProfile_s * p = 0;
  91. XcolorProfile * profile = 0;
  92. #endif
  93. #ifdef USE_GETTEXT
  94. setlocale(LC_ALL,"");
  95. #endif
  96. if(argc >= 2)
  97. {
  98. int pos = 1, i;
  99. char *wrong_arg = 0;
  100. while(pos < argc)
  101. {
  102. switch(argv[pos][0])
  103. {
  104. case '-':
  105. for(i = 1; pos < argc && i < strlen(argv[pos]); ++i)
  106. switch (argv[pos][i])
  107. {
  108. case 'd': delete_region = 1; break;
  109. case 'l': list_windows = 1; break;
  110. case 'p': print = 1; break;
  111. case 'r': place_region = 1; break;
  112. case 'v': verbose += 1; break;
  113. case 'x': OY_PARSE_INT_ARG( x ); break;
  114. case 'y': OY_PARSE_INT_ARG( y ); break;
  115. case 'h':
  116. case '-':
  117. if(i == 1)
  118. {
  119. if(OY_IS_ARG("id"))
  120. { OY_PARSE_INT_ARG2( id, "id" ); break; }
  121. else if(OY_IS_ARG("width"))
  122. { OY_PARSE_INT_ARG2( width, "width" ); break; }
  123. else if(OY_IS_ARG("height"))
  124. { OY_PARSE_INT_ARG2( height, "height" ); break; }
  125. else if(OY_IS_ARG("profile"))
  126. { OY_PARSE_STRING_ARG2( profile_name, "profile" ); break; }
  127. else if(OY_IS_ARG("display"))
  128. { OY_PARSE_STRING_ARG2( display, "display" ); break; }
  129. else if(OY_IS_ARG("geometry"))
  130. { OY_PARSE_STRING_ARG2( geometry, "geometry" ); break; }
  131. else if(OY_IS_ARG("window-name"))
  132. { print_window_name = 1; i=100; break; }
  133. }
  134. default:
  135. printfHelp(argc, argv);
  136. exit (0);
  137. break;
  138. }
  139. break;
  140. default:
  141. printfHelp(argc, argv);
  142. exit (0);
  143. break;
  144. }
  145. if( wrong_arg )
  146. {
  147. fprintf(stderr, "%s %s\n", _("wrong argument to option:"), wrong_arg);
  148. printfHelp(argc, argv);
  149. exit(1);
  150. }
  151. ++pos;
  152. }
  153. } else
  154. {
  155. printfHelp(argc, argv);
  156. exit (0);
  157. }
  158. #ifdef HAVE_OY
  159. XcmICCprofileFromMD5FuncSet( fromMD5 );
  160. XcmICCprofileGetNameFuncSet( getName );
  161. #endif
  162. dpy = XOpenDisplay( display );
  163. if(!dpy)
  164. {
  165. fprintf( stderr, "%s %s\n", "unable to open display", display?display:"");
  166. exit(1);
  167. }
  168. if(geometry)
  169. {
  170. int matches = sscanf( geometry, "%ix%i+%i+%i",
  171. &width, &height, &x, &y );
  172. if(matches != 4 && strcmp(geometry,"0x0+0+0") != 0)
  173. {
  174. fprintf( stderr, "%s: --geometry WIDTHxHEIGHT+XPOS+YPOS (%s)\n",
  175. _("argument not recognised"), geometry);
  176. exit(1);
  177. }
  178. rec[0].x = x;
  179. rec[0].y = y;
  180. rec[0].width = width;
  181. rec[0].height = height;
  182. }
  183. win = (Window) id;
  184. screen = DefaultScreen( dpy );
  185. root = XRootWindow( dpy, screen );
  186. if(list_windows)
  187. {
  188. Status status = 0;
  189. if(!verbose)
  190. {
  191. {
  192. Window root_return = 0,
  193. parent_return = 0,
  194. * children_return = 0,
  195. * wins = 0;
  196. unsigned int nchildren_return = 0, wins_n = 0;
  197. int i;
  198. XWindowAttributes window_attributes_return;
  199. XSync( dpy, 0 );
  200. status = XQueryTree( dpy, root,
  201. &root_return, &parent_return,
  202. &children_return, &nchildren_return );
  203. if(status == 0) fprintf( stderr, "%d: XQueryTree failed\n", __LINE__ );
  204. wins = (Window*)malloc(sizeof(Window) * nchildren_return );
  205. memcpy( wins, children_return, sizeof(Window) * nchildren_return );
  206. XFree( children_return );
  207. children_return = wins; wins = 0;
  208. for(i = nchildren_return - 1; i >= 0; --i)
  209. {
  210. root_return = 0;
  211. status = XQueryTree( dpy, children_return[i],
  212. &root_return, &parent_return,
  213. &wins, &wins_n );
  214. if(status == 0)fprintf( stderr, "%d: XQueryTree failed\n", __LINE__ );
  215. status = XGetWindowAttributes( dpy, children_return[i],
  216. &window_attributes_return );
  217. if(status == 0)fprintf( stderr, "%d: XQueryTree failed\n", __LINE__ );
  218. if(window_attributes_return.map_state == IsViewable &&
  219. parent_return == root)
  220. {
  221. if(verbose)
  222. fprintf( stdout, "%s",
  223. XcmePrintWindowRegions( dpy, children_return[i], 0 ));
  224. fprintf( stdout, "%d", (int)children_return[i] );
  225. if(print_window_name)
  226. fprintf( stdout, " %s",
  227. XcmePrintWindowName(dpy, children_return[i]) );
  228. fprintf( stdout, "\n" );
  229. ++count;
  230. }
  231. XFree( wins );
  232. }
  233. free( children_return );
  234. }
  235. } else
  236. {
  237. XcmeContext_s * c = XcmeContext_Create( display );
  238. XcmeContext_Release( &c );
  239. }
  240. } else if(print)
  241. {
  242. if(!win)
  243. {
  244. fprintf( stderr, "%s\n", _("The integer window ID is missed. Use option: --id 12345"));
  245. exit(1);
  246. }
  247. fprintf( stdout, "%s\n", XcmePrintWindowRegions( dpy, win, 1 ) );
  248. } else if(place_region)
  249. {
  250. int need_wait = 1;
  251. #ifdef HAVE_OY
  252. /* Upload a ICC profile to X11 root window */
  253. if(profile_name)
  254. {
  255. p = oyProfile_FromFile( profile_name, 0,0 );
  256. if(p)
  257. {
  258. blob = oyProfile_GetMem( p, &size, 0,0 );
  259. if(blob && size)
  260. {
  261. /* Create a XcolorProfile object that will be uploaded to the display.*/
  262. profile = malloc(sizeof(XcolorProfile) + size);
  263. oyProfile_GetMD5(p, OY_FROM_PROFILE, (uint32_t*)profile->md5);
  264. profile->length = htonl(size);
  265. memcpy(profile + 1, blob, size);
  266. result = XcolorProfileUpload( dpy, profile );
  267. if(result)
  268. printf("XcolorProfileUpload: %d\n", result);
  269. }
  270. oyProfile_Release( &p );
  271. }
  272. }
  273. #endif
  274. reg = XFixesCreateRegion( dpy, rec, 1);
  275. region.region = htonl(reg);
  276. #ifdef HAVE_OY
  277. if(blob && size)
  278. memcpy(region.md5, profile->md5, 16);
  279. else
  280. #endif
  281. memset( region.md5, 0, 16 );
  282. if(rec[0].x || rec[0].y || rec[0].width || rec[0].height)
  283. {
  284. /* upload the new or changed region to the X server */
  285. error = XcolorRegionInsert( dpy, win, 0, &region, 1 );
  286. if(error)
  287. printf( OY_DBG_FORMAT_
  288. "XcolorRegionInsert failed %d\n",
  289. OY_DBG_ARGS_, error );
  290. } else
  291. {
  292. unsigned long nRegions = 0;
  293. XcolorRegion * r = XcolorRegionFetch( dpy, win, &nRegions );
  294. need_wait = 0;
  295. if(nRegions && r)
  296. {
  297. error = XcolorRegionDelete( dpy, win, 0, nRegions );
  298. fprintf(stderr, "deleted %lu region%c\n", nRegions, nRegions==1?' ':'s');
  299. XFree( r ); r = 0;
  300. } else
  301. {
  302. fprintf(stderr, "no region to delete \n");
  303. }
  304. }
  305. XFlush( dpy );
  306. /** Closing the display object will destroy all XFixes regions automatically
  307. * by Xorg. Therefore we loop here to keep the XFixes regions alive. */
  308. if(need_wait)
  309. while(1) sleep(2);
  310. } if(delete_region)
  311. {
  312. XcolorRegion *old_regions = 0;
  313. unsigned long old_regions_n = 0;
  314. int pos = -1;
  315. /* get old regions */
  316. old_regions = XcolorRegionFetch( dpy, win, &old_regions_n );
  317. /* remove specified region */
  318. pos = XcolorRegionFind( old_regions, old_regions_n, dpy, win, rec );
  319. XFree( old_regions );
  320. if(pos >= 0)
  321. {
  322. int undeleted_n = old_regions_n;
  323. XcolorRegionDelete( dpy, win, pos, 1 );
  324. old_regions = XcolorRegionFetch( dpy, win, &old_regions_n );
  325. if(undeleted_n - old_regions_n != 1)
  326. printf( OY_DBG_FORMAT_"removed %d; have still %d\n", OY_DBG_ARGS_,
  327. pos, (int)old_regions_n );
  328. else
  329. fprintf( stderr, "removed position %d\n", pos );
  330. } else
  331. printf( "region not found: %s in %lu\n", geometry, old_regions_n );
  332. XFlush( dpy );
  333. }
  334. XCloseDisplay( dpy );
  335. return result;
  336. }
  337. int XcolorRegionFind(XcolorRegion * old_regions, unsigned long old_regions_n, Display * dpy, Window win, XRectangle * rectangle)
  338. {
  339. XRectangle * rect = 0;
  340. int nRect = 0;
  341. int pos = -1;
  342. int i, j;
  343. /* get old regions */
  344. old_regions = XcolorRegionFetch( dpy, win, &old_regions_n );
  345. /* search region */
  346. for(i = 0; i < old_regions_n; ++i)
  347. {
  348. if(!old_regions[i].region || pos >= 0)
  349. break;
  350. rect = XFixesFetchRegion( dpy, ntohl(old_regions[i].region),
  351. &nRect );
  352. for(j = 0; j < nRect; ++j)
  353. {
  354. #ifdef HAVE_OY
  355. if(oy_debug)
  356. printf( OY_DBG_FORMAT_
  357. "reg[%d]: %dx%d+%d+%d %dx%d+%d+%d\n",
  358. OY_DBG_ARGS_, i,
  359. rectangle->width, rectangle->height,
  360. rectangle->x, rectangle->y,
  361. rect[j].width, rect[j].height, rect[j].x, rect[j].y
  362. );
  363. #endif
  364. if(rectangle->x == rect[j].x &&
  365. rectangle->y == rect[j].y &&
  366. rectangle->width == rect[j].width &&
  367. rectangle->height == rect[j].height )
  368. {
  369. pos = i;
  370. break;
  371. }
  372. }
  373. }
  374. return pos;
  375. }
  376. #ifdef HAVE_OY
  377. void * fromMD5 ( const void * md5_hash,
  378. size_t * size,
  379. void *(allocate_func)(size_t) )
  380. {
  381. void * data = 0;
  382. oyProfile_s * p = oyProfile_FromMD5( (uint32_t*)md5_hash, 0 );
  383. data = oyProfile_GetMem( p, size, 0, allocate_func );
  384. oyProfile_Release( &p );
  385. return data;
  386. }
  387. char * getName ( const void * data,
  388. size_t size,
  389. void *(allocate_func)(size_t),
  390. int file_name )
  391. {
  392. char * text = 0;
  393. const char * t = 0;
  394. oyProfile_s * p = oyProfile_FromMem( size, (void*)data, 0, 0 );
  395. if(file_name)
  396. t = oyProfile_GetFileName( p, -1 );
  397. else
  398. t = oyProfile_GetText( p, oyNAME_DESCRIPTION );
  399. if(t && t[0])
  400. {
  401. text = (char*)allocate_func( strlen(t) + 1 );
  402. strcpy( text, t );
  403. }
  404. oyProfile_Release( &p );
  405. return text;
  406. }
  407. #endif