gtk+opengl窗口最小化的一个bug

在给gtk画的界面加上opengl绘图之后,发现最小化之后,任务栏的小图标直接消失了

然后找到了这么一个api

void
gtk_window_set_skip_taskbar_hint (GtkWindow *window,
                                  gboolean setting);

Windows may set a hint asking the desktop environment not to display the window in the task bar. This function sets this hint.

Parameters

window

GtkWindow

 

setting

TRUE to keep this window from appearing in the task bar

   

设置窗口是否在任务栏显示,如果为TRUE,则不在任务栏显示,如果为FALSE,则在任务栏显示(一般默认都是这样)

然后我通过gtk_window_get_skip_taskbar_hint ()取了一下这个标记,发现是FALSE

虽然这个标记未必有用,解释可以看这里https://www.xuebuyuan.com/1003446.html,但我没设置过隐藏,总不能给我自动隐藏了吧

后来写了同样的代码,发现在linux上是没有问题的,然而在windows上就是有问题,最小化,窗口消失了

如果单单是gtk的代码,不加上opengl来绘图,在windows上也是没有问题的,所以猜测这也许是gtk在windows上的一个bug

代码,见上一篇 https://blog.csdn.net/Since_lily/article/details/87939764

然后,查了下GtkWidget窗口的信号

The “window-state-event” signal

gboolean
user_function (GtkWidget *widget,
               GdkEvent  *event,
               gpointer   user_data)

The ::window-state-event will be emitted when the state of the toplevel window associated to the widget changes.

To receive this signal the GdkWindow associated to the widget needs to enable the GDK_STRUCTURE_MASK mask. GDK will enable this mask automatically for all new windows.

Parameters

widget

the object which received the signal

 

event

the GdkEventWindowState which triggered this signal.

[typeGdk.EventWindowState]

user_data

user data set when the signal handler was connected.

 

Returns

TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.

窗口最小化,最大化等等的时候都会触发这个信号window-state-event,通过回调可以截获信号并处理

第二个参数是一个event的结构体指针,在此处,结构体如下

struct GdkEventWindowState

struct GdkEventWindowState {
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  GdkWindowState changed_mask;
  GdkWindowState new_window_state;
};

Generated when the state of a toplevel window changes.

Members

GdkEventType type;

the type of the event (GDK_WINDOW_STATE).

 

GdkWindow *window;

the window which received the event.

 

gint8 send_event;

TRUE if the event was sent explicitly.

 

GdkWindowState changed_mask;

mask specifying what flags have changed.

 

GdkWindowState new_window_state;

the new window state, a combination ofGdkWindowState bits.

关键在GdkWindowState结构中state的变化

/**
 * GdkWindowState:
 * @GDK_WINDOW_STATE_WITHDRAWN: the window is not shown.
 * @GDK_WINDOW_STATE_ICONIFIED: the window is minimized.
 * @GDK_WINDOW_STATE_MAXIMIZED: the window is maximized.
 * @GDK_WINDOW_STATE_STICKY: the window is sticky.
 * @GDK_WINDOW_STATE_FULLSCREEN: the window is maximized without
 *   decorations.
 * @GDK_WINDOW_STATE_ABOVE: the window is kept above other windows.
 * @GDK_WINDOW_STATE_BELOW: the window is kept below other windows.
 * @GDK_WINDOW_STATE_FOCUSED: the window is presented as focused (with active decorations).
 * @GDK_WINDOW_STATE_TILED: the window is in a tiled state, Since 3.10. Since 3.22.23, this
 *                          is deprecated in favor of per-edge information.
 * @GDK_WINDOW_STATE_TOP_TILED: whether the top edge is tiled, Since 3.22.23
 * @GDK_WINDOW_STATE_TOP_RESIZABLE: whether the top edge is resizable, Since 3.22.23
 * @GDK_WINDOW_STATE_RIGHT_TILED: whether the right edge is tiled, Since 3.22.23
 * @GDK_WINDOW_STATE_RIGHT_RESIZABLE: whether the right edge is resizable, Since 3.22.23
 * @GDK_WINDOW_STATE_BOTTOM_TILED: whether the bottom edge is tiled, Since 3.22.23
 * @GDK_WINDOW_STATE_BOTTOM_RESIZABLE: whether the bottom edge is resizable, Since 3.22.23
 * @GDK_WINDOW_STATE_LEFT_TILED: whether the left edge is tiled, Since 3.22.23
 * @GDK_WINDOW_STATE_LEFT_RESIZABLE: whether the left edge is resizable, Since 3.22.23
 *
 * Specifies the state of a toplevel window.
 */
typedef enum 
{
  GDK_WINDOW_STATE_WITHDRAWN        = 1 << 0,
  GDK_WINDOW_STATE_ICONIFIED        = 1 << 1,
  GDK_WINDOW_STATE_MAXIMIZED        = 1 << 2,
  GDK_WINDOW_STATE_STICKY           = 1 << 3,
  GDK_WINDOW_STATE_FULLSCREEN       = 1 << 4,
  GDK_WINDOW_STATE_ABOVE            = 1 << 5,
  GDK_WINDOW_STATE_BELOW            = 1 << 6,
  GDK_WINDOW_STATE_FOCUSED          = 1 << 7,
  GDK_WINDOW_STATE_TILED            = 1 << 8,
  GDK_WINDOW_STATE_TOP_TILED        = 1 << 9,
  GDK_WINDOW_STATE_TOP_RESIZABLE    = 1 << 10,
  GDK_WINDOW_STATE_RIGHT_TILED      = 1 << 11,
  GDK_WINDOW_STATE_RIGHT_RESIZABLE  = 1 << 12,
  GDK_WINDOW_STATE_BOTTOM_TILED     = 1 << 13,
  GDK_WINDOW_STATE_BOTTOM_RESIZABLE = 1 << 14,
  GDK_WINDOW_STATE_LEFT_TILED       = 1 << 15,
  GDK_WINDOW_STATE_LEFT_RESIZABLE   = 1 << 16
} GdkWindowState;

找到了所有的event,大概是一个数的16个bit位,每一位代表一个含义

比如,窗口是最小化状态,那么第1位一定是1(gtk_widget_iconify)

点击了任务栏的图标,窗口显示出来,这时候第一位被置0(gtk_widget_deiconify或 gtk_widget_show等等)

static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
{
	slog("<%s>---mask=[%d]-----new_window_state=[%d]", __func__, event->changed_mask, event->new_window_state);

    return FALSE;
}

于是,就捕捉event,查看changed_mask和new_window_state,发现了问题所在

当点击最小化按钮,第1位被置1,第0位被置1,代表窗口最小化,同时不显示,这时,窗口应该是最小化状态,只显示任务栏图标,但是,任务栏图标没有,窗口直接凭空消失了

看来,gtk窗口和opengl在windows上结合得不是很好,但问题总要解决啊,不能把最小化按钮给禁掉啊,太不人性化了

解决方案

既然不加opengl的窗口是正常的,那就让有opengl的窗口不最小化,而是隐藏掉

用一个不可见的小窗口作为跳板,实际上最小化的时候,任务栏的图标是那个小窗口的,大窗口只有hide和show两个状态,没有iconify的状态

代码如下

#include <glib.h>
#include <gtk/gtk.h>
 
#include "GL/glew.h"
#include <stdio.h>
 
static GtkWidget *window;
static GtkWidget *first_window = NULL;
 
FILE *fp;
 
// Shaders 以定义字符串的方式给出
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
const GLchar* fragmentShaderSource = "#version 330 core\n"
"uniform vec4 mycolor;\n"
"void main()\n"
"{\n"
"gl_FragColor = mycolor;\n"
"}\n\0";
 
 
//main函数调用,定义成全局形式
GLuint VAO, VBO;/*声明VAO,VBO*/
GLuint vertexShader, fragmentShader, shaderProgram;/*声明着色器对象和着色器程序对象*/
 
void slog_init()
{
	fp = fopen("log.txt", "a+");
	if(NULL == fp){
		printf("log_init failed.");
	}
}
 
void slog(char * fmt,...)
{
	va_list  ap;
 
	if( NULL != fp){
		va_start(ap, fmt);
		vfprintf(fp, fmt, ap);
		va_end(ap);
		fprintf(fp, "\n");
		fflush(fp);
	}
}
 
//VBO,VAO初始化
void draw_init()
{
	GLfloat vertices[] = {
		-0.5f,-0.5f,0.0f,
		0.5f,-0.5f,0.0f,
		0.0f,0.5f,0.0f	};
 
	//生成顶点数组对象VAO
	glGenVertexArrays(1, &VAO);
	//生成顶点缓冲对象VBO
	glGenBuffers(1, &VBO);
	//绑定VAO
	glBindVertexArray(VAO);
	//绑定VBO
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//复制顶点数据到VB0
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 
	//解释顶点数据链接方式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 3 * sizeof(GLfloat),(GLvoid *) 0);
	//glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 0, 0);/*两个顶点属性之间无间隙,第五个参数可设置为0*/
	glEnableVertexAttribArray(0);/*开启顶点属性,参数是顶点属性location*/
 
	//解绑VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	//解绑VAO
	glBindVertexArray(0);

	//生成顶点着色器
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);/*着色器源码附加到着色器对象上*/
	glCompileShader(vertexShader);/*编译顶点着色器*/
 
	//检查顶点着色器是否编译成功,不成功输出错误信息
	GLint success;
	GLchar infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		slog("---shaderinit-----GetShaderiv error=[%d]", success);
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		glDeleteShader(vertexShader);
	}
	
	//生成片段着色器
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);
	
	//检查片段着色器是否编译成功,不成功输出错误信息
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		slog("---shaderinit-----GetShaderiv error=[%d]", success);
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		glDeleteShader(fragmentShader);
	}
 
	//生成着色器程序对象,并连接着色器
	shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);/*把编译好的着色器附加到着色器程序对象上*/
	glAttachShader(shaderProgram, fragmentShader);
 
	//尝试链接
	glLinkProgram(shaderProgram);
	//检查链接着色器程序是否成功,不成功输出错误信息
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if(!success)
	{
		slog("---shaderinit-----GetShaderiv error=[%d]", success);
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		glDeleteProgram(shaderProgram);
	}
 
	//删除着色器
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
}
 
gboolean
display(gpointer user_data)
{
	gtk_gl_area_queue_render(GTK_GL_AREA(user_data));
 
   return TRUE;
}

gboolean
render(GtkWidget *area, gpointer user_data)
{
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// clear the window
	glClear(GL_COLOR_BUFFER_BIT);
	
	int timeValue = time(NULL);
	float blueValue = sin(timeValue) / 2.0f + 0.5f;
	glUniform4f(glGetUniformLocation(shaderProgram, "mycolor"), 0.0f, 0.0f, blueValue, 1.0f);

    //绘制过程	
	glUseProgram(shaderProgram);
	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 3);
	glBindVertexArray(0);

  return TRUE;
}
 
void
realize(GtkWidget *area, gpointer user_data)
{
	gtk_gl_area_make_current(GTK_GL_AREA(area));
	if (gtk_gl_area_get_error(GTK_GL_AREA(area)) != NULL)
        	return;
 
	glewExperimental = GL_TRUE;
	gboolean ret = glewInit();
	if(ret != GLEW_OK)
	{
		slog("<%s>--------glew init error [%s]", __func__, glewGetErrorString(ret));
	}
	
	draw_init();
	
	g_timeout_add(100, display, area);
	
}

static void
unrealize (GtkWidget *widget)
{
  gtk_gl_area_make_current (GTK_GL_AREA (widget));

  if (gtk_gl_area_get_error (GTK_GL_AREA (widget)) != NULL)
    return;

  glDeleteBuffers (1, &VAO);
  glDeleteProgram (shaderProgram);
}

static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
{
	slog("<%s>---mask=[%d]-----new_window_state=[%d]", __func__, event->changed_mask, event->new_window_state);

	if((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED ))
    { 		
		slog("<-------------------->---minimized");
				
		gtk_widget_show(first_window);
        gtk_widget_hide(window);
        gtk_window_iconify(GTK_WINDOW(first_window));
        
        return TRUE;
    }
    return FALSE;
}

static gboolean window_state_event1 (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
{
	slog("<%s>---mask=[%d]-----new_window_state=[%d]", __func__, event->changed_mask, event->new_window_state);

	if((event->changed_mask == GDK_WINDOW_STATE_ICONIFIED) && (!(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)))
    {
		slog("<%s>---show main window", __func__);
		
        gtk_window_deiconify(GTK_WINDOW(window));
		gtk_widget_show(window);
		gtk_widget_hide(first_window);
		return TRUE;
    }
	return FALSE;
}
 
static void create_window(void)
{
	window = gtk_window_new(GDK_WINDOW_ROOT);
 
	gtk_window_set_title(GTK_WINDOW(window),"Triangle");
	gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); 
	
	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
	gtk_widget_set_size_request(window, 800,800);
//	gtk_window_fullscreen(GTK_WINDOW(window));
g_signal_connect (G_OBJECT(window), "window-state-event", G_CALLBACK(window_state_event), NULL);
 
	GError *error = NULL;
 
	GtkWidget *area = gtk_gl_area_new();
	gtk_gl_area_set_required_version(GTK_GL_AREA(area), 3, 2);
	gtk_gl_area_set_auto_render(GTK_GL_AREA(area), FALSE);
	
	g_object_connect(area,
			"signal::render", render, NULL,
			"signal::realize", realize, NULL,
			"signal::unrealize", unrealize, NULL,
			NULL);
 
	gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(area));
 
 
 	gtk_widget_hide(first_window);
	gtk_widget_show_all(window);
}

static void create_first_window(void)
{
	first_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

	gtk_window_set_title(GTK_WINDOW(first_window),"First Window");
	gtk_window_set_position(GTK_WINDOW(first_window),GTK_WIN_POS_CENTER); 
	gtk_window_set_icon(GTK_WINDOW(window), gdk_pixbuf_new_from_file("awesomeface.png", NULL));
	gtk_window_set_resizable(GTK_WINDOW(first_window), FALSE);
	gtk_widget_set_size_request(first_window, 200,200);
	
	g_signal_connect (G_OBJECT(first_window), "window-state-event", G_CALLBACK(window_state_event1), NULL);

	gtk_widget_show_all(first_window);

}
 
int main(int argc, char *argv[])
{
	slog_init();
	gtk_init(&argc, &argv);
 
 create_first_window();
	create_window();
 
	gtk_main();
}

猜你喜欢

转载自blog.csdn.net/Since_lily/article/details/88392551
今日推荐