1 /* GKrellM 2 | Copyright (C) 1999-2019 Bill Wilson 3 | 4 | Author: Bill Wilson billw@gkrellm.net 5 | Latest versions might be found at: http://gkrellm.net 6 | 7 | 8 | GKrellM is free software: you can redistribute it and/or modify it 9 | under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | GKrellM is distributed in the hope that it will be useful, but WITHOUT 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 | License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see http://www.gnu.org/licenses/ 20 | 21 | 22 | Additional permission under GNU GPL version 3 section 7 23 | 24 | If you modify this program, or any covered work, by linking or 25 | combining it with the OpenSSL project's OpenSSL library (or a 26 | modified version of that library), containing parts covered by 27 | the terms of the OpenSSL or SSLeay licenses, you are granted 28 | additional permission to convey the resulting work. 29 | Corresponding Source for a non-source form of such a combination 30 | shall include the source code for the parts of OpenSSL used as well 31 | as that of the covered work. 32 */ 33 34 #include "gkrellm.h" 35 #include "gkrellm-private.h" 36 37 #include <errno.h> 38 #if !defined(F_TLOCK) 39 #include <sys/file.h> 40 #endif 41 42 #include <pwd.h> 43 #include <sys/types.h> 44 45 #include <gdk/gdkx.h> 46 #include <X11/Xmd.h> 47 #include <X11/SM/SMlib.h> 48 #include <X11/Xatom.h> 49 50 #define _NET_WM_STATE_REMOVE 0 51 #define _NET_WM_STATE_ADD 1 52 #define _NET_WM_STATE_TOGGLE 2 53 54 55 static Pixmap root_xpixmap = None; 56 static GdkGC *trans_gc; 57 58 static gchar *client_id; 59 60 61 void 62 gkrellm_winop_reset(void) 63 { 64 root_xpixmap = None; 65 } 66 67 68 static void 69 cb_smc_save_yourself(SmcConn smc_conn, SmPointer client_data, gint save_type, 70 gboolean shutdown, gint interact_style, gboolean fast) 71 { 72 gkrellm_save_all(); 73 SmcSaveYourselfDone(smc_conn, True); 74 } 75 76 static void 77 cb_smc_die(SmcConn smc_conn, SmPointer client_data) 78 { 79 SmcCloseConnection(smc_conn, 0, NULL); 80 gtk_main_quit(); 81 } 82 83 static void 84 cb_smc_save_complete(SmcConn smc_conn, SmPointer client_data) 85 { 86 } 87 88 static void 89 cb_smc_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data) 90 { 91 } 92 93 static void 94 cb_ice_connection_messages(IceConn ice_connection, gint source, 95 GdkInputCondition condition) 96 { 97 IceProcessMessages(ice_connection, NULL, NULL); 98 } 99 100 static void 101 smc_connect(gint argc, gchar **argv) 102 { 103 SmProp userid, program, restart, clone, pid, *props[6]; 104 #if 0 105 SmProp restart_style; 106 CARD8 restartstyle; 107 SmPropValue restart_style_val; 108 #endif 109 SmPropValue userid_val, pid_val; 110 SmcCallbacks *callbacks; 111 SmcConn smc_connection; 112 IceConn ice_connection; 113 struct passwd *pwd; 114 uid_t uid; 115 gchar error_string[256], pid_str[16], userid_string[256]; 116 gulong mask; 117 gint i, j; 118 119 /* Session manager callbacks 120 */ 121 callbacks = g_new0(SmcCallbacks, 1); 122 callbacks->save_yourself.callback = cb_smc_save_yourself; 123 callbacks->die.callback = cb_smc_die; 124 callbacks->save_complete.callback = cb_smc_save_complete; 125 callbacks->shutdown_cancelled.callback = cb_smc_shutdown_cancelled; 126 127 mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask 128 | SmcShutdownCancelledProcMask; 129 130 smc_connection = SmcOpenConnection(NULL /* SESSION_MANAGER env variable */, 131 NULL /* share ICE connection */, 132 SmProtoMajor, SmProtoMinor, mask, 133 callbacks, 134 _GK.session_id, &client_id, 135 sizeof(error_string), error_string); 136 g_free(callbacks); 137 if (!smc_connection) 138 return; 139 140 gdk_set_sm_client_id(client_id); 141 142 /* Session manager properties - 4 are required. 143 */ 144 userid.name = SmUserID; 145 userid.type = SmARRAY8; 146 userid.num_vals = 1; 147 userid.vals = &userid_val; 148 uid = getuid(); 149 if ((pwd = getpwuid(uid)) != NULL) 150 snprintf(userid_string, sizeof(userid_string), "%s", pwd->pw_name); 151 else 152 snprintf(userid_string, sizeof(userid_string), "%d", uid); 153 userid_val.value = userid_string; 154 userid_val.length = strlen(userid_string); 155 156 pid.name = SmProcessID; 157 pid.type = SmARRAY8; 158 pid.num_vals = 1; 159 pid.vals = &pid_val; 160 sprintf(pid_str, "%i", getpid()); 161 pid_val.value = (SmPointer) pid_str; 162 pid_val.length = strlen(pid_str); 163 164 restart.name = SmRestartCommand; 165 restart.type = SmLISTofARRAY8; 166 restart.vals = g_new0(SmPropValue, argc + 2); 167 j = 0; 168 for (i = 0; i < argc; ++i) { 169 if ( strcmp(argv[i], "--sm-client-id") ) { 170 restart.vals[j].value = (SmPointer) argv[i]; 171 restart.vals[j++].length = strlen(argv[i]); 172 } else 173 i++; 174 } 175 restart.vals[j].value = (SmPointer) "--sm-client-id"; 176 restart.vals[j++].length = strlen("--sm-client-id"); 177 restart.vals[j].value = (SmPointer) client_id; 178 restart.vals[j++].length = strlen(client_id); 179 restart.num_vals = j; 180 181 #if 0 182 restartstyle = SmRestartImmediately; 183 restart_style.name = SmRestartStyleHint; 184 restart_style.type = SmCARD8; 185 restart_style.num_vals = 1; 186 restart_style.vals = &restart_style_val; 187 restart_style_val.value = (SmPointer) &restartstyle; 188 restart_style_val.length = 1; 189 #endif 190 191 clone.name = SmCloneCommand; 192 clone.type = SmLISTofARRAY8; 193 clone.vals = restart.vals; 194 clone.num_vals = restart.num_vals - 2; 195 196 program.name = SmProgram; 197 program.type = SmARRAY8; 198 program.vals = restart.vals; 199 program.num_vals = 1; 200 201 props[0] = &program; 202 props[1] = &userid; 203 props[2] = &restart; 204 props[3] = &clone; 205 props[4] = &pid; 206 #if 0 207 /* Make this an option? */ 208 props[5] = &restart_style; 209 SmcSetProperties(smc_connection, 6, props); 210 #else 211 SmcSetProperties(smc_connection, 5, props); 212 #endif 213 214 g_free(restart.vals); 215 216 ice_connection = SmcGetIceConnection(smc_connection); 217 gdk_input_add(IceConnectionNumber(ice_connection), GDK_INPUT_READ, 218 (GdkInputFunction) cb_ice_connection_messages, ice_connection); 219 } 220 221 static void 222 net_wm_state(gchar *hint, gboolean state) 223 { 224 XEvent xev; 225 226 xev.type = ClientMessage; 227 xev.xclient.type = ClientMessage; 228 xev.xclient.window = GDK_WINDOW_XWINDOW(gkrellm_get_top_window()->window); 229 xev.xclient.message_type = gdk_x11_get_xatom_by_name("_NET_WM_STATE"); 230 xev.xclient.format = 32; 231 xev.xclient.data.l[0] = state ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; 232 xev.xclient.data.l[1] = gdk_x11_get_xatom_by_name(hint); 233 xev.xclient.data.l[2] = 0; 234 235 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), 236 False, SubstructureNotifyMask|SubstructureRedirectMask, &xev); 237 } 238 239 void 240 gkrellm_winop_state_skip_taskbar(gboolean state) 241 { 242 if (!_GK.is_dock_type) 243 net_wm_state("_NET_WM_STATE_SKIP_TASKBAR", state); 244 } 245 246 void 247 gkrellm_winop_state_skip_pager(gboolean state) 248 { 249 if (!_GK.is_dock_type) 250 net_wm_state("_NET_WM_STATE_SKIP_PAGER", state); 251 } 252 253 void 254 gkrellm_winop_state_above(gboolean state) 255 { 256 net_wm_state("_NET_WM_STATE_ABOVE", state); 257 /* Apparently KDE 3.1.0 and possibly below does not implement 258 * _NET_WM_STATE_ABOVE but _NET_WM_STATE_STAYS_ON_TOP that implies 259 * approximately the same thing 260 */ 261 net_wm_state("_NET_WM_STATE_STAYS_ON_TOP", state); 262 } 263 264 void 265 gkrellm_winop_state_below(gboolean state) 266 { 267 net_wm_state("_NET_WM_STATE_BELOW", state); 268 } 269 270 static FILE *f_lock; 271 272 static gboolean 273 _gkrellm_get_lock(void) 274 { 275 gchar *lock_dir, *lock_file, *display, *s; 276 gchar buf[32]; 277 278 snprintf(buf, sizeof(buf), "LCK..gkrellm"); 279 280 #if defined(F_TLOCK) 281 lock_dir = g_strdup_printf("/var/lock/gkrellm-%d", (gint) getuid()); 282 if (!g_file_test(lock_dir, G_FILE_TEST_IS_DIR)) 283 mkdir(lock_dir, 0755); 284 285 lock_file = gkrellm_make_config_file_name(lock_dir, buf); 286 g_free(lock_dir); 287 display = XDisplayName(NULL); 288 if (display) 289 { 290 s = g_strconcat(lock_file, "_", display, NULL); 291 g_free(lock_file); 292 lock_file = s; 293 } 294 f_lock = fopen(lock_file, "w+"); /* buffering does not apply here */ 295 g_free(lock_file); 296 if ( f_lock 297 && lockf(fileno(f_lock), F_TLOCK, 0) != 0 298 && errno == EAGAIN 299 ) 300 return FALSE; 301 if (f_lock) 302 { 303 fprintf(f_lock, "%10d\n", (gint) getpid()); 304 fflush(f_lock); 305 } 306 #endif 307 return TRUE; 308 } 309 310 enum 311 { 312 STRUT_LEFT = 0, 313 STRUT_RIGHT = 1, 314 STRUT_TOP = 2, 315 STRUT_BOTTOM = 3, 316 STRUT_LEFT_START = 4, 317 STRUT_LEFT_END = 5, 318 STRUT_RIGHT_START = 6, 319 STRUT_RIGHT_END = 7, 320 STRUT_TOP_START = 8, 321 STRUT_TOP_END = 9, 322 STRUT_BOTTOM_START = 10, 323 STRUT_BOTTOM_END = 11 324 }; 325 326 static Atom net_wm_strut_partial = None; 327 static Atom net_wm_strut = None; 328 329 void 330 gkrellm_winop_update_struts(void) 331 { 332 gulong struts[12] = { 0, }; 333 Display *display; 334 Window window; 335 gint width; 336 gint height; 337 338 if (!_GK.is_dock_type) 339 return; 340 341 display = GDK_WINDOW_XDISPLAY(gkrellm_get_top_window()->window); 342 window = GDK_WINDOW_XWINDOW(gkrellm_get_top_window()->window); 343 344 if (net_wm_strut_partial == None) 345 { 346 net_wm_strut_partial 347 = XInternAtom(display, "_NET_WM_STRUT_PARTIAL", False); 348 } 349 if (net_wm_strut == None) 350 { 351 net_wm_strut = XInternAtom(display, "_NET_WM_STRUT", False); 352 } 353 354 gtk_window_get_size(GTK_WINDOW(gkrellm_get_top_window()), &width, &height); 355 356 if (_GK.x_position == 0) 357 { 358 struts[STRUT_LEFT] = width; 359 struts[STRUT_LEFT_START] = _GK.y_position; 360 struts[STRUT_LEFT_END] = _GK.y_position + height; 361 } 362 else if (_GK.x_position == _GK.w_display - width) 363 { 364 struts[STRUT_RIGHT] = width; 365 struts[STRUT_RIGHT_START] = _GK.y_position; 366 struts[STRUT_RIGHT_END] = _GK.y_position + height; 367 } 368 369 gdk_error_trap_push(); 370 XChangeProperty (display, window, net_wm_strut, 371 XA_CARDINAL, 32, PropModeReplace, 372 (guchar *) &struts, 4); 373 XChangeProperty (display, window, net_wm_strut_partial, 374 XA_CARDINAL, 32, PropModeReplace, 375 (guchar *) &struts, 12); 376 gdk_error_trap_pop(); 377 } 378 379 void 380 gkrellm_winop_options(gint argc, gchar **argv) 381 { 382 Display *display; 383 Window window; 384 Atom atoms[4]; 385 gint n = 0; 386 387 if ( !_GK.allow_multiple_instances_real 388 && !_GK.force_host_config 389 && !_gkrellm_get_lock() 390 ) 391 { 392 g_message("gkrellm: %s\n", 393 _("Exiting because multiple instances option is off.\n")); 394 exit(0); 395 } 396 smc_connect(argc, argv); 397 display = GDK_WINDOW_XDISPLAY(gkrellm_get_top_window()->window); 398 window = GDK_WINDOW_XWINDOW(gkrellm_get_top_window()->window); 399 400 /* Set window type or list of states using standard EWMH hints. 401 | See http://www.freedesktop.org/ 402 | At least KDE3 and GNOME2 are EWMH compliant. 403 */ 404 if (_GK.dock_type && !_GK.command_line_decorated) 405 { 406 atoms[0] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", False); 407 408 XChangeProperty(display, window, 409 XInternAtom(display, "_NET_WM_WINDOW_TYPE", False), 410 XA_ATOM, 32, PropModeReplace, (guchar *) atoms, 1); 411 _GK.is_dock_type = TRUE; 412 _GK.state_skip_taskbar = FALSE; 413 _GK.state_skip_pager = FALSE; 414 } 415 if (_GK.state_skip_taskbar) 416 { 417 atoms[n] = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False); 418 ++n; 419 } 420 if (_GK.state_skip_pager) 421 { 422 atoms[n] = XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", False); 423 ++n; 424 } 425 if (_GK.state_above) 426 { 427 atoms[n++] = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); 428 /* see gkrellm_winop_state_above() */ 429 atoms[n++] = XInternAtom(display, "_NET_WM_STATE_STAYS_ON_TOP", False); 430 _GK.state_below = FALSE; 431 } 432 if (_GK.state_below) 433 { 434 atoms[n] = XInternAtom(display, "_NET_WM_STATE_BELOW", False); 435 ++n; 436 } 437 if (n > 0) 438 XChangeProperty(display, window, 439 XInternAtom(display, "_NET_WM_STATE", False), 440 XA_ATOM, 32, PropModeReplace, (guchar *) atoms, n); 441 } 442 443 void 444 gkrellm_winop_withdrawn(void) 445 { 446 Display *display; 447 Window window; 448 449 if (!_GK.withdrawn) 450 return; 451 display = GDK_WINDOW_XDISPLAY(gkrellm_get_top_window()->window); 452 window = GDK_WINDOW_XWINDOW(gkrellm_get_top_window()->window); 453 454 if (!_GK.is_dock_type) 455 { 456 XWMHints mywmhints; 457 mywmhints.initial_state = WithdrawnState; 458 mywmhints.flags=StateHint; 459 460 XSetWMHints(display, window, &mywmhints); 461 } 462 else 463 gkrellm_message_dialog(NULL, 464 _("Warning: -w flag is ignored when the window dock type is set")); 465 } 466 467 /* Use XParseGeometry, but width and height are ignored. 468 | If GKrellM is moved, update _GK.y_position. 469 */ 470 void 471 gkrellm_winop_place_gkrellm(gchar *geom) 472 { 473 gint place, x, y, w_gkrell, h_gkrell; 474 475 x = y = 0; 476 place = XParseGeometry(geom, &x, &y, 477 (guint *) &w_gkrell, (guint *) &h_gkrell); 478 479 w_gkrell = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width; 480 h_gkrell = _GK.monitor_height + _GK.total_frame_height; 481 482 if (place & YNegative) 483 y = _GK.h_display - h_gkrell + y; 484 if (place & XNegative) 485 x = _GK.w_display - w_gkrell + x; 486 gdk_window_move(gkrellm_get_top_window()->window, x, y); 487 _GK.y_position = y; 488 _GK.x_position = x; 489 _GK.position_valid = TRUE; 490 gkrellm_debug(DEBUG_POSITION, "geometry moveto %d %d\n", x, y); 491 } 492 493 void 494 gkrellm_winop_flush_motion_events(void) 495 { 496 XEvent xevent; 497 498 gdk_flush(); 499 while (XCheckTypedEvent(GDK_DISPLAY(), MotionNotify, &xevent)) 500 ; 501 } 502 503 /* Check if background has changed 504 */ 505 gboolean 506 gkrellm_winop_updated_background(void) 507 { 508 Pixmap root_pix = None; 509 Atom prop, ret_type = (Atom) 0; 510 guchar *prop_return = NULL; 511 gint fmt; 512 gulong nitems, bytes_after; 513 514 if (!_GK.any_transparency) 515 return FALSE; 516 prop = XInternAtom(GDK_DISPLAY(), "_XROOTPMAP_ID", True); 517 if (prop == None) 518 return FALSE; 519 520 XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), prop, 0L, 1L, False, 521 AnyPropertyType, &ret_type, &fmt, &nitems, &bytes_after, 522 &prop_return); 523 if (prop_return && ret_type == XA_PIXMAP) 524 { 525 root_pix = *((Pixmap *) prop_return); 526 XFree(prop_return); 527 } 528 else 529 return FALSE; 530 531 if (root_pix != root_xpixmap) 532 { 533 root_xpixmap = root_pix; 534 return TRUE; 535 } 536 return FALSE; 537 } 538 539 gboolean 540 gkrellm_winop_draw_rootpixmap_onto_transparent_chart(GkrellmChart *cp) 541 { 542 Window child; 543 GkrellmMargin *m; 544 gint x, y; 545 546 if ( root_xpixmap == None || trans_gc == NULL || !cp->transparency 547 || !cp->drawing_area || !cp->drawing_area->window 548 ) 549 return FALSE; 550 XTranslateCoordinates(GDK_DISPLAY(), 551 GDK_WINDOW_XWINDOW(cp->drawing_area->window), 552 GDK_ROOT_WINDOW(), 553 0, 0, &x, &y, &child); 554 XSetTSOrigin(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), -x, -y); 555 556 /* First make the chart totally transparent 557 */ 558 gdk_draw_rectangle(cp->bg_src_pixmap, trans_gc, 559 TRUE, 0, 0, cp->w, cp->h); 560 561 /* If mode permits, stencil on non transparent parts of bg_clean_pixmap. 562 */ 563 if (cp->transparency == 2 && cp->bg_mask) 564 { 565 gdk_gc_set_clip_mask(_GK.text_GC, cp->bg_mask); 566 gdk_draw_drawable(cp->bg_src_pixmap, _GK.text_GC, 567 cp->bg_clean_pixmap, 0, 0, 0, 0, cp->w, cp->h); 568 } 569 m = &cp->style->margin; 570 if (cp->top_spacer.pixmap) 571 { 572 XSetTSOrigin(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), -x, -(y - m->top)); 573 gdk_draw_rectangle(cp->top_spacer.pixmap, trans_gc, 574 TRUE, 0, 0, cp->w, cp->style->margin.top); 575 if (cp->transparency == 2 && cp->top_spacer.mask) 576 { 577 gdk_gc_set_clip_mask(_GK.text_GC, cp->top_spacer.mask); 578 gdk_draw_drawable(cp->top_spacer.pixmap, _GK.text_GC, 579 cp->top_spacer.clean_pixmap, 0, 0, 0, 0, 580 cp->w, cp->style->margin.top); 581 } 582 gtk_image_set_from_pixmap(GTK_IMAGE(cp->top_spacer.image), 583 cp->top_spacer.pixmap, NULL); 584 } 585 586 if (cp->bottom_spacer.pixmap) 587 { 588 XSetTSOrigin(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), 589 -x, -(y + cp->h - m->bottom)); 590 gdk_draw_rectangle(cp->bottom_spacer.pixmap, trans_gc, 591 TRUE, 0, 0, cp->w, cp->style->margin.bottom); 592 if (cp->transparency == 2 && cp->bottom_spacer.mask) 593 { 594 gdk_gc_set_clip_mask(_GK.text_GC, cp->bottom_spacer.mask); 595 gdk_draw_drawable(cp->bottom_spacer.pixmap, _GK.text_GC, 596 cp->bottom_spacer.clean_pixmap, 0, 0, 0, 0, 597 cp->w, cp->style->margin.bottom); 598 } 599 gtk_image_set_from_pixmap(GTK_IMAGE(cp->bottom_spacer.image), 600 cp->bottom_spacer.pixmap, NULL); 601 } 602 gdk_gc_set_clip_mask(_GK.text_GC, NULL); 603 cp->bg_sequence_id += 1; 604 return TRUE; 605 } 606 607 gboolean 608 gkrellm_winop_draw_rootpixmap_onto_transparent_panel(GkrellmPanel *p) 609 { 610 Window child; 611 gint x, y; 612 613 if ( root_xpixmap == None || trans_gc == NULL || !p->transparency 614 || !p->drawing_area || !p->drawing_area->window 615 ) 616 return FALSE; 617 XTranslateCoordinates(GDK_DISPLAY(), 618 GDK_WINDOW_XWINDOW(p->drawing_area->window), 619 GDK_ROOT_WINDOW(), 620 0, 0, &x, &y, &child); 621 XSetTSOrigin(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), -x, -y); 622 623 /* First make the panel totally transparent 624 */ 625 gdk_draw_rectangle(p->bg_pixmap, trans_gc, TRUE, 0, 0, p->w, p->h); 626 627 /* If mode permits, stencil on non transparent parts of bg_clean_pixmap. 628 */ 629 if (p->transparency == 2 && p->bg_mask) 630 { 631 gdk_gc_set_clip_mask(_GK.text_GC, p->bg_mask); 632 gdk_draw_drawable(p->bg_pixmap, _GK.text_GC, p->bg_clean_pixmap, 633 0, 0, 0, 0, p->w, p->h); 634 gdk_gc_set_clip_mask(_GK.text_GC, NULL); 635 } 636 return TRUE; 637 } 638 639 static void 640 draw_rootpixmap_onto_transparent_spacers(GkrellmMonitor *mon, gint xr, gint yr) 641 { 642 GkrellmMonprivate *mp = mon->privat; 643 gint x, y; 644 645 if (mp->top_spacer.image) 646 { 647 x = xr + mp->top_spacer.image->allocation.x; 648 y = yr + mp->top_spacer.image->allocation.y; 649 XSetTSOrigin(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), -x, -y); 650 gdk_draw_rectangle(mp->top_spacer.pixmap, trans_gc, 651 TRUE, 0, 0, _GK.chart_width, mp->top_spacer.height); 652 if (mp->top_spacer.mask) 653 { 654 gdk_gc_set_clip_mask(_GK.text_GC, mp->top_spacer.mask); 655 gdk_draw_drawable(mp->top_spacer.pixmap, _GK.text_GC, 656 mp->top_spacer.clean_pixmap, 0, 0, 0, 0, 657 _GK.chart_width, mp->top_spacer.height); 658 } 659 gtk_image_set_from_pixmap(GTK_IMAGE(mp->top_spacer.image), 660 mp->top_spacer.pixmap, NULL); 661 } 662 if (mp->bottom_spacer.image) 663 { 664 x = xr + mp->bottom_spacer.image->allocation.x; 665 y = yr + mp->bottom_spacer.image->allocation.y; 666 XSetTSOrigin(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), -x, -y); 667 gdk_draw_rectangle(mp->bottom_spacer.pixmap, trans_gc, 668 TRUE, 0, 0, _GK.chart_width, mp->bottom_spacer.height); 669 if (mp->bottom_spacer.mask) 670 { 671 gdk_gc_set_clip_mask(_GK.text_GC, mp->bottom_spacer.mask); 672 gdk_draw_drawable(mp->bottom_spacer.pixmap, _GK.text_GC, 673 mp->bottom_spacer.clean_pixmap, 0, 0, 0, 0, 674 _GK.chart_width, mp->bottom_spacer.height); 675 } 676 gtk_image_set_from_pixmap(GTK_IMAGE(mp->bottom_spacer.image), 677 mp->bottom_spacer.pixmap, NULL); 678 } 679 } 680 681 void 682 gkrellm_winop_apply_rootpixmap_transparency(void) 683 { 684 Window child; 685 GtkWidget *top_window = gkrellm_get_top_window(); 686 Atom prop, 687 ret_type = (Atom) 0; 688 GList *list; 689 GkrellmMonitor *mon; 690 GkrellmChart *cp; 691 GkrellmPanel *p; 692 guchar *prop_return = NULL; 693 gint fmt; 694 gulong nitems, bytes_after; 695 gint depth_visual; 696 Window root_return; 697 guint w_ret, h_ret, bw_ret, depth_ret; 698 gint x_ret, y_ret, x_root, y_root; 699 700 if (!_GK.any_transparency) 701 return; 702 prop = XInternAtom(GDK_DISPLAY(), "_XROOTPMAP_ID", True); 703 if (prop == None) 704 return; 705 XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), prop, 0L, 1L, False, 706 AnyPropertyType, &ret_type, &fmt, &nitems, &bytes_after, 707 &prop_return); 708 if (prop_return && ret_type == XA_PIXMAP) 709 { 710 root_xpixmap = *((Pixmap *) prop_return); 711 XFree(prop_return); 712 } 713 if (root_xpixmap == None) 714 return; 715 if (trans_gc == NULL) 716 { 717 trans_gc = gdk_gc_new(top_window->window); 718 gdk_gc_copy(trans_gc, _GK.draw1_GC); 719 } 720 721 depth_ret = 0; 722 depth_visual = gdk_drawable_get_visual(top_window->window)->depth; 723 if ( !XGetGeometry(GDK_DISPLAY(), root_xpixmap, &root_return, 724 &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret) 725 || depth_ret != depth_visual 726 ) 727 { 728 root_xpixmap = None; 729 return; 730 } 731 732 /* I could use gdk_pixmap_foreign_new() and stay in the gdk domain, 733 | but it fails (in XGetGeometry()) if I change backgrounds. 734 */ 735 XSetTile(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), root_xpixmap); 736 XSetFillStyle(GDK_DISPLAY(), GDK_GC_XGC(trans_gc), FillTiled); 737 for (list = gkrellm_get_chart_list(); list; list = list->next) 738 { 739 cp = (GkrellmChart *) list->data; 740 if (!cp->transparency || !cp->shown) 741 continue; 742 gkrellm_winop_draw_rootpixmap_onto_transparent_chart(cp); 743 gkrellm_refresh_chart(cp); 744 } 745 for (list = gkrellm_get_panel_list(); list; list = list->next) 746 { 747 p = (GkrellmPanel *) list->data; 748 if (!p->transparency || !p->shown) 749 continue; 750 gkrellm_draw_panel_label(p); 751 } 752 XTranslateCoordinates(GDK_DISPLAY(), 753 GDK_WINDOW_XWINDOW(top_window->window), 754 GDK_ROOT_WINDOW(), 755 0, 0, &x_root, &y_root, &child); 756 for (list = gkrellm_monitor_list; list; list = list->next) 757 { 758 mon = (GkrellmMonitor *) list->data; 759 draw_rootpixmap_onto_transparent_spacers(mon, x_root, y_root); 760 } 761 gdk_gc_set_clip_mask(_GK.text_GC, NULL); 762 } 763