PageRenderTime 105ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/panel.c

https://bitbucket.org/csgordon/trayer
C | 620 lines | 523 code | 70 blank | 27 comment | 155 complexity | 3cab116f51b035f0898a4b3f14dd4923 MD5 | raw file
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <locale.h>
  8. #include <string.h>
  9. #include <signal.h>
  10. #include <gdk/gdk.h>
  11. #include "panel.h"
  12. #include "misc.h"
  13. #include "bg.h"
  14. #include "main.h"
  15. #include "gdk-helper.h"
  16. #define VERSION "1.1.1"
  17. static gchar version[] = VERSION;
  18. int distance=0, distancefrom=DISTANCEFROM_TOP;
  19. int expand=1 , padding=0;
  20. //#define DEBUG
  21. #include "dbg.h"
  22. static panel *p;
  23. static gchar *transparent_rc = "style 'transparent-style'\n"
  24. "{\n"
  25. "bg_pixmap[NORMAL] = \"<parent>\"\n"
  26. "bg_pixmap[INSENSITIVE] = \"<parent>\"\n"
  27. "bg_pixmap[PRELIGHT] = \"<parent>\"\n"
  28. "bg_pixmap[SELECTED] = \"<parent>\"\n"
  29. "bg_pixmap[ACTIVE] = \"<parent>\"\n"
  30. "}\n"
  31. "class \"GtkEventBox\" style \"transparent-style\"\n"
  32. "class \"GtkSocket\" style \"transparent-style\"\n"
  33. "class \"GtkBar\" style \"transparent-style\"\n"
  34. "class \"GtkBox\" style \"transparent-style\"\n"
  35. "\n";
  36. static void set_bg(GtkWidget *widget, panel *p);
  37. /****************************************************
  38. * panel's handlers for WM events *
  39. ****************************************************/
  40. /*
  41. static void
  42. panel_del_wm_strut(panel *p)
  43. {
  44. XDeleteProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT);
  45. XDeleteProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
  46. }
  47. */
  48. static void
  49. panel_set_wm_strut(panel *p)
  50. {
  51. unsigned int data[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  52. int i = 4;
  53. ENTER;
  54. if (!GTK_WIDGET_MAPPED (p->topgwin))
  55. return;
  56. switch (p->edge) {
  57. case EDGE_LEFT:
  58. i = 0;
  59. data[i] = p->aw;
  60. data[4 + i*2] = p->ay;
  61. data[5 + i*2] = p->ay + p->ah - 1;
  62. break;
  63. case EDGE_RIGHT:
  64. i = 1;
  65. data[i] = p->aw;
  66. data[4 + i*2] = p->ay;
  67. data[5 + i*2] = p->ay + p->ah - 1;
  68. break;
  69. case EDGE_TOP:
  70. i = 2;
  71. data[i] = p->ah;
  72. data[4 + i*2] = p->ax;
  73. data[5 + i*2] = p->ax + p->aw - 1;
  74. break;
  75. case EDGE_BOTTOM:
  76. i = 3;
  77. data[i] = p->ah;
  78. data[4 + i*2] = p->ax;
  79. data[5 + i*2] = p->ax + p->aw - 1 ;
  80. break;
  81. default:
  82. ERR("wrong edge %d. strut won't be set\n", p->edge);
  83. RET();
  84. }
  85. DBG("type %d. width %d. from %d to %d\n", i, data[i], data[4 + i*2], data[5 + i*2]);
  86. XChangeProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
  87. XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 12);
  88. /* old spec, for wms that do not support STRUT_PARTIAL */
  89. XChangeProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT,
  90. XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
  91. RET();
  92. }
  93. static GdkFilterReturn
  94. panel_wm_events(GdkXEvent *xevent, GdkEvent *event, panel *p)
  95. {
  96. Atom at;
  97. Window win;
  98. XEvent *ev = (XEvent *) xevent;
  99. ENTER;
  100. DBG("win = 0x%x\n", ev->xproperty.window);
  101. if ( ev->type != PropertyNotify )
  102. RET(GDK_FILTER_CONTINUE);
  103. at = ev->xproperty.atom;
  104. win = ev->xproperty.window;
  105. if (win == GDK_ROOT_WINDOW()) {
  106. if (at == a_XROOTPMAP_ID) {
  107. bg_rootbg_changed();
  108. set_bg(p->topgwin, p);
  109. gtk_widget_queue_draw(p->topgwin);
  110. DBG("a_XROOTPMAP_ID\n");
  111. }
  112. }
  113. RET(GDK_FILTER_CONTINUE);
  114. }
  115. /****************************************************
  116. * panel's handlers for GTK events *
  117. ****************************************************/
  118. static gint
  119. panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
  120. {
  121. ENTER;
  122. RET(FALSE);
  123. }
  124. static gint
  125. panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
  126. {
  127. ENTER;
  128. // TODO need to cleanup
  129. gtk_main_quit();
  130. RET(FALSE);
  131. }
  132. static gint
  133. panel_size_req(GtkWidget *widget, GtkRequisition *req, panel *p)
  134. {
  135. ENTER;
  136. DBG("IN req=(%d, %d)\n", req->width, req->height);
  137. if (p->widthtype == WIDTH_REQUEST)
  138. p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
  139. if (p->heighttype == HEIGHT_REQUEST)
  140. p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
  141. calculate_position(p, distance,distancefrom);
  142. req->width = p->aw;
  143. req->height = p->ah;
  144. DBG("OUT req=(%d, %d)\n", req->width, req->height);
  145. RET( TRUE );
  146. }
  147. static gint
  148. panel_size_alloc(GtkWidget *widget, GtkAllocation *a, panel *p)
  149. {
  150. ENTER;
  151. DBG("new alloc: size (%d, %d). pos (%d, %d)\n", a->width, a->height, a->x, a->y);
  152. DBG("old alloc: size (%d, %d). pos (%d, %d)\n", p->aw, p->ah, p->ax, p->ay);
  153. if (p->widthtype == WIDTH_REQUEST)
  154. p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
  155. if (p->heighttype == HEIGHT_REQUEST)
  156. p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
  157. calculate_position(p, distance,distancefrom);
  158. DBG("pref alloc: size (%d, %d). pos (%d, %d)\n", p->aw, p->ah, p->ax, p->ay);
  159. if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
  160. DBG("actual coords eq to preffered. just returning\n");
  161. RET(TRUE);
  162. }
  163. gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
  164. if (p->setstrut)
  165. panel_set_wm_strut(p);
  166. RET(TRUE);
  167. }
  168. /****************************************************
  169. * panel creation *
  170. ****************************************************/
  171. static void
  172. set_bg(GtkWidget *widget, panel *p)
  173. {
  174. ENTER;
  175. if (p->gtopbg)
  176. g_object_unref(p->gtopbg);
  177. p->gtopbg = bg_new_for_win(p->topxwin);
  178. modify_drawable(p->gtopbg, p->topgwin->style->black_gc, p->tintcolor, p->alpha);
  179. gdk_window_set_back_pixmap(p->topgwin->window, p->gtopbg, FALSE);
  180. gdk_window_clear(p->topgwin->window);
  181. gtk_widget_queue_draw_area (p->topgwin, 0, 0, 2000, 2000);
  182. RET();
  183. }
  184. static void
  185. panel_style_set(GtkWidget *widget, GtkStyle *s, panel *p)
  186. {
  187. ENTER;
  188. gtk_rc_parse_string(transparent_rc);
  189. if (GTK_WIDGET_REALIZED(widget))
  190. set_bg(widget, p);
  191. RET();
  192. }
  193. static gboolean
  194. panel_configure_event(GtkWidget *widget, GdkEventConfigure *event, panel *p)
  195. {
  196. static gint x = 0, y = 0, width = 0, height = 0;
  197. ENTER;
  198. if (x == event->x && y == event->y
  199. && width == event->width && height == event->height)
  200. RET(FALSE);
  201. x = event->x;
  202. y = event->y;
  203. width = event->width;
  204. height = event->height;
  205. set_bg(widget, p);
  206. RET(FALSE);
  207. }
  208. void
  209. panel_start_gui(panel *p)
  210. {
  211. ENTER;
  212. //gtk_rc_parse_string(transparent_rc);
  213. p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  214. gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
  215. gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
  216. gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "trayer");
  217. gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
  218. g_signal_connect ( G_OBJECT(p->topgwin) , "delete-event" , G_CALLBACK(panel_delete_event) , p);
  219. g_signal_connect ( G_OBJECT(p->topgwin) , "destroy-event", G_CALLBACK(panel_destroy_event), p);
  220. g_signal_connect ( G_OBJECT (p->topgwin), "size-request" , G_CALLBACK(panel_size_req) , p);
  221. g_signal_connect ( G_OBJECT (p->topgwin), "size-allocate", G_CALLBACK(panel_size_alloc), p);
  222. if (p->transparent) {
  223. g_signal_connect (G_OBJECT (p->topgwin), "configure-event", G_CALLBACK(panel_configure_event), p);
  224. g_signal_connect (G_OBJECT (p->topgwin), "style-set", G_CALLBACK( panel_style_set), p);
  225. }
  226. gtk_widget_realize(p->topgwin);
  227. gdk_window_set_decorations(p->topgwin->window, 0);
  228. gtk_widget_set_app_paintable(p->topgwin, TRUE);
  229. p->lbox = p->my_box_new(FALSE, 0);
  230. gtk_container_set_border_width(GTK_CONTAINER(p->lbox), 0);
  231. gtk_container_add(GTK_CONTAINER(p->topgwin), p->lbox);
  232. gtk_widget_show(p->lbox);
  233. if (p->allign == ALLIGN_RIGHT) {
  234. GtkWidget * expander = p->my_box_new(FALSE, 0);
  235. gtk_box_pack_start(GTK_BOX(p->lbox), expander, TRUE, TRUE, 0);
  236. gtk_widget_show(expander);
  237. }
  238. p->box = p->my_box_new(FALSE, 1);
  239. gtk_container_set_border_width(GTK_CONTAINER(p->box), 1);
  240. gtk_box_pack_start(GTK_BOX(p->lbox), p->box, FALSE, TRUE, 0);
  241. gtk_widget_show(p->box);
  242. // get properties on topgwin
  243. p->topGdkWindow = gtk_widget_get_window(p->topgwin);
  244. p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
  245. bg_init(gdk_helper_display());
  246. /* make our window unfocusable */
  247. gdk_window_set_accept_focus(p->topGdkWindow,False);
  248. if (p->setdocktype) {
  249. gdk_window_set_type_hint(p->topGdkWindow,GDK_WINDOW_TYPE_HINT_DOCK);
  250. }
  251. Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
  252. /************************/
  253. /* Window Mapping Point */
  254. gtk_widget_show_all(p->topgwin);
  255. Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
  256. gdk_window_stick ( p->topGdkWindow);
  257. gdk_window_set_skip_pager_hint ( p->topGdkWindow, True );
  258. gdk_window_set_skip_taskbar_hint ( p->topGdkWindow, True );
  259. XSelectInput (gdk_helper_display(), GDK_ROOT_WINDOW(), PropertyChangeMask);
  260. XSelectInput (gdk_helper_display(), p->topxwin, PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
  261. gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_wm_events, p);
  262. calculate_position(p, distance,distancefrom);
  263. gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
  264. if (p->setstrut)
  265. panel_set_wm_strut(p);
  266. RET();
  267. }
  268. static int
  269. panel_parse_global(panel *p)
  270. {
  271. ENTER;
  272. p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
  273. ? ORIENT_HORIZ : ORIENT_VERT;
  274. if (p->orientation == ORIENT_HORIZ) {
  275. p->my_box_new = gtk_hbox_new;
  276. } else {
  277. p->my_box_new = gtk_vbox_new;
  278. }
  279. if (p->width < 0)
  280. p->width = 100;
  281. if (p->widthtype == WIDTH_PERCENT && p->width > 100)
  282. p->width = 100;
  283. p->heighttype = HEIGHT_PIXEL;
  284. if (p->heighttype == HEIGHT_PIXEL) {
  285. if (p->height < PANEL_HEIGHT_MIN)
  286. p->height = PANEL_HEIGHT_MIN;
  287. else if (p->height > PANEL_HEIGHT_MAX)
  288. p->height = PANEL_HEIGHT_MAX;
  289. }
  290. panel_start_gui(p);
  291. RET(1);
  292. }
  293. int
  294. panel_start(panel *p)
  295. {
  296. /* parse global section */
  297. ENTER;
  298. if (!panel_parse_global(p))
  299. RET(0);
  300. if (!tray_constructor(p))
  301. RET(0);
  302. gtk_widget_show_all(p->topgwin);
  303. RET(1);
  304. }
  305. void panel_stop(panel *p)
  306. {
  307. ENTER;
  308. tray_destructor(p);
  309. XSelectInput (gdk_helper_display(), GDK_ROOT_WINDOW(), NoEventMask);
  310. gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_wm_events, p);
  311. gtk_widget_destroy(p->topgwin);
  312. RET();
  313. }
  314. void
  315. usage()
  316. {
  317. ENTER;
  318. printf("trayer %s - lightweight GTK2+ systray for UNIX desktops\n", version);
  319. printf("Command line options:\n");
  320. printf(" -h -- print this help and exit:\n");
  321. printf(" -v -- print version and exit:\n");
  322. printf(" --edge <left|right|top|bottom|none> (default:bottom) \n");
  323. printf(" --align <left|right|center> (default:center)\n");
  324. printf(" --margin <number>\n");
  325. printf(" --widthtype <request|pixel|percent> (default:percent)\n");
  326. printf(" --width <number> (default:100)\n");
  327. printf(" --heighttype <request|pixel> (default:pixel)\n");
  328. printf(" --height <number> (default:26)\n");
  329. printf(" --SetDockType <true|false> (default:true)\n");
  330. printf(" --SetPartialStrut <true|false> (default:false)\n");
  331. printf(" --transparent <true|false> (default:false)\n");
  332. printf(" --alpha <number> (default:127)\n");
  333. printf(" --tint <int>\n");
  334. printf(" --distance <number>\n");
  335. printf(" --distancefrom <number>\n");
  336. printf(" --expand <false|true>\n");
  337. printf(" --padding <number>\n");
  338. printf(" --monitor <number> (default:0)\n");
  339. }
  340. void
  341. handle_error(Display * d, XErrorEvent * ev)
  342. {
  343. char buf[256];
  344. ENTER;
  345. XGetErrorText(gdk_helper_display(), ev->error_code, buf, 256);
  346. ERR( "trayer : X error: %s\n", buf);
  347. RET();
  348. }
  349. int
  350. main(int argc, char *argv[], char *env[])
  351. {
  352. int i;
  353. ENTER;
  354. setlocale(LC_CTYPE, "");
  355. gtk_init(&argc, &argv);
  356. XSetLocaleModifiers("");
  357. XSetErrorHandler((XErrorHandler) handle_error);
  358. // resolve xatoms
  359. resolve_atoms();
  360. p = g_new0(panel, 1);
  361. memset(p, 0, sizeof(panel));
  362. p->allign = ALLIGN_CENTER;
  363. p->edge = EDGE_BOTTOM;
  364. p->widthtype = WIDTH_PERCENT;
  365. p->width = 100;
  366. p->heighttype = HEIGHT_PIXEL;
  367. p->height = PANEL_HEIGHT_DEFAULT;
  368. p->setdocktype = 1;
  369. p->setstrut = 0;
  370. p->transparent = 0;
  371. p->alpha = 127;
  372. p->tintcolor = 0xFFFFFFFF;
  373. p->xtopbg = None;
  374. p->monitor = 0;
  375. for (i = 1; i < argc; i++) {
  376. if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
  377. usage();
  378. exit(0);
  379. } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
  380. printf("trayer %s\n", version);
  381. exit(0);
  382. } else if (!strcmp(argv[i], "--edge")) {
  383. i++;
  384. if (i == argc) {
  385. ERR( "trayer: missing edge parameter value\n");
  386. usage();
  387. exit(1);
  388. } else {
  389. p->edge = str2num(edge_pair, argv[i], EDGE_NONE);
  390. }
  391. } else if (!strcmp(argv[i], "--align")) {
  392. i++;
  393. if (i == argc) {
  394. ERR( "trayer: missing align parameter value\n");
  395. usage();
  396. exit(1);
  397. } else {
  398. p->allign = str2num(allign_pair, argv[i], ALLIGN_NONE);
  399. }
  400. } else if (!strcmp(argv[i], "--margin")) {
  401. i++;
  402. if (i == argc) {
  403. ERR( "trayer: missing margin parameter value\n");
  404. usage();
  405. exit(1);
  406. } else {
  407. p->margin = atoi(argv[i]);
  408. }
  409. } else if (!strcmp(argv[i], "--widthtype")) {
  410. i++;
  411. if (i == argc) {
  412. ERR( "trayer: missing widthtype parameter value\n");
  413. usage();
  414. exit(1);
  415. } else {
  416. p->widthtype = str2num(width_pair, argv[i], WIDTH_NONE);
  417. }
  418. } else if (!strcmp(argv[i], "--width")) {
  419. i++;
  420. if (i == argc) {
  421. ERR( "trayer: missing width parameter value\n");
  422. usage();
  423. exit(1);
  424. } else {
  425. p->width = atoi(argv[i]);
  426. }
  427. } else if (!strcmp(argv[i], "--heighttype")) {
  428. i++;
  429. if (i == argc) {
  430. ERR( "trayer: missing heighttype parameter value\n");
  431. usage();
  432. exit(1);
  433. } else {
  434. p->heighttype = str2num(height_pair, argv[i], HEIGHT_NONE);
  435. }
  436. } else if (!strcmp(argv[i], "--height")) {
  437. i++;
  438. if (i == argc) {
  439. ERR( "trayer: missing height parameter value\n");
  440. usage();
  441. exit(1);
  442. } else {
  443. p->height = atoi(argv[i]);
  444. }
  445. } else if (!strcmp(argv[i], "--SetDockType")) {
  446. i++;
  447. if (i == argc) {
  448. ERR( "trayer: missing SetDockType parameter value\n");
  449. usage();
  450. exit(1);
  451. } else {
  452. p->setdocktype = str2num(bool_pair, argv[i], 0);
  453. }
  454. } else if (!strcmp(argv[i], "--SetPartialStrut")) {
  455. i++;
  456. if (i == argc) {
  457. ERR( "trayer: missing SetPartialStrut parameter value\n");
  458. usage();
  459. exit(1);
  460. } else {
  461. p->setstrut = str2num(bool_pair, argv[i], 0);
  462. }
  463. } else if (!strcmp(argv[i], "--transparent")) {
  464. i++;
  465. if (i == argc) {
  466. ERR( "trayer: missing transparent parameter value\n");
  467. usage();
  468. exit(1);
  469. } else {
  470. p->transparent = str2num(bool_pair, argv[i], 1);
  471. }
  472. } else if (!strcmp(argv[i], "--alpha")) {
  473. i++;
  474. if (i == argc) {
  475. ERR( "trayer: missing alpha parameter value\n");
  476. usage();
  477. exit(1);
  478. } else {
  479. p->alpha = atoi(argv[i]);
  480. }
  481. } else if (!strcmp(argv[i], "--tint")) {
  482. i++;
  483. if (i == argc) {
  484. ERR( "trayer: missing tint parameter value\n");
  485. usage();
  486. exit(1);
  487. } else {
  488. p->tintcolor = strtoul(argv[i], NULL, 0);
  489. }
  490. } else if (!strcmp(argv[i], "--distance")) {
  491. i++;
  492. if (i == argc) {
  493. ERR( "trayer: missing distance parameter value\n");
  494. usage();
  495. exit(1);
  496. } else {
  497. distance = atoi(argv[i]);
  498. }
  499. } else if (!strcmp(argv[i], "--distancefrom")) {
  500. i++;
  501. if (i == argc) {
  502. ERR( "trayer: missing distancefrom parameter value\n");
  503. usage();
  504. exit(1);
  505. } else {
  506. distancefrom = str2num(distancefrom_pair, argv[i], DISTANCEFROM_NONE);
  507. }
  508. } else if (!strcmp(argv[i], "--expand")) {
  509. i++;
  510. if (i == argc) {
  511. ERR( "trayer: missing expand parameter value\n");
  512. usage();
  513. exit(1);
  514. } else {
  515. expand = str2num(bool_pair, argv[i], 1);
  516. }
  517. } else if (!strcmp(argv[i], "--padding")) {
  518. i++;
  519. if (i == argc) {
  520. ERR( "trayer: missing padding parameter value\n");
  521. usage();
  522. exit(1);
  523. } else {
  524. padding = atoi(argv[i]);
  525. }
  526. } else if (!strcmp(argv[i], "--monitor")) {
  527. i++;
  528. if (i == argc) {
  529. ERR( "trayer: missing monitor parameter value\n");
  530. usage();
  531. exit(1);
  532. } else {
  533. p->monitor = atoi(argv[i]);
  534. }
  535. } else {
  536. printf("trayer: unknown option - %s\n", argv[i]);
  537. usage();
  538. exit(1);
  539. }
  540. }
  541. g_return_val_if_fail (p != NULL, 1);
  542. if (!panel_start(p)) {
  543. ERR( "trayer: can't start panel\n");
  544. exit(1);
  545. }
  546. gtk_main();
  547. panel_stop(p);
  548. g_free(p);
  549. exit(0);
  550. }