GTK 窗口背景不透明度

问题描述 投票:0回答:1

我们目前正致力于在 GJS 中开发 GTK 应用程序,并希望使用分层在视频之上的 WebView 来显示视频。我们可以使用 GStreamer 打开一个窗口并显示视频,并使用 WebkitGTK+ 中的 WebKit2 打开一个单独的窗口并显示 WebView。

GStreamer 窗口是 ApplicationWindow 内的 DrawingArea。 WebView 是 ApplicationWindow 内部的 WebView。 WebView 窗口设置为始终位于视频顶部,但背景为白色,因此我们无法通过 WebView 看到下面的视频。

我们希望更改显示 Webview 的窗口的不透明度,使背景完全透明,同时保留 WebView 中显示的内容。我们可以将WebView背景的文档设置为完全透明。 GTK中有没有办法让ApplicationWindow和WebView背景透明?

我尝试过使用CSSProperties,但这似乎并没有影响窗口的不透明度。

gtk gjs
1个回答
0
投票

嗨,我还需要一个透明的 Gtk 窗口。
你说你使用 CSS,但它不起作用,我还认为 CSS 在 GTK 3 (3.24.33) 中不能正常工作,因为我的一些 CSS 规则没有影响小部件,直到我认识到,这是我的错,不太关注 “add_provider” “Gtk.StyleContext” 类的实例方法的优先级参数。
我总是使用 0 来表示优先级

widget.get_style_context().add_provider (cssProvider, 0);
但你必须设置高优先级值才能使其工作。
用途:
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - 值为 600
Gtk.STYLE_PROVIDER_PRIORITY_USER - 值为 800

这是我在 GTK 中使用 alpha 通道的窗口的代码 (3.24.33)

#!/usr/bin/gjs
"use strict";
imports.gi.versions.Gtk="3.0";
const { Gtk, Gdk } = imports.gi;
Gtk.init(null);

const window = new Gtk.Window(),
      box=new Gtk.Box ({ orientation:Gtk.Orientation.VERTICAL}),
      label=new Gtk.Label ({label:"I'm a window with alpha channel'"}),
      button=new Gtk.Button ({label:"make me intransparent", halign:Gtk.Align.CENTER}),
      cssProvider=new Gtk.CssProvider();

var styleContext;

cssProvider.load_from_data("\
   window.transparent   { background-color: rgba(0,0,0,0) }\
   window.intransparent { background-color: #FFFFFF }\
   button:hover         { background-color: #FFFF00 }\
   button.pointerdown   { background-color: #FF0000 }\
   label                { background-color: #AA99EE; padding:10px }");

styleContext=window.get_style_context();
styleContext.add_provider (cssProvider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
styleContext.add_class("transparent");

label.get_style_context().add_provider (cssProvider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
button.get_style_context().add_provider (cssProvider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);

button.connect ("button-press-event", function (button, event)
   {
   const position=window.get_position();

   if (event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS || event.get_event_type() == Gdk.EventType.TRIPLE_BUTTON_PRESS) return true;
   
   button.get_style_context().add_class("pointerdown");
   if (window.isTransparent)
      {
      window.get_style_context().add_class("intransparent");
      button.label="make me transparent";
      window.set_decorated(true);
      }
   else
      {
      window.get_style_context().remove_class("intransparent");
      button.label="make me intransparent";      
      window.set_decorated(false);
      }
   
   window.move (position[0], position[1]);
   window.isTransparent=!window.isTransparent;
   });

button.connect ("button-release-event", function (button, event)
   {
   button.get_style_context().remove_class("pointerdown");
   });

window.set_title ("window with alpha channel")
window.set_size_request (640, 480);
window.set_position (Gtk.WindowPosition.CENTER);
window.set_visual (window.get_screen().get_rgba_visual());  //-- sets the alpha channel on the window!
window.set_decorated (false);                               //-- removes decoration
window.set_gravity (Gdk.Gravity.STATIC);                    //-- set the gravity for window.move and window.get_position on window content top left corner
window.isTransparent=true;

box.add(label); box.add(button); window.add(box);
window.show_all();

Gtk.main();

但真正的问题是 - 如何让事件通过窗口,其中窗口是透明的,因为它仍然在那里并捕获所有事件。
我尝试了“set_pass_through”方法,但没有成功。
我尝试构建一个新的 Gdk.Event 但我无法设置 coords、root_coords 和 window 等值。只有 get 方法,没有 set 方法。 如果有人知道如何构造一个新的用户定义的 Gdk 事件并向其附加值 - 请告诉我。

唯一有效的方法是使用低级函数“Gtk.event_propagate”
捕获窗口中的事件并将其不变地发送到定义的接收器窗口(可以在下面或任何位置) 但这意味着只有事件的根坐标是正确的,并且您必须通过检查子窗口小部件的所有分配(如果它们位于指针下方)来管理接收器窗口内的事件传播,然后在它们上触发!

#!/usr/bin/gjs
"use strict";
imports.gi.versions.Gtk="3.0";
const { Gtk, Gdk } = imports.gi;
Gtk.init(null);

const window = new Gtk.Window(),
      box=new Gtk.Box ({ orientation:Gtk.Orientation.VERTICAL}),
      label=new Gtk.Label ({label:"I'm a window with alpha channel'"}),
      button=new Gtk.Button ({label:"make me intransparent", halign:Gtk.Align.CENTER}),
      cssProvider=new Gtk.CssProvider();

var styleContext;

cssProvider.load_from_data("\
   window.transparent   { background-color: rgba(0,0,0,0) }\
   window.intransparent { background-color: #FFFFFF }\
   button:hover         { background-color: #FFFF00 }\
   button.pointerdown   { background-color: #FF0000 }\
   label                { background-color: #AA99EE; padding:10px }");

styleContext=window.get_style_context();
styleContext.add_provider (cssProvider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
styleContext.add_class("transparent");

label.get_style_context().add_provider (cssProvider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
button.get_style_context().add_provider (cssProvider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);

button.connect ("button-press-event", function (button, event)
   {
   const position=window.get_position();

   if (event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS || event.get_event_type() == Gdk.EventType.TRIPLE_BUTTON_PRESS) return true;
   
   button.get_style_context().add_class("pointerdown");
   if (window.isTransparent)
      {
      window.get_style_context().add_class("intransparent");
      button.label="make me transparent";
      window.set_decorated(true);
      }
   else
      {
      window.get_style_context().remove_class("intransparent");
      button.label="make me intransparent";      
      window.set_decorated(false);
      }
   
   window.move (position[0], position[1]);
   window.isTransparent=!window.isTransparent;
   });

button.connect ("button-release-event", function (button, event)
   {
   button.get_style_context().remove_class("pointerdown");
   });

window.set_title ("window with alpha channel")
window.set_size_request (640, 480);
window.set_position (Gtk.WindowPosition.CENTER);
window.set_visual (window.get_screen().get_rgba_visual());     //-- sets the alpha channel on the window!
window.set_decorated (false);                                  //-- removes decoration
window.set_gravity (Gdk.Gravity.STATIC);                       //-- set the gravity for window.move and window.get_position on window content top left corner
window.isTransparent=true;

box.add(label); box.add(button); window.add(box);
window.show_all();

window.lastEventInfo={ time:null, type:null };                 //-- saves the time and the type of the last event on window
window.connect("button_press_event", function (button, event)
   {
   const time=event.get_time(), type=event.get_event_type ();
   var event_target_widget, pixbuf, coords;
   
   /* signal "button-press-event" and "button-release-event" fires two times per click on window, if you click on it, and there is no widget above window in the click area, which receive these signals (descendants chain)
      e.g click on box, label - this can be stopped by returning true in the handler, which stops the signal emission, but this also will stop all later connected handlers - so i check event time and event type to eliminate it*/
   if (time == window.lastEventInfo.time && type == window.lastEventInfo.type) return;
   window.lastEventInfo= { time: time, type: type };
   
   event_target_widget=Gtk.get_event_widget (event), pixbuf;        //-- get the event target - the widget, which received the signal
   if (event_target_widget==window)                                 //-- if target is not window, then widget, which receive this signal must be above (e.g. button), then do nothing 
      {
      //-- target == window, e.g click on label, box or directly on window, check if pixel under pointer is transparent
      coords=event.get_coords();
      pixbuf=Gdk.pixbuf_get_from_window (window.get_window(), coords[1], coords[2], 1, 1);  //-- get pixel under pointer
      if (pixbuf.get_pixels()[3] == 0)  Gtk.propagate_event (window_receive, event);        //-- if pixel is transparent (alpha=0), send event to window_receive
      }
   });

//-- receiver window   
const window_receive=new Gtk.Window ();
var window_receive_label=new Gtk.Label ({ label:"waiting for event" }), counter=0;
window_receive.add (window_receive_label);
window_receive.set_title ("window receiver");
window_receive.set_size_request(400,200);
window_receive.connect ("button_press_event", function (button, event) { window_receive_label.set_text("count: "+(++counter)+" received event at time "+event.get_time()+" - type: "+event.get_event_type()); });
window_receive.show_all();

Gtk.main();

如果有人知道,如何让事件通过,哪里的窗口是透明的,请在下面回答!

© www.soinside.com 2019 - 2024. All rights reserved.