54148


背景を透過し、かつ不定形なGUIを描画する方法について質問です。  
行いたいこと : Windowsのイルカや、PythonのAnacondaの起動画面のようにウィンドウを持たず、かつ不定形なGUIをLinux上で作成したい  
分からないこと: そもそもLinux上で可能なのか、またどのようなライブラリで実現できるのか  
また、十分条件ですがOpenGLで3D描画をできるとなお良いです。

何かご存知の方、ご回答いただけるとありがたいです。


CC BY-SA 4.0
2019-04-10T23:45:58.750
54077
2019-04-17T13:17:14.877
32622
question
linux opengl gui
背景を透過する不定形なGUIの描画について(Windowsのイルカみたいな)


GTK+でできます。

[code]

    #include <gtk/gtk.h>
    #include <cairo.h>
    #include <math.h>
    
    gboolean on_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
    {
        cairo_save(cr);
    
        /* GTK+の低レイヤーのcairoで、アルファレンダリングする */
        cairo_scale(cr, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget));
        cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
        cairo_arc(cr, 0.5, 0.5, 0.5, 0.0, M_PI * 2.0);
        cairo_fill(cr);
    
        cairo_restore(cr);
    
        return TRUE;
    }
    
    int main(int argc, char *argv[])
    {
        GtkWidget *window;
    
        gtk_init(&argc, &argv);
    
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
        /* デフォルトの背景描画をしない */
        gtk_widget_set_app_paintable(window, TRUE);
        /* ウィンドウ装飾(タイトルなど)を非表示 */
        gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
        /* RGBAレンダリングを有効に */
        gtk_widget_set_visual(window, gdk_screen_get_rgba_visual(gdk_screen_get_default()));
    
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
        g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(on_draw), NULL);
    
        gtk_widget_show(window);
    
        gtk_main();
    
        return 0;
    }
    
[/code]

GtkGLAreaを使えば、GTK+でOpenGLレンダリングを行う事ができます。

[code]

    #include <GL/gl.h>
    #include <gtk/gtk.h>
    
    gboolean on_render(GtkGLArea *gl_area, GdkGLContext *context, gpointer user_data)
    {
        glClearColor(0.2f, 0.2f, 0.2f, 0.5f);
        glClear(GL_COLOR_BUFFER_BIT);
    
    #if 0
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_CULL_FACE);
    
        glBegin(GL_TRIANGLE_STRIP);
        glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
        glVertex3f( 0.9f,  0.9f, 0.5f);
        glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
        glVertex3f( 0.9f, -0.9f, 0.5f);
        glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
        glVertex3f(-0.9f, -0.9f, 0.5f);
        glEnd();
    #endif
    
        glFlush();
    
    
        return FALSE;
    }
    
    int main(int argc, char *argv[])
    {
        GtkWidget *window;
        GtkWidget *gl_area;
    
        gtk_init(&argc, &argv);
    
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
        gtk_widget_set_app_paintable(window, TRUE);
        gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
        gtk_widget_set_visual(window, gdk_screen_get_rgba_visual(gdk_screen_get_default()));
    
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    
        gl_area = gtk_gl_area_new();
        gtk_gl_area_set_has_alpha(GTK_GL_AREA(gl_area), TRUE);
        gtk_widget_show(gl_area);
        gtk_container_add(GTK_CONTAINER(window), gl_area);
    
        g_signal_connect(G_OBJECT(gl_area), "render", G_CALLBACK(on_render), NULL);
    
        gtk_widget_show(window);
    
        gtk_main();
        return 0;
    }
    
[/code]

残念ながらGtkGLAreaは使った事がなく、三角形をレンダリングするところまではできませんでしたが、背景色のアルファを0.5にしてクリアすると透けて表示されるので、ちゃんとレンダリングすれば非矩形表示もできるはずです。

* * *

以前同じ事をQtでやろうとしたけど、結局やり方がわからなかった。  
誰かQtで回答してくれないかなぁボソ

* * *

解決済みですけど、思い出した事があったので、追記します。

ご存知かもしれませんが、[GLFW](https://www.glfw.org/)というライブラリがあります。  
OpenGLのテストコードを書くのに重宝するのですが、こいつが結構高機能で、もしかしたらそんな機能もあるんじゃないかな、と思ってドキュメントを眺めていたら、見つけました。

[code]

    #include <GL/gl.h>
    #include <GLFW/glfw3.h>
    #include <cstdio>
    
    int main()
    {
        if (!glfwInit()) {
            std::fprintf(stderr, "%s(%d): failed to initialize GLFW.\n", __FILE__, __LINE__);
            return 1;
        }
        // ウィンドウ装飾を非表示
        glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
        // フレームバッファを半透明表示
        glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
    
        GLFWwindow *window = glfwCreateWindow(400, 300, "Test", NULL, NULL);
        glfwMakeContextCurrent(window);
    
        while (!glfwWindowShouldClose(window)) {
            // アルファも含め、全てのカラーをクリア
            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            glClear(GL_COLOR_BUFFER_BIT);
    
            glDisable(GL_DEPTH_TEST);
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDisable(GL_CULL_FACE);
    
            glBegin(GL_TRIANGLES);
            glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
            glVertex3f( 0.5f,  0.5f, 0.0f);
            glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
            glVertex3f(-0.5f, -0.5f, 0.0f);
            glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
            glVertex3f( 0.5f, -0.5f, 0.0f);
            glEnd();
    
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
        glfwTerminate();
        return 0;
    }
    
[/code]

ただ、残念な事に、上記で使用している`GLFW_TRANSPARENT_FRAMEBUFFER`はバージョン3.3から追加された機能で、
**リリースされたのが昨日** なんですよね。  
(なんちゅうタイミングだ)

だから、使うのであればディストリビューションが配布しているものは使用せず、自分でソースコードを持ってきてビルドする必要があると思います。

ただ、OpenGLを使って、というのであればこれが一番簡単でベストかなぁと思います。


CC BY-SA 4.0
2019-04-11T15:20:32.497
54101
2019-04-16T12:04:11.817
2019-04-16T12:04:11.817
15473
15473
54077
answer


JavaだとJava7以降は単独でできるようです。  
[Java SE 7：
非矩形ウィンドウと半透明ウィンドウのさらなる応用](https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-
MJ12-architect-marinacci.pdf)

YouTube/ニコニコ動画で最小限の表示の仕組みを解説しているものがあります。  
[【Java】デスクトップマスコットをなるべく簡単に【プログラミング】YouTube](https://www.youtube.com/watch?v=nse99Tms0GM&list=PLg8GyFm8HIJcWlRfLxxTo1YEkzNqKoUJr)
/ [同ニコニコ動画](https://www.nicovideo.jp/user/70827037/video?order=a)

項目をまとめると以下になると考えられます。  
これはJavaに限らず、どの言語やライブラリでも同じでしょう。

  * タイトルバー等装飾の無い全透過のフレームを用意する。
  * 画像を表示するパネルを用意する。
  * 透過チャンネルを持つ画像データを用意してパネルに表示する。  
Officeアシスタントのカイル君のようにアニメーションに見せたい場合、大きなサイズの画像の中に升目上に動きの各フレームを並べて、必要に応じて実際の表示部分を変えることにより、3Dで動いているように見せることが可能。  
**ただし、実際のカイル君がどう描画されているかは知りませんが**

  * 画像の移動・拡大/縮小・メニュー・UIなどは自分で実装する。(少なくともマウス/キーボードのトリガ処理は必要)

アニメーションは無いですが、UIも含めたもう少し詳しい例が以下になります。  
主な説明はProcessingという言語のものですが、Javaのソースも掲載されています。  
[非矩形ウィンドウを表示するには](http://mslabo.sakura.ne.jp/WordPress/make/processing%E3%80%80%E9%80%86%E5%BC%95%E3%81%8D%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/%E9%9D%9E%E7%9F%A9%E5%BD%A2%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF/)

* * *

[Simple DirectMedia Layer](http://sdl2referencejp.osdn.jp/) という OpenGL
にかぶせて使うライブラリがあって、クロスプラットフォームで使えるそうです。  
[紬ちゃんマスコット SDL2.0編](http://temama.hatenablog.com/entry/2016/05/07/104938) /
[SDL2で非矩形の画像ビューアを作成](https://qiita.com/nak2yoshi/items/20e256f8ea612ff9927b) /
[D言語＋SDL2で非矩形ウィンドウを作成する](https://qiita.com/nak2yoshi/items/1411fbb65ccf82545e65)  
[SDL2 and 3D Rendering](https://stackoverflow.com/q/55366742/9014308) / [Is 3d
game development advantageous/possible in
SDL2?](https://gamedev.stackexchange.com/q/125823)

OpenGL系ではこんな記事もあります。  
[OpenGL（GLES2.0）のアルファブレンドで透過処理した画像が黒っぽくなる。](https://qiita.com/takenobi/items/870411f1c98701d12adc)  
[How to make an OpenGL rendering context with transparent
background?](https://stackoverflow.com/q/4052940/9014308) / [Make transparency
not show what is behind the window in opengl with
c++](https://stackoverflow.com/q/23829839/9014308)  
[Option for transparent windows #197](https://github.com/glfw/glfw/issues/197)  
[GLSC3DProject/GLSC3D](https://github.com/GLSC3DProject/GLSC3D) / [GLSC3D
(Ver. 3.0.0)
Manual](https://github.com/GLSC3DProject/GLSC3D/blob/master/Manual/GLSC3D_Manual.pdf)

* * *

Qt系では、以下のような記事があります。  
[Pyside の透過PNG表示のサンプル](https://qiita.com/suto3/items/6790c94cf4c3c2470c6d)  
[月の杜工房 - Qt ウィンドウスタイル](http://mf-atelier.sakura.ne.jp/mf-
atelier/modules/tips/program/Qt/qt_style.html)  
[Frameless and transparent window
qt5](https://stackoverflow.com/q/18316710/9014308)  
[frameless windows with qt5
(qml)](https://stackoverflow.com/q/20860692/9014308)  
[Qt5 & QtQuick2 - transparent main
window](https://stackoverflow.com/q/14780504/9014308)  
[QQuickWindow transparent](https://stackoverflow.com/q/18533641/9014308)  
[widget透過のまとめ](http://folioscope.hatenablog.jp/entry/20110104/1294157371)

他にこんなのも。  
[Kivyで非矩形ウィンドウ](https://qiita.com/nawonaototomousu/items/ed0690ac3e4cddb63b8c)  
[GTK+で非矩形ウィンドウを表示する](https://blogs.osdn.jp/2018/07/10/gtkmm-transparent.html)  
[デスクトップマスコット MaCoPiX](https://another.maple4ever.net/archives/1454/)

* * *

そしてこれらみんなのルーツとも言えそうな、neko もありますね。  
今回の参考にはならないかもしれませんが。  
[Neko (ソフトウェア) -
ウィキペディア](https://ja.wikipedia.org/wiki/Neko_\(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2\))  
[なつかしのoneko on Fedora 26](https://pandanote.info/?p=764)  
[猫がマウスカーソルを追いかけるソフト
oneko](http://tenten909.blog.shinobi.jp/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E9%96%A2%E9%80%A3/%E7%8C%AB%E3%81%8C%E3%83%9E%E3%82%A6%E3%82%B9%E3%82%AB%E3%83%BC%E3%82%BD%E3%83%AB%E3%82%92%E8%BF%BD%E3%81%84%E3%81%8B%E3%81%91%E3%82%8B%E3%82%BD%E3%83%95%E3%83%88%E3%80%80oneko)  
[Linux / Unix Desktop Fun: Cat And Mouse Chase All Over Your
Screen](https://www.cyberciti.biz/open-source/oneko-app-creates-cute-cat-
chasing-around-your-mouse/)  
[kazunari03/oneko-linux](https://github.com/kazunari03/oneko-linux)  
[oneko-sakura](http://www.daidouji.com/oneko/)


CC BY-SA 4.0
2019-04-13T16:40:51.177
54148
2019-04-13T16:40:51.177
26370
54077
answer


Qtで作ってみました。

始めに、次のような画像を用意します。周囲の部分は透明にして、透過PNG形式で保存します。

[![画像の説明をここに入力](https://i.stack.imgur.com/1gW0O.png)](https://i.stack.imgur.com/1gW0O.png)

Qt Creatorで、Qt GUIアプリのプロジェクトを新規作成します。  
メニューバーとステータスバーは不要なので削除します。  
画像サイズに合わせてgeometryの幅と高さを設定し、sizePolicyをFixedにします。  
必要に応じてボタンなどのGUI部品を配置します。

[![画像の説明をここに入力](https://i.stack.imgur.com/961WA.png)](https://i.stack.imgur.com/961WA.png)

アプリケーションにリソースファイルを追加し、画像ファイルを登録します。

MainWindowのコンストラクタで、フレーム無しで、ウィンドウを透明にする設定を記述します。

[code]

    setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_TranslucentBackground);
    setAutoFillBackground(true);
    
[/code]

MainWindowのヘッダファイルにQImageオブジェクトをメンバ変数として持たせ、そこに画像を読み込ませます。

[code]

    bg_image_.load(":/image/bg.png");
    bg_image_ = bg_image_.convertToFormat(QImage::Format_RGBA8888);
    int w = bg_image_.width();
    int h = bg_image_.height();
    setFixedSize(w, h);
    
[/code]

Windowsでは不要ですが、LinuxとmacOSでは透過部分を指定するためのマスクビットマップが必要ですので、生成して登録します。

[code]

    QImage maskimage(w, h, QImage::Format_Grayscale8);
    for (int y = 0; y < h; y++) {
        uint8_t const *src = bg_image_.scanLine(y);
        uint8_t *dst = maskimage.scanLine(y);
        for (int x = 0; x < w; x++) {
            dst[x] = src[x * 4 + 3] < 128 ? 255 : 0;
        }
    }
    setMask(QBitmap::fromImage(maskimage));
    
[/code]

paintEventで画像を描画します。

[code]

    QPainter pr(this);
    pr.drawImage(0, 0, bg_image_);
    
[/code]

それ以外は普通のQtアプリ開発と同じです。

[![画像の説明をここに入力](https://i.stack.imgur.com/3GWou.png)](https://i.stack.imgur.com/3GWou.png)

OpenGLは使ったことはありませんが、QGLWidgetかQOpenGLWidgetを使うとできるかもしれません。ただし、透過部分を指定するビットマップの生成が面倒そうです。

ソースコード <https://github.com/soramimi/Kyle>


CC BY-SA 4.0
2019-04-17T13:17:14.877
54262
2019-04-17T13:17:14.877
3337
54077
answer