X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fmain.c;h=970774d2eac52a7ff5350891f8442619287eb265;hb=88cddf89c868fa3c62f51078dddc588b897f1af0;hp=1cabcf637dc992dd14dcf71656795e371e218c5a;hpb=574302ed0fced0d57233c4517d414b4c3e875d7d;p=geometrycompositor.git diff --git a/source/main.c b/source/main.c index 1cabcf6..970774d 100644 --- a/source/main.c +++ b/source/main.c @@ -26,6 +26,8 @@ typedef struct CompositedWindow Pixmap pixmap; GLXPixmap glx_pixmap; unsigned texture; + unsigned mask_texture; + int use_mask; } CompositedWindow; typedef struct CompositedMonitor @@ -58,9 +60,11 @@ typedef struct CompositedScreen GLXFBConfig fbconfig; GLXWindow glx_window; GLXContext glx_context; - unsigned shaders[2]; + unsigned shaders[3]; unsigned program; - unsigned geometry_loc; + int geometry_loc; + unsigned masked_program; + int masked_geometry_loc; unsigned window_vertex_buffer; unsigned window_vertex_array; unsigned framebuffer; @@ -79,6 +83,7 @@ typedef struct Compositor CompositedScreen *screens; unsigned nscreens; int damage_event; + int shape_event; PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB; PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT; PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT; @@ -87,7 +92,7 @@ typedef struct Compositor int dirty; } Compositor; -static const char *vshader = +static const char *vshader_src = "#version 150\n" "uniform vec4 geometry;\n" "in vec2 vertex;\n" @@ -99,7 +104,7 @@ static const char *vshader = " texcoord = texture_coord;\n" "}\n"; -static const char *fshader = +static const char *fshader_src = "#version 150\n" "uniform sampler2D image;\n" "in vec2 texcoord;\n" @@ -109,6 +114,19 @@ static const char *fshader = " frag_color = texture(image, texcoord);\n" "}\n"; +static const char *masked_fshader_src = + "#version 150\n" + "uniform sampler2D image;\n" + "uniform sampler2D mask;\n" + "in vec2 texcoord;\n" + "out vec4 frag_color;\n" + "void main()\n" + "{\n" + " if(texture(mask, texcoord).r==0.0)\n" + " discard;\n" + " frag_color = texture(image, texcoord);\n" + "}\n"; + static const float window_vertices[] = { /* vertex texcoord */ @@ -211,17 +229,16 @@ unsigned compile_shader(GLenum type, const char *source) return shader; } -unsigned link_program(unsigned *shaders, unsigned nshaders) +unsigned link_program(unsigned vshader, unsigned fshader) { unsigned program; - unsigned i; int status; char info_log[1024]; GLsizei length; program = glCreateProgram(); - for(i=0; ishaders[0] = compile_shader(GL_VERTEX_SHADER, vshader); - screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader); - if(!screen->shaders[0] || !screen->shaders[1]) + screen->shaders[0] = compile_shader(GL_VERTEX_SHADER, vshader_src); + screen->shaders[1] = compile_shader(GL_FRAGMENT_SHADER, fshader_src); + screen->shaders[2] = compile_shader(GL_FRAGMENT_SHADER, masked_fshader_src); + if(!screen->shaders[0] || !screen->shaders[1] || !screen->shaders[2]) return 0; - screen->program = link_program(screen->shaders, 2); + screen->program = link_program(screen->shaders[0], screen->shaders[1]); if(!screen->program) return 0; + screen->masked_program = link_program(screen->shaders[0], screen->shaders[2]); + if(!screen->masked_program) + return 0; + screen->geometry_loc = glGetUniformLocation(screen->program, "geometry"); + screen->masked_geometry_loc = glGetUniformLocation(screen->masked_program, "geometry"); + + loc = glGetUniformLocation(screen->masked_program, "mask"); + if(loc>=0) + { + glUseProgram(screen->masked_program); + glUniform1i(loc, 1); + } glGenBuffers(1, &screen->window_vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, screen->window_vertex_buffer); @@ -273,12 +315,8 @@ int create_gl_resources(Compositor *compositor, CompositedScreen *screen) glBindBuffer(GL_ARRAY_BUFFER, 0); - glGenTextures(1, &screen->fb_texture); - glBindTexture(GL_TEXTURE_2D, screen->fb_texture); + screen->fb_texture = create_2d_texture(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screen->width, screen->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, 0); glGenFramebuffers(1, &screen->framebuffer); @@ -301,6 +339,24 @@ CompositedWindow *find_window(CompositedScreen *screen, Window w) return NULL; } +CompositedWindow *find_window_global(Compositor *compositor, Window w, CompositedScreen **screen) +{ + unsigned i, j; + + for(i=0; inscreens; ++i) + for(j=0; jscreens[i].nwindows; ++j) + if(compositor->screens[i].windows[j].window==w) + { + if(screen) + *screen = &compositor->screens[i]; + return &compositor->screens[i].windows[j]; + } + + if(screen) + *screen = NULL; + return NULL; +} + void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window) { int attribs[5]; @@ -323,6 +379,75 @@ void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, Comp window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs); } +void update_window_mask(Compositor *compositor, CompositedWindow *window) +{ + Bool bounding_shaped; + Bool clip_shaped; + int xi, yi; + XRectangle *rects; + int rect_count; + int rect_order; + unsigned width; + unsigned height; + unsigned char *data; + int i; + unsigned y; + + XShapeQueryExtents(compositor->display, window->window, &bounding_shaped, &xi, &yi, &width, &height, &clip_shaped, &xi, &yi, &width, &height); + window->use_mask = bounding_shaped; + if(!window->use_mask) + return; + + rects = XShapeGetRectangles(compositor->display, window->window, ShapeBounding, &rect_count, &rect_order); + + width = window->width+2*window->border; + height = window->height+2*window->border; + data = (unsigned char *)malloc(width*height); + memset(data, 0, width*height); + for(i=0; iborder; + rects[i].y += window->border; + if(rects[i].x>=(int)width || rects[i].y>=(int)height) + continue; + + if(rects[i].x<0) + { + if(-rects[i].x>rects[i].width) + continue; + rects[i].width += rects[i].x; + rects[i].x = 0; + } + + if(rects[i].y<0) + { + if(-rects[i].y>rects[i].height) + continue; + rects[i].height += rects[i].y; + rects[i].y = 0; + } + + if(rects[i].x+rects[i].width>(int)width) + rects[i].width = width-rects[i].x; + if(rects[i].y+rects[i].height>(int)height) + rects[i].height = height-rects[i].y; + + for(y=0; ymask_texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data); + + free(data); +} + CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, Window w) { CompositedWindow *window; @@ -366,11 +491,13 @@ CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, W if(window->map_state==IsViewable) create_window_pixmap(compositor, screen, window); - glGenTextures(1, &window->texture); - glBindTexture(GL_TEXTURE_2D, window->texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + window->texture = create_2d_texture(); + window->mask_texture = create_2d_texture(); + + if(window->map_state==IsViewable) + update_window_mask(compositor, window); + + XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask); return window; } @@ -444,18 +571,6 @@ CompositedScreen *find_screen_by_root(Compositor *compositor, Window root) return NULL; } -CompositedScreen *find_screen_by_window(Compositor *compositor, Window w) -{ - unsigned i, j; - - for(i=0; inscreens; ++i) - for(j=0; jscreens[i].nwindows; ++j) - if(compositor->screens[i].windows[j].window==w) - return &compositor->screens[i]; - - return NULL; -} - void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monitor) { unsigned t; @@ -777,7 +892,7 @@ int initialize_compositor(Compositor *compositor) else if(major_ver<1) return with_error("XDamage 1.0 or later is required"); - if(!XShapeQueryExtension(compositor->display, &event_base, &error_base)) + if(!XShapeQueryExtension(compositor->display, &compositor->shape_event, &error_base)) return with_error("XShape is required but was not found"); else if(!XShapeQueryVersion(compositor->display, &major_ver, &minor_ver)) return with_error("Cannot determine XShape version"); @@ -818,6 +933,7 @@ void shutdown_screen(Compositor *compositor, CompositedScreen *screen) for(i=0; inwindows; ++i) { glDeleteTextures(1, &screen->windows[i].texture); + glDeleteTextures(1, &screen->windows[i].mask_texture); if(screen->windows[i].pixmap) { glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap); @@ -842,8 +958,9 @@ void shutdown_screen(Compositor *compositor, CompositedScreen *screen) glDeleteFramebuffers(1, &screen->framebuffer); glDeleteTextures(1, &screen->fb_texture); glDeleteProgram(screen->program); - glDeleteShader(screen->shaders[0]); - glDeleteShader(screen->shaders[1]); + glDeleteProgram(screen->masked_program); + for(i=0; i<3; ++i) + glDeleteShader(screen->shaders[i]); glXMakeContextCurrent(compositor->display, 0, 0, NULL); glXDestroyContext(compositor->display, screen->glx_context); @@ -906,6 +1023,7 @@ void process_map_event(Compositor *compositor, XMapEvent *event) window->map_state = IsViewable; create_window_pixmap(compositor, screen, window); + update_window_mask(compositor, window); mark_dirty(compositor, screen); } @@ -971,6 +1089,7 @@ void process_configure_event(Compositor *compositor, XConfigureEvent *event) window->height = event->height; window->border = event->border_width; create_window_pixmap(compositor, screen, window); + update_window_mask(compositor, window); } reorder_window(screen, window, event->above); @@ -997,13 +1116,25 @@ void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event) CompositedScreen *screen; CompositedWindow *window; - screen = find_screen_by_window(compositor, event->drawable); - if(!screen) + window = find_window_global(compositor, event->drawable, &screen); + if(window && window->map_state==IsViewable) + mark_dirty(compositor, screen); +} + +void process_shape_event(Compositor *compositor, XShapeEvent *event) +{ + CompositedScreen *screen; + CompositedWindow *window; + + if(event->kind!=ShapeBounding) return; - window = find_window(screen, event->drawable); - if(window->map_state==IsViewable) + window = find_window_global(compositor, event->window, &screen); + if(window && window->map_state==IsViewable) + { + update_window_mask(compositor, window); mark_dirty(compositor, screen); + } } int process_event(Compositor *compositor) @@ -1043,6 +1174,8 @@ int process_event(Compositor *compositor) default: if(event.type==compositor->damage_event+XDamageNotify) process_damage_event(compositor, (XDamageNotifyEvent *)&event); + else if(event.type==compositor->shape_event+ShapeNotify) + process_shape_event(compositor, (XShapeEvent *)&event); else printf("Event %d\n", event.type); } @@ -1053,6 +1186,7 @@ int process_event(Compositor *compositor) void refresh_screen(Compositor *compositor, CompositedScreen *screen) { unsigned i; + int use_mask; use_gl(compositor, screen); @@ -1061,7 +1195,7 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen) glClearColor(0.5f, 0.5f, 0.5f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(screen->program); + use_mask = -1; glBindVertexArray(screen->window_vertex_array); for(i=0; inwindows; ++i) { @@ -1069,14 +1203,28 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen) if(window->map_state!=IsViewable) continue; + if(window->use_mask!=use_mask) + { + use_mask = window->use_mask; + glUseProgram(use_mask ? screen->masked_program : screen->program); + } + + if(window->use_mask) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, window->mask_texture); + glActiveTexture(GL_TEXTURE0); + } + + XDamageSubtract(compositor->display, window->damage, None, None); + glBindTexture(GL_TEXTURE_2D, window->texture); compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL); - glUniform4f(screen->geometry_loc, + glUniform4f((use_mask ? screen->masked_geometry_loc : screen->geometry_loc), (float)window->x/screen->width, 1.0f-(float)(window->y+window->height)/screen->height, (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT); - XDamageSubtract(compositor->display, window->damage, None, None); } glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); @@ -1085,6 +1233,8 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen) glBindTexture(GL_TEXTURE_2D, screen->fb_texture); glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(0xFFFF); + if(use_mask) + glUseProgram(screen->program); for(i=0; inmonitors; ++i) {