/* Style.cc Copyright © 2003 David Reveman. This file is part of Waimea. Waimea is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Waimea is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Waimea; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif // HAVE_CONFIG_H extern "C" { #include #ifdef STDC_HEADERS # include # include #endif // STDC_HEADERS #ifdef HAVE_STRINGS_H # include #endif // HAVE_STRINGS_H #ifdef HAVE_LIBGEN_H # include #else inline char *basename(char *name) { int i = strlen(name); for (; i >= 0 && name[i] != '/'; i--); if (name[i] == '/') i++; return &name[i]; } #endif // HAVE_LIBGEN_H #ifdef LIMITS_H # include #endif // LIMITS_H #ifdef HAVE_UNISTD_H # include # include # include #endif // HAVE_UNISTD_H #ifdef HAVE_MATH_H # include #endif // HAVE_MATH_H } #include "Style.hh" Style::Style(WaScreen *_ws, char *_name) : RenderGroup(_ws, _name) { translucent = shaped = false; focusable = false; textops = NULL; subs = NULL; cursor = (Cursor) 0; left_spacing = right_spacing = top_spacing = bottom_spacing = grid_spacing = 0; left_spacing_u = right_spacing_u = top_spacing_u = bottom_spacing_u = grid_spacing_u = PXLenghtUnitType; _w = RENDER_WIDTH_DEFAULT; _h = RENDER_HEIGHT_DEFAULT; _wu = _hu = PXLenghtUnitType; is_a_style = true; shapemask = NULL; orientation = VerticalOrientationType; serial = 0; } Style::~Style(void) { if (shapemask) shapemask->unref(); clear(); } void Style::clear(void) { if (textops) { while (! textops->empty()) { textops->back()->unref(); textops->pop_back(); } delete textops; textops = NULL; } if (subs) { while (! subs->empty()) { subs->back()->unref(); subs->pop_back(); } delete subs; subs = NULL; } ((RenderGroup *) this)->clear(); } void Style::inheritContent(Style *inherit_style) { if (inherit_style->subs) { list::iterator it = inherit_style->subs->begin(); for (; it != inherit_style->subs->end(); it++) { if (! subs) subs = new list; subs->push_back((*it)->ref()); } } ((RenderGroup *) this)->inheritContent((RenderGroup *) inherit_style); } void Style::inheritAttributes(Style *inherit_style) { translucent = inherit_style->translucent; focusable = inherit_style->focusable; shaped = inherit_style->shaped; left_spacing = inherit_style->left_spacing; right_spacing = inherit_style->right_spacing; top_spacing = inherit_style->top_spacing; bottom_spacing = inherit_style->bottom_spacing; grid_spacing = inherit_style->grid_spacing; left_spacing_u = inherit_style->left_spacing_u; right_spacing_u = inherit_style->right_spacing_u; top_spacing_u = inherit_style->top_spacing_u; bottom_spacing_u = inherit_style->bottom_spacing_u; grid_spacing_u = inherit_style->grid_spacing_u; _w = inherit_style->_w; _h = inherit_style->_h; _wu = inherit_style->_wu; _hu = inherit_style->_hu; cursor = inherit_style->cursor; orientation = inherit_style->orientation; } void Style::applyAttributes(Parser *parser, Tst *attr) { char *value = parser->attrGetString(attr, "inherit", NULL); if (value) { Style *inherit_style = ws->getStyleNamed(value, false); if (inherit_style == this) { parser->warning("style %s cannot inherit itself\n", name); } else if (inherit_style) { inheritAttributes(inherit_style); } else { if (! parser->attrGetBool(attr, "ignore_missing", false)) parser->warning("undefined style: %s\n", value); } } ((RenderGroup *) this)->applyAttributes(parser, attr); shaped = parser->attrGetBool(attr, "alpha_level_shape", shaped); translucent = parser->attrGetBool(attr, "translucent", translucent); focusable = parser->attrGetBool(attr, "focusable", focusable); left_spacing = parser->attrGetLength(attr, "left_spacing", left_spacing, &left_spacing_u); right_spacing = parser->attrGetLength(attr, "right_spacing", right_spacing, &right_spacing_u); top_spacing = parser->attrGetLength(attr, "top_spacing", top_spacing, &top_spacing_u); bottom_spacing = parser->attrGetLength(attr, "bottom_spacing", bottom_spacing, &bottom_spacing_u); grid_spacing = parser->attrGetLength(attr, "grid_spacing", grid_spacing, &grid_spacing_u); value = parser->attrGetString(attr, "cursor", NULL); if (value) { #ifdef XCURSOR char *cursorfile = smartfile(value, parser->filename, false); if (cursorfile) cursor = ws->waimea->cursor->getCursor(cursorfile); else #endif // XCURSOR cursor = ws->waimea->cursor->getCursor(value); } value = parser->attrGetString(attr, "orientation", NULL); if (value && (! strcmp(value, "horizontal"))) orientation = HorizontalOrientationType; } DWindowObject::DWindowObject(WaScreen *_ws, Window _id, int _type, WaStringMap *_sm, char *_name) : AWindowObject(_ws, _id, _type, _sm, _name) { style = NULL; sb = NULL; hidden = force_texture = force_alpha = force_setbg = true; mapRequest = false; #ifdef THREAD if (__render_thread_count) pthread_mutex_init(&__win__render_safe_mutex, NULL); #endif // THREAD memset(styles, 0, sizeof(styles)); memset(default_styles, 0, sizeof(default_styles)); for (int i = 0; i < WIN_STATE_LAST; i++) { style_buffers[i].style = NULL; style_buffers[i].surface = NULL; style_buffers[i].text_table = NULL; style_buffers[i].x = INT_MAX; style_buffers[i].y = INT_MAX; style_buffers[i].bg = None; style_buffers[i].width = style_buffers[i].height = 0; } } DWindowObject::~DWindowObject(void) { DWIN_RENDER_GET(this); RENDER_LIST_LOCK; list::iterator it = __render_list.begin(); while (it != __render_list.end()) { if (*it == this) it = __render_list.erase(it); else it++; } RENDER_LIST_RELEASE; DWIN_RENDER_RELEASE(this); #ifdef THREAD if (__render_thread_count) pthread_mutex_destroy(&__win__render_safe_mutex); #endif // THREAD MAPUNREFSECOND(dynamic_groups); for (int i = 0; i < WIN_STATE_LAST; i++) { if (style_buffers[i].style) style_buffers[i].style->unref(); if (style_buffers[i].surface) style_buffers[i].surface->unref(); MAPUNREFSECOND(style_buffers[i].cache_table); if (style_buffers[i].text_table) MAPPTRCLEAR(style_buffers[i].text_table); MAPUNREFSECOND(style_buffers[i].dynamic_groups); } for (int i = 0; i < WIN_STATE_LAST; i++) { if (styles[i]) styles[i]->unref(); if (default_styles[i]) default_styles[i]->unref(); } if (style) style->unref(); } void DWindowObject::resetStyle(void) { if (! ws) return; list *ls = NULL; destroySubwindows(); force_texture = true; for (int i = 0; i < WIN_STATE_LAST; i++) { if (style_buffers[i].style) style_buffers[i].style->unref(); style_buffers[i].style = NULL; if (style_buffers[i].surface) style_buffers[i].surface->unref(); style_buffers[i].surface = NULL; MAPUNREFSECOND(style_buffers[i].cache_table); if (style_buffers[i].text_table) MAPPTRCLEAR(style_buffers[i].text_table); style_buffers[i].text_table = NULL; style_buffers[i].x = INT_MAX; style_buffers[i].y = INT_MAX; style_buffers[i].bg = None; style_buffers[i].width = style_buffers[i].height = 0; MAPUNREFSECOND(style_buffers[i].dynamic_groups); } for (int i = 0; i < WIN_STATE_LAST; i++) { if (styles[i]) styles[i]->unref(); if (default_styles[i]) default_styles[i]->unref(); } memset(styles, 0, sizeof(styles)); memset(default_styles, 0, sizeof(default_styles)); switch (decor_root->type) { case WindowFrameType: ls = &ws->window_styles; break; case DockHandlerType: ls = &ws->dockappholder_styles; break; case RootType: ls = &ws->root_styles; break; case MenuType: case MenuItemType: ls = &ws->menu_styles; break; } if (style) style->unref(); style = NULL; sb = NULL; if (ls) { list::iterator it = ls->begin(); for (; it != ls->end(); it++) { if ((styles[WIN_STATE_PASSIVE] = (*it)->match(ids, WIN_STATE_PASSIVE, window_name))) { break; } } for (it = ls->begin(); it != ls->end(); it++) { if ((styles[WIN_STATE_ACTIVE] = (*it)->match(ids, WIN_STATE_ACTIVE, window_name))) { break; } } for (it = ls->begin(); it != ls->end(); it++) { if ((styles[WIN_STATE_HOVER] = (*it)->match(ids, WIN_STATE_HOVER, window_name))) { break; } } for (it = ls->begin(); it != ls->end(); it++) { if ((styles[WIN_STATE_PRESSED] = (*it)->match(ids, WIN_STATE_PRESSED, window_name))) { break; } } } if (! styles[WIN_STATE_PASSIVE]) styles[WIN_STATE_PASSIVE] = (Style *) (*ws->styles.begin())->ref(); for (int i = 0; i < WIN_STATE_LAST; i++) { if (styles[i]) default_styles[i] = (Style *) styles[i]->ref(); } sb = &style_buffers[WIN_STATE_PASSIVE]; style = (Style *) styles[WIN_STATE_PASSIVE]->ref(); } void DWindowObject::updateSubwindows(void) { list::iterator subinfo_it; map::iterator sub_it; if (type == SubwindowType) if (((SubWindowObject *) this)->subwin_level > MAX_SUBWIN_LEVEL) return; if (sb->style->subs) { subinfo_it = sb->style->subs->begin(); for (; subinfo_it != sb->style->subs->end(); subinfo_it++) { if ((subs.find((*subinfo_it)->ident) == subs.end())) { SubWindowObject *sw; bool ancestor_failure = false; DWindowObject *ancestor = this; while (ancestor->type == SubwindowType) { if (((SubWindowObject *) ancestor)->sub_info->ident == (*subinfo_it)->ident) { ancestor_failure = true; ws->showWarningMessage( __FUNCTION__, "could not create sub-window, an " "ancestor had the same sub-window ID."); break; } ancestor = ((SubWindowObject *) ancestor)->parent; } if (! ancestor_failure) { if (type == WindowFrameType) sw = new FrameSubWindowObject(this, *subinfo_it); else sw = new SubWindowObject(this, *subinfo_it); subs.insert(make_pair((*subinfo_it)->ident, sw)); sw->commonStyleUpdate(); if (sw->decor_root->type == WindowFrameType) { EventDetail ed; ed.x = ed.y = INT_MAX; ed.x11mod = ed.wamod = 0; ed.type = WindowStateChangeNotify; ws->waimea->eh->evAct(NULL, sw->id, &ed); } } } } } sub_it = subs.begin(); for (; sub_it != subs.end(); sub_it++) { SubWindowObject *sw = (*sub_it).second; bool shown = false; if (sb->style->subs) { subinfo_it = sb->style->subs->begin(); for (; subinfo_it != sb->style->subs->end(); subinfo_it++) { if ((*sub_it).first == (*subinfo_it)->ident) { sw->hidden = false; shown = true; MAPUNREFSECOND(sw->dynamic_groups); map::iterator dit = dynamic_groups.begin(); for (; dit != dynamic_groups.end(); dit++) { sw->dynamic_groups.insert( make_pair((*dit).first, (RenderGroup *) ((*dit).second)->ref())); } sw->showSubwindow(); break; } } } if ((! shown) && (! sw->hidden)) { sw->hidden = true; sw->hideSubwindow(); } } if (type == WindowFrameType && sb->style->subs) { XLowerWindow(ws->display, ((WaFrameWindow *) this)->wa->id); } } void DWindowObject::destroySubwindows(void) { while (! subs.empty()) { ((*subs.begin()).second)->unref(); subs.erase(subs.begin()); } } void DWindowObject::initTextOpTable(void) { if (type == WindowFrameType) return; if (sb->text_table) MAPPTRCLEAR(sb->text_table); sb->text_table = NULL; if (sb->style->textops) { list::iterator tit = sb->style->textops->begin(); for (; tit != sb->style->textops->end(); tit++) { if (! (*tit)->is_static) { if (! sb->text_table) sb->text_table = new map; sb->text_table->insert( make_pair(*tit, WA_STRDUP(""))); } } } } void DWindowObject::setDynamicGroup(int type, RenderGroup *group) { map::iterator dit = dynamic_groups.find(type); if (dit != dynamic_groups.end()) { (*dit).second->unref(); dynamic_groups.erase(dit); } if (group) dynamic_groups.insert(make_pair(type, (RenderGroup *) group->ref())); map::iterator it = subs.begin(); for (; it != subs.end(); it++) ((*it).second)->setDynamicGroup(type, group); } void DWindowObject::commonStyleUpdate(void) { int current_window_state = STATE_FROM_MASK_AND_LIST(window_state_mask, styles); if (style) style->unref(); style = (Style *) styles[current_window_state]->ref(); if (sb->style != style || (sb->style && sb->style->serial != sb->serial)) { sb = &style_buffers[current_window_state]; force_setbg = true; if (sb->style == style) { force_alpha = true; if (! sb->surface) force_texture = true; if (sb->serial != style->serial) { force_texture = true; if (sb->text_table) { MAPPTRCLEAR(sb->text_table); sb->text_table = NULL; } MAPUNREFSECOND(sb->cache_table); initTextOpTable(); } } else { if (sb->style) sb->style->unref(); sb->style = (Style *) style->ref(); if (sb->surface) sb->surface->unref(); sb->surface = NULL; MAPUNREFSECOND(sb->dynamic_groups); sb->bg = None; sb->width = sb->height = 0; if (sb->text_table) MAPPTRCLEAR(sb->text_table); sb->text_table = NULL; sb->x = INT_MAX; sb->y = INT_MAX; force_texture = true; MAPUNREFSECOND(sb->cache_table); initTextOpTable(); } if (sb->style->cursor) XDefineCursor(ws->display, id, sb->style->cursor); updateSubwindows(); sb->serial = sb->style->serial; } } void DWindowObject::styleUpdate(bool, bool) { pushRenderEvent(); } void DWindowObject::renderWindow(cairo_t *cr, bool from_bgparent) { int x, y; unsigned int w, h; bool render_texture = false; bool render_alpha = false; bool update_shape = false; Pixmap pixmap = (Pixmap) 0; Pixmap bitmap = (Pixmap) 0; DWIN_RENDER_SAFE_LOCK(this); if (force_texture) { render_texture = true; force_texture = false; force_alpha = false; } else if (force_alpha) { render_alpha = true; force_alpha = false; } startRender(); currentPositionAndSize(&x, &y, &w, &h); bool pos_change, size_change; if (x != sb->x || y != sb->y) pos_change = true; else pos_change = false; if (w != sb->width || h != sb->height) size_change = true; else size_change = false; if (size_change) render_texture = true; else if (pos_change) render_alpha = true; sb->x = x; sb->y = y; sb->width = w; sb->height = h; evalWhatToRender(pos_change, size_change, &render_texture, &render_alpha, &update_shape); commonEvalWhatToRender(pos_change, size_change, &render_texture, &render_alpha, &update_shape); if (type == WindowFrameType) { render_texture = false; render_alpha = false; update_shape = false; } if (render_texture) { render_alpha = true; update_shape = true; } bool alpha = (sb->style->translucent && type != RootType); bool shape = false; #ifdef SHAPE shape = (sb->style->shaped && type != RootType); #endif // SHAPE /* ARGB visual */ if (ws->screen_depth == 32) { if (alpha) { int p_x, p_y; DWindowObject *bgparent; WaSurface *bgsurface = getBgInfo (&bgparent, &p_x, &p_y); if (bgsurface && bgsurface != ws->bg_surface) { if (ws->waimea->client_side_rendering) { if (!bgsurface->data) alpha = false; } else { if (bgsurface->pixmap == None) alpha = false; } } else alpha = false; } #ifdef SHAPE shape = false; #endif // SHAPE } if (render_texture || (alpha && render_alpha)) { Pixmap root_pixmap = None; unsigned char *root_data = NULL; cairo_surface_t *root_surface = NULL; if (alpha || shape) { int p_x, p_y; DWindowObject *bgparent; WaSurface *bgsurface = getBgInfo(&bgparent, &p_x, &p_y); if (! from_bgparent) { DWIN_RENDER_SAFE_LOCK(bgparent); } if (ws->waimea->client_side_rendering) { root_data = ws->getRootBgImage( (bgsurface)? bgsurface->data: NULL, (bgsurface)? bgsurface->width: 0, (bgsurface)? bgsurface->height: 0, p_x, p_y, w, h); root_surface = cairo_image_surface_create_for_data(root_data, CAIRO_FORMAT_ARGB32, w, h, w * sizeof(WaPixel)); } else { root_pixmap = ws->getRootBgPixmap( (bgsurface)? bgsurface->pixmap: None, (bgsurface)? bgsurface->width: 0, (bgsurface)? bgsurface->height: 0, p_x, p_y, w, h); root_surface = cairo_xlib_surface_create(ws->display, root_pixmap, ws->visual, (ws->screen_depth == 32)? CAIRO_FORMAT_ARGB32: CAIRO_FORMAT_RGB24, ws->colormap); } if (! from_bgparent) { DWIN_RENDER_SAFE_RELEASE(bgparent); } } CacheSurface *return_surface; sb->style->parent_surface = root_surface; sb->style->return_surface = &return_surface; sb->style->render(this, cr, NULL, w, h); sb->style->return_surface = NULL; sb->style->parent_surface = NULL; if (alpha || shape) { cairo_destroy(cr); cr = cairo_create(root_surface); cairo_set_operator(cr, RENDER_OPERATOR_DEFAULT); if (sb->style->xrop_set) cairo_set_operator(cr, sb->style->xrop); cairo_identity_matrix(cr); cairo_set_source_surface(cr, return_surface->crsurface, 0., 0.); cairo_rectangle(cr, 0., 0., w, h); cairo_clip(cr); cairo_paint_with_alpha(cr, sb->style->opacity); cairo_reset_clip(cr); } if (shape) { cairo_surface_t *alpha_surface; unsigned char *shape_data; if (ws->waimea->client_side_rendering) { shape_data = new unsigned char[w * h * sizeof(WaPixel)]; memset (shape_data, 0, w * h * sizeof(WaPixel)); alpha_surface = cairo_image_surface_create_for_data(shape_data, CAIRO_FORMAT_ARGB32, w, h, w * sizeof(WaPixel)); } else { GC gc; XGCValues gcv; bitmap = XCreatePixmap(ws->display, ws->id, w, h, 1); gcv.foreground = 0x00000000; gc = XCreateGC(ws->display, bitmap, GCForeground, &gcv); XFillRectangle(ws->display, bitmap, gc, 0, 0, w, h); XFreeGC(ws->display, gc); alpha_surface = cairo_xlib_surface_create(ws->display, bitmap, NULL, CAIRO_FORMAT_A1, ws->colormap); } cairo_destroy(cr); cr = cairo_create(alpha_surface); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_surface(cr, return_surface->crsurface, 0., 0.); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_rectangle(cr, 0, 0, w, h); cairo_clip(cr); cairo_paint_with_alpha(cr, sb->style->opacity); cairo_reset_clip(cr); if (sb->style->shapemask) { cairo_set_operator(cr, CAIRO_OPERATOR_OVER); sb->style->shapemask->render(this, cr, alpha_surface, w, h); } else { cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_set_source_surface(cr, return_surface->crsurface, 0., 0.); cairo_rectangle(cr, 0.0, 0.0, w, h); cairo_clip(cr); cairo_paint_with_alpha(cr, sb->style->opacity); cairo_reset_clip(cr); } if (ws->waimea->client_side_rendering) { /* XXX: can this be done with CAIRO_FORMAT_A1 image data instead? */ unsigned int *src = (unsigned int *) shape_data; unsigned int _x, _y, bit = 0x01; unsigned char *shape_map = new unsigned char[(w + 7) / 8 * h]; unsigned char *dst = shape_map; unsigned char value = 0; unsigned char src_alpha; for (_y = 0; _y < h; _y++) { for (_x = 0; _x < w; _x++) { src_alpha = *src >> 24; if (src_alpha >= 127) value |= bit; if (bit == 0x80) { *dst++ = value; value = 0; bit = 0x01; } else bit <<= 1; src++; } if (bit != 0x01) *dst++ = value; value = 0; bit = 0x01; } bitmap = XCreateBitmapFromData(ws->display, ws->id, (char *) shape_map, w, h); delete [] shape_data; delete [] shape_map; } cairo_surface_destroy(alpha_surface); } CacheSurface *surface; if (root_surface) { return_surface->unref(); surface = new CacheSurface(ws->display, root_surface, root_pixmap, root_data, w, h, &sb->dynamic_groups); surface->bitmap = bitmap; } else surface = return_surface; if (ws->waimea->client_side_rendering) { Visual *visual; int depth; if (type == RootType) { XWindowAttributes attr; XGetWindowAttributes (ws->display, ws->id, &attr); visual = attr.visual; depth = attr.depth; } else { visual = ws->visual; depth = ws->screen_depth; } pixmap = XCreatePixmap(ws->display, ws->id, surface->width, surface->height, depth); XImage *xim = XCreateImage(ws->display, visual, depth, ZPixmap, 0, (char *) surface->data, w, h, 32, 0); GC gc = XCreateGC(ws->display, pixmap, 0, NULL); XPutImage(ws->display, pixmap, gc, xim, 0, 0, 0, 0, w, h); xim->data = NULL; XDestroyImage(xim); XFreeGC(ws->display, gc); surface->pixmap = pixmap; } if (sb->surface) sb->surface->unref(); sb->surface = surface; pixmap = sb->surface->pixmap; } else if (force_setbg && sb->surface) { pixmap = sb->surface->pixmap; update_shape = true; } #ifdef SHAPE if (shape && update_shape) { if (sb->surface) bitmap = sb->surface->bitmap; if (bitmap) setShape(bitmap); } else if (update_shape) unsetShape(); #endif // SHAPE if (pixmap) { force_setbg = false; XSetWindowBackgroundPixmap(ws->display, id, pixmap); XClearWindow(ws->display, id); } map::iterator it = subs.begin(); for (; it != subs.end(); it++) { if (! ((*it).second)->hidden) { DWindowObject *dwin = (*it).second; RENDER_LIST_LOCK; list::iterator it = __render_list.begin(); while (it != __render_list.end()) { if (*it == dwin) it = __render_list.erase(it); else it++; } RENDER_LIST_RELEASE; dwin->renderWindow(cr, (type == WindowFrameType)? false: true); } } if (mapRequest) { if (type != RootType) XMapWindow (ws->display, id); mapRequest = false; } DWIN_RENDER_SAFE_RELEASE(this); endRender(pixmap); } void DWindowObject::commonEvalWhatToRender(bool, bool, bool *render_texture, bool *, bool *) { if (sb->style->has_dynamic_op) { map::iterator sbdit; map::iterator dit = dynamic_groups.begin(); for (; dit != dynamic_groups.end(); dit++) { sbdit = sb->dynamic_groups.find((*dit).first); if (sbdit == sb->dynamic_groups.end() || (*sbdit).second != (*dit).second) { if (sbdit != sb->dynamic_groups.end()) { ((*sbdit).second)->unref(); sb->dynamic_groups.erase(sbdit); } sb->dynamic_groups.insert( make_pair((*dit).first, (RenderGroup *) ((*dit).second)->ref())); *render_texture = true; } } sbdit = sb->dynamic_groups.begin(); for (; sbdit != sb->dynamic_groups.end(); sbdit++) { dit = dynamic_groups.find((*sbdit).first); if (dit == dynamic_groups.end()) { ((*sbdit).second)->unref(); sb->dynamic_groups.erase(sbdit); *render_texture = true; } } } if (sb->serial != sb->style->serial) { *render_texture = true; initTextOpTable(); } if (sb->text_table) { WaWindow *ww = getWindow(); MenuItem *mi = getMenuItem(); map::iterator tit = sb->text_table->begin(); for (; tit != sb->text_table->end(); tit++) { char *newstr = expand(((*tit).first)->utf8, ww, mi); if (strcmp((*tit).second, newstr)) { *render_texture = true; delete [] (*tit).second; (*tit).second = newstr; } else delete [] newstr; } } } #ifdef SHAPE void DWindowObject::commonSetShape(Pixmap bitmap) { XShapeCombineMask(ws->display, id, ShapeBounding, 0, 0, bitmap, ShapeSet); } void DWindowObject::commonUnsetShape(void) { XShapeCombineMask(ws->display, id, ShapeBounding, 0, 0, None, ShapeSet); } void DWindowObject::setShape(Pixmap bitmap) { commonSetShape(bitmap); } void DWindowObject::unsetShape(void) { commonUnsetShape(); } #endif // SHAPE void DWindowObject::pushRenderEvent(void) { if (type == RootType && ws->config.external_bg) return; if (hidden) return; RENDER_LIST_LOCK; __render_list.push_back(this); RENDER_LIST_SIGNAL; } SubWindowObject::SubWindowObject(DWindowObject *_parent, SubwinInfo *sinfo) : DWindowObject(NULL, (Window) 0, SubwindowType, NULL, NULL) { parent = _parent; ws = parent->ws; sub_info = sinfo; if (parent->type == SubwindowType) subwin_level = ((SubWindowObject *) parent)->subwin_level + 1; else subwin_level = 1; decor_root = parent->decor_root; char *name = ws->getSubwindowName(sinfo->ident); if (window_name) delete [] window_name; if (parent->window_name) { window_name = new char[strlen(parent->window_name) + strlen(name) + 2]; sprintf(window_name, "%s.%s", parent->window_name, name); } else window_name = WA_STRDUP(name); XSetWindowAttributes attrib_set; int create_mask = CWOverrideRedirect | CWEventMask; attrib_set.override_redirect = true; attrib_set.event_mask = ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask; id = XCreateWindow(ws->display, parent->id, 0, 0, 1, 1, 0, CopyFromParent, CopyFromParent, CopyFromParent, create_mask, &attrib_set); ws->waimea->window_table.insert(make_pair(id, this)); if (parent->window_state_mask & WIN_STATE_ACTIVE_MASK) window_state_mask = WIN_STATE_ACTIVE_MASK; else window_state_mask = 0L; if (sinfo->raised && (! (parent->type == RootType))) XRaiseWindow(ws->display, id); else XLowerWindow(ws->display, id); resetActionList(parent->ids->ref()); resetStyle(); } SubWindowObject::~SubWindowObject(void) { ws->waimea->window_table.erase(id); destroySubwindows(); XDestroyWindow(ws->display, id); } void SubWindowObject::showSubwindow(void) { XMapWindow(ws->display, id); } void SubWindowObject::hideSubwindow(void) { XUnmapWindow(ws->display, id); } void SubWindowObject::currentPositionAndSize(int *x, int *y, unsigned int *w, unsigned int *h) { double nx, ny, nw, nh; int ox, oy; unsigned int ow, oh, ud; Window dw; style->calcPositionAndSize(parent->sb->width, parent->sb->height, ws->hdpi, ws->vdpi, &nx, &ny, &nw, &nh); *x = WA_ROUND(nx); *y = WA_ROUND(ny); *w = WA_ROUND_U(nw); *h = WA_ROUND_U(nh); if (*w == 0) *w = 1; if (*h == 0) *h = 1; XGetGeometry(ws->display, id, &dw, &ox, &oy, &ow, &oh, &ud, &ud); if (ow != *w || oh != *h) { XMoveResizeWindow(ws->display, id, *x, *y, *w,* h); } else if (ox != *x || oy != *y) { XMoveWindow(ws->display, id, *x, *y); } } void SubWindowObject::evalWhatToRender(bool, bool size_change, bool *render_texture, bool *render_alpha, bool *update_shape) { Window dw; int x, y; XTranslateCoordinates(ws->display, id, ws->id, 0, 0, &x, &y, &dw); if ((! size_change) && (x > (int) ws->width || y > (int) ws->height || x + (int) sb->width < 0 || y + (int) sb->height < 0)) { *render_texture = false; *render_alpha = false; *update_shape = false; return; } Pixmap newbg = (parent->sb->surface)? parent->sb->surface->pixmap: None; if (sb->bg != newbg) { *render_alpha = true; sb->bg = newbg; } } WaSurface *SubWindowObject::getBgInfo(DWindowObject **dwo, int *x, int *y) { *x = sb->x; *y = sb->y; *dwo = parent; return parent->sb->surface; } FrameSubWindowObject::FrameSubWindowObject(DWindowObject *_parent, SubwinInfo *sinfo) : SubWindowObject(_parent, sinfo) { last_x = last_y = current_x = current_y = 0; frame = (WaFrameWindow *) parent; #ifdef SHAPE shapeinfo = new ShapeInfo(id); #endif // SHAPE } FrameSubWindowObject::~FrameSubWindowObject(void) { #ifdef SHAPE if (shapeinfo->in_list) frame->removeShapeInfo(shapeinfo); delete shapeinfo; #endif // SHAPE } void FrameSubWindowObject::showSubwindow(void) { #ifdef SHAPE frame->addShapeInfo(shapeinfo); shapeinfo->in_list = true; #endif // SHAPE XMapWindow(ws->display, id); } void FrameSubWindowObject::hideSubwindow(void) { #ifdef SHAPE if (shapeinfo->in_list) { frame->removeShapeInfo(shapeinfo); shapeinfo->in_list = false; } #endif // SHAPE XUnmapWindow(ws->display, id); } void FrameSubWindowObject::currentPositionAndSize(int *x, int *y, unsigned int *w, unsigned int *h) { double nx, ny, nw, nh; int ox, oy; unsigned int ow, oh, ud; Window dw; style->calcPositionAndSize(parent->sb->width, parent->sb->height, ws->hdpi, ws->vdpi, &nx, &ny, &nw, &nh); current_x = WA_ROUND(nx); current_y = WA_ROUND(ny); *w = WA_ROUND_U(nw); *h = WA_ROUND_U(nh); if (*w == 0) *w = 1; if (*h == 0) *h = 1; XGetGeometry(ws->display, id, &dw, &ox, &oy, &ow, &oh, &ud, &ud); if (ow != *w || oh != *h) { XMoveResizeWindow(ws->display, id, current_x, current_y, *w, *h); } else if (ox != current_x || oy != current_y) { XMoveWindow(ws->display, id, current_x, current_y); } XTranslateCoordinates(ws->display, id, ws->id, 0, 0, x, y, &dw); } void FrameSubWindowObject::evalWhatToRender(bool, bool size_change, bool *render_texture, bool *render_alpha, bool *update_shape) { Window dw; int x, y; XTranslateCoordinates(ws->display, id, ws->id, 0, 0, &x, &y, &dw); if ((! size_change) && (x > (int) ws->width || y > (int) ws->height || x + (int) sb->width < 0 || y + (int) sb->height < 0)) { *render_texture = false; *render_alpha = false; *update_shape = false; return; } if (current_x != last_x || current_y != last_y) { *update_shape = true; } Pixmap newbg = (ws->bg_surface)? ws->bg_surface->pixmap: None; if (sb->bg != newbg) { *render_alpha = true; sb->bg = newbg; } } WaSurface *FrameSubWindowObject::getBgInfo(DWindowObject **dwo, int *x, int *y) { *x = sb->x; *y = sb->y; *dwo = ws; return ws->bg_surface; } #ifdef SHAPE void FrameSubWindowObject::setShape(Pixmap bitmap) { commonSetShape(bitmap); shapeinfo->setShapeOffset(current_x, current_y); frame->shapeUpdateNotify(); last_x = current_x; last_y = current_y; } void FrameSubWindowObject::unsetShape(void) { commonUnsetShape(); shapeinfo->setShapeOffset(current_x, current_y); frame->shapeUpdateNotify(); last_x = current_x; last_y = current_y; } #endif // SHAPE RootWindowObject::RootWindowObject(WaScreen *_ws, Window _id, int _type, WaStringMap *sm, char *_wname) : DWindowObject(_ws, _id, _type, sm, _wname) { #ifdef THREAD if (__render_thread_count) { pthread_mutex_init(&__win__render_mutex, NULL); pthread_cond_init(&__win__render_cond, NULL); __win__render_count = 0; __win__render_get_count = 0; } #endif // THREAD hidden = false; decor_root = this; resetStyle(); } RootWindowObject::~RootWindowObject(void) { DWIN_RENDER_GET(this); destroySubwindows(); #ifdef THREAD if (__render_thread_count) { pthread_mutex_destroy(&__win__render_mutex); pthread_cond_destroy(&__win__render_cond); } #endif // THREAD if (type != RootType) XDestroyWindow(ws->display, id); } void RootWindowObject::currentPositionAndSize(int *x, int *y, unsigned int *w, unsigned int *h) { Window dw; unsigned int ud; XGetGeometry(ws->display, id, &dw, x, y, w, h, &ud, &ud); XTranslateCoordinates(ws->display, id, ws->id, 0, 0, x, y, &dw); } void RootWindowObject::evalWhatToRender(bool, bool size_change, bool *render_texture, bool *render_alpha, bool *update_shape) { if ((! size_change) && (sb->x > (int) ws->width || sb->y > (int) ws->height || sb->x + (int) sb->width < 0 || sb->y + (int) sb->height < 0)) { *render_texture = false; *render_alpha = false; *update_shape = false; return; } Pixmap newbg = (ws->bg_surface)? ws->bg_surface->pixmap: None; if (sb->bg != newbg) { *render_alpha = true; sb->bg = newbg; } } WaSurface *RootWindowObject::getBgInfo(DWindowObject **dwo, int *x, int *y) { *x = sb->x; *y = sb->y; *dwo = ws; return ws->bg_surface; }