/* * Matchbox Window Manager II - A lightweight window manager not for the * desktop. * * Authored By Tomas Frydrych * * Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com * * This program 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. * * This program 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. * */ #include "mb-wm-theme.h" #include "mb-wm-theme-xml.h" #include #include #include #define SIMPLE_FRAME_TITLEBAR_HEIGHT 40 #define SIMPLE_FRAME_EDGE_SIZE 3 MBWMThemeCustomClientTypeFunc custom_client_type_func = NULL; void *custom_client_type_func_data = NULL; MBWMThemeCustomButtonTypeFunc custom_button_type_func = NULL; void *custom_button_type_func_data = NULL; MBWMThemeCustomThemeTypeFunc custom_theme_type_func = NULL; void *custom_theme_type_func_data = NULL; MBWMThemeCustomThemeAllocFunc custom_theme_alloc_func = NULL; static void xml_element_start_cb (void *data, const char *tag, const char **expat_attr); static void xml_element_end_cb (void *data, const char *tag); static void xml_stack_free (MBWMList *stack); static void mb_wm_theme_simple_paint_decor (MBWMTheme *theme, MBWMDecor *decor); static void mb_wm_theme_simple_paint_button (MBWMTheme *theme, MBWMDecorButton *button); static void mb_wm_theme_simple_get_decor_dimensions (MBWMTheme *, MBWindowManagerClient *, int *, int *, int *, int *); static void mb_wm_theme_simple_get_button_size (MBWMTheme *, MBWMDecor *, MBWMDecorButtonType, int *, int *); static void mb_wm_theme_simple_get_button_position (MBWMTheme *, MBWMDecor *, MBWMDecorButtonType, int*, int*); static MBWMDecor * mb_wm_theme_simple_create_decor (MBWMTheme *, MBWindowManagerClient *, MBWMDecorType); static void mb_wm_theme_class_init (MBWMObjectClass *klass) { MBWMThemeClass *t_class = MB_WM_THEME_CLASS (klass); t_class->paint_decor = mb_wm_theme_simple_paint_decor; t_class->paint_button = mb_wm_theme_simple_paint_button; t_class->decor_dimensions = mb_wm_theme_simple_get_decor_dimensions; t_class->button_size = mb_wm_theme_simple_get_button_size; t_class->button_position = mb_wm_theme_simple_get_button_position; t_class->create_decor = mb_wm_theme_simple_create_decor; #if MBWM_WANT_DEBUG klass->klass_name = "MBWMTheme"; #endif } static void mb_wm_theme_destroy (MBWMObject *obj) { MBWMTheme *theme = MB_WM_THEME (obj); if (theme->path) free (theme->path); MBWMList *l = theme->xml_clients; while (l) { MBWMXmlClient * c = l->data; MBWMList * n = l->next; mb_wm_xml_client_free (c); free (l); l = n; } } static int mb_wm_theme_init (MBWMObject *obj, va_list vap) { MBWMTheme *theme = MB_WM_THEME (obj); MBWindowManager *wm = NULL; MBWMObjectProp prop; MBWMList *xml_clients = NULL; char *path = NULL; MBWMColor *clr_lowlight = NULL; MBWMColor *clr_shadow = NULL; prop = va_arg(vap, MBWMObjectProp); while (prop) { switch (prop) { case MBWMObjectPropWm: wm = va_arg(vap, MBWindowManager *); break; case MBWMObjectPropThemePath: path = va_arg(vap, char *); break; case MBWMObjectPropThemeXmlClients: xml_clients = va_arg(vap, MBWMList *); break; case MBWMObjectPropThemeColorLowlight: clr_lowlight = va_arg(vap, MBWMColor *); break; case MBWMObjectPropThemeColorShadow: clr_shadow = va_arg(vap, MBWMColor *); break; case MBWMObjectPropThemeShadowType: theme->shadow_type = va_arg(vap, int); break; case MBWMObjectPropThemeCompositing: theme->compositing = va_arg(vap, int); break; case MBWMObjectPropThemeShaped: theme->shaped = va_arg(vap, int); break; default: MBWMO_PROP_EAT (vap, prop); } prop = va_arg(vap, MBWMObjectProp); } theme->wm = wm; theme->xml_clients = xml_clients; if (path) theme->path = strdup (path); if (clr_shadow && clr_shadow->set) { theme->color_shadow.r = clr_shadow->r; theme->color_shadow.g = clr_shadow->g; theme->color_shadow.b = clr_shadow->b; theme->color_shadow.a = clr_shadow->a; } else { theme->color_shadow.r = 0.0; theme->color_shadow.g = 0.0; theme->color_shadow.b = 0.0; theme->color_shadow.a = 0.95; } if (clr_lowlight && clr_lowlight->set) { theme->color_lowlight.r = clr_lowlight->r; theme->color_lowlight.g = clr_lowlight->g; theme->color_lowlight.b = clr_lowlight->b; theme->color_lowlight.a = clr_lowlight->a; } else { theme->color_lowlight.r = 0.0; theme->color_lowlight.g = 0.0; theme->color_lowlight.b = 0.0; theme->color_lowlight.a = 0.55; } return 1; } int mb_wm_theme_class_type () { static int type = 0; if (UNLIKELY(type == 0)) { static MBWMObjectClassInfo info = { sizeof (MBWMThemeClass), sizeof (MBWMTheme), mb_wm_theme_init, mb_wm_theme_destroy, mb_wm_theme_class_init }; type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); } return type; } Bool mb_wm_theme_is_button_press_activated (MBWMTheme *theme, MBWMDecor *decor, MBWMDecorButtonType type) { MBWindowManagerClient * client; MBWMXmlClient * c; MBWMXmlDecor * d; MBWMXmlButton * b; MBWMClientType c_type; if (!theme || !theme->xml_clients || !decor || !decor->parent_client) return False; client = decor->parent_client; c_type = MB_WM_CLIENT_CLIENT_TYPE (client); if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) && (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)) && (b = mb_wm_xml_button_find_by_type (d->buttons, type))) { return b->press_activated; } return False; } void mb_wm_theme_get_button_size (MBWMTheme *theme, MBWMDecor *decor, MBWMDecorButtonType type, int *width, int *height) { MBWMThemeClass *klass; MBWM_ASSERT (decor && decor->parent_client); if (!theme || !decor || !decor->parent_client) return; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->button_size) klass->button_size (theme, decor, type, width, height); } /* * If the parent decor uses absolute postioning, the returned values * are absolute. If the decor does packing, these values are added to * calculated button position. */ void mb_wm_theme_get_button_position (MBWMTheme *theme, MBWMDecor *decor, MBWMDecorButtonType type, int *x, int *y) { MBWMThemeClass *klass; MBWM_ASSERT (decor && decor->parent_client); if (!theme || !decor || !decor->parent_client) return; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->button_position) klass->button_position (theme, decor, type, x, y); else { if (x) *x = 2; if (y) *y = 2; } } void mb_wm_theme_get_decor_dimensions (MBWMTheme *theme, MBWindowManagerClient *client, int *north, int *south, int *west, int *east) { MBWMThemeClass *klass; MBWM_ASSERT (client); if (!theme || !client) return; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->decor_dimensions) klass->decor_dimensions (theme, client, north, south, west, east); } void mb_wm_theme_paint_decor (MBWMTheme *theme, MBWMDecor *decor) { MBWMThemeClass *klass; if (!theme) return; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->paint_decor) klass->paint_decor (theme, decor); } void mb_wm_theme_paint_button (MBWMTheme *theme, MBWMDecorButton *button) { MBWMThemeClass *klass; if (!theme) return; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->paint_button) klass->paint_button (theme, button); } Bool mb_wm_theme_supports (MBWMTheme *theme, MBWMThemeCaps capability) { if (theme) return False; return ((capability & theme->caps) != False); } typedef enum { XML_CTX_UNKNOWN = 0, XML_CTX_THEME, XML_CTX_CLIENT, XML_CTX_DECOR, XML_CTX_BUTTON, XML_CTX_IMG, } XmlCtx; struct stack_data { XmlCtx ctx; void *data; }; struct expat_data { XML_Parser par; int theme_type; int version; MBWMList *xml_clients; char *img; MBWMList *stack; MBWMColor color_lowlight; MBWMColor color_shadow; MBWMCompMgrShadowType shadow_type; Bool compositing; Bool shaped; }; MBWMTheme * mb_wm_theme_new (MBWindowManager * wm, const char * theme_path) { MBWMTheme *theme = NULL; int theme_type = 0; char *path = NULL; char buf[256]; XML_Parser par = NULL; FILE *file = NULL; MBWMList *xml_clients = NULL; char *img = NULL; MBWMColor clr_lowlight; MBWMColor clr_shadow; MBWMCompMgrShadowType shadow_type; Bool compositing; Bool shaped; struct stat st; /* * If no theme specified, we try to load the default one, if that fails, * we automatically fallback on the built-in defaults. */ if (!theme_path) theme_path = "Default"; /* Attempt to parse the xml theme, if any, retrieving the theme type * * NB: We cannot do this in the _init function, since we need to know the * type *before* we can create the underlying object on which the * init method operates. */ if (*theme_path == '/') { if (!stat (theme_path, &st)) path = (char *) theme_path; } else { const char *home = getenv("HOME"); int size; if (home) { const char *fmt = "%s/.themes/%s/matchbox2/theme.xml"; size = strlen (theme_path) + strlen (fmt) + strlen (home); path = alloca (size); snprintf (path, size, fmt, home, theme_path); if (stat (path, &st)) path = NULL; } if (!path) { const char * fmt = "%s/themes/%s/matchbox2/theme.xml"; size = strlen (theme_path) + strlen (fmt) + strlen (DATADIR); path = alloca (size); snprintf (path, size, fmt, DATADIR, theme_path); if (stat (path, &st)) path = NULL; } } if (path) { struct expat_data udata; if (!(file = fopen (path, "r")) || !(par = XML_ParserCreate(NULL))) { goto default_theme; } memset (&udata, 0, sizeof (struct expat_data)); udata.compositing = True; udata.par = par; XML_SetElementHandler (par, xml_element_start_cb, xml_element_end_cb); XML_SetUserData(par, (void *)&udata); while (fgets (buf, sizeof (buf), file) && XML_Parse(par, buf, strlen(buf), 0)); XML_Parse(par, NULL, 0, 1); if (udata.version == 2) { theme_type = udata.theme_type; xml_clients = udata.xml_clients; if (udata.img) { if (*udata.img == '/') img = udata.img; else { int len = strlen (path) + strlen (udata.img); char * s; char * p = malloc (len + 1); strncpy (p, path, len); s = strrchr (p, '/'); if (s) { *(s+1) = 0; strcat (p, udata.img); } else { strncpy (p, udata.img, len); } img = p; free (udata.img); } } } clr_lowlight.r = udata.color_lowlight.r; clr_lowlight.g = udata.color_lowlight.g; clr_lowlight.b = udata.color_lowlight.b; clr_lowlight.a = udata.color_lowlight.a; clr_lowlight.set = udata.color_lowlight.set; clr_shadow.r = udata.color_shadow.r; clr_shadow.g = udata.color_shadow.g; clr_shadow.b = udata.color_shadow.b; clr_shadow.a = udata.color_shadow.a; clr_shadow.set = udata.color_shadow.set; shadow_type = udata.shadow_type; compositing = udata.compositing; shaped = udata.shaped; xml_stack_free (udata.stack); } if (custom_theme_alloc_func) { theme = custom_theme_alloc_func (theme_type, MBWMObjectPropWm, wm, MBWMObjectPropThemePath, path, MBWMObjectPropThemeImg, img, MBWMObjectPropThemeXmlClients, xml_clients, MBWMObjectPropThemeColorLowlight, &clr_lowlight, MBWMObjectPropThemeColorShadow, &clr_shadow, MBWMObjectPropThemeShadowType, shadow_type, MBWMObjectPropThemeCompositing, compositing, MBWMObjectPropThemeShaped, shaped, NULL); } else if (theme_type) { theme = MB_WM_THEME (mb_wm_object_new (theme_type, MBWMObjectPropWm, wm, MBWMObjectPropThemePath, path, MBWMObjectPropThemeImg, img, MBWMObjectPropThemeXmlClients, xml_clients, MBWMObjectPropThemeColorLowlight, &clr_lowlight, MBWMObjectPropThemeColorShadow, &clr_shadow, MBWMObjectPropThemeShadowType, shadow_type, MBWMObjectPropThemeCompositing, compositing, MBWMObjectPropThemeShaped, shaped, NULL)); } default_theme: if (!theme) { theme = MB_WM_THEME (mb_wm_object_new ( MB_WM_TYPE_THEME, MBWMObjectPropWm, wm, MBWMObjectPropThemeXmlClients, xml_clients, MBWMObjectPropThemeColorLowlight, &clr_lowlight, MBWMObjectPropThemeColorShadow, &clr_shadow, MBWMObjectPropThemeShadowType, shadow_type, MBWMObjectPropThemeCompositing, compositing, MBWMObjectPropThemeShaped, shaped, NULL)); } if (par) XML_ParserFree (par); if (file) fclose (file); if (img) free (img); return theme; } MBWMDecor * mb_wm_theme_create_decor (MBWMTheme *theme, MBWindowManagerClient *client, MBWMDecorType type) { MBWMThemeClass *klass; MBWM_ASSERT (client); if (!theme || !client) return NULL; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->create_decor) return klass->create_decor (theme, client, type); return NULL; } void mb_wm_theme_resize_decor (MBWMTheme *theme, MBWMDecor *decor) { MBWMThemeClass *klass; MBWM_ASSERT (decor); if (!theme || !decor) return; klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme)); if (klass->resize_decor) klass->resize_decor (theme, decor); } MBWMClientLayoutHints mb_wm_theme_get_client_layout_hints (MBWMTheme * theme, MBWindowManagerClient * client) { MBWMXmlClient * c; MBWMClientType c_type; if (!client || !theme) return 0; c_type = MB_WM_CLIENT_CLIENT_TYPE (client); if (!theme->xml_clients || !(c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type))) { return 0; } return c->layout_hints; } /* * Returns True if the theme prescribes at least one value for the geometry */ Bool mb_wm_theme_get_client_geometry (MBWMTheme * theme, MBWindowManagerClient * client, MBGeometry * geom) { MBWMXmlClient * c; MBWMClientType c_type; if (!geom || !client || !theme) return False; c_type = MB_WM_CLIENT_CLIENT_TYPE (client); if (!theme || !theme->xml_clients || !(c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) || (c->x < 0 && c->y < 0 && c->width < 0 && c->height < 0)) { return False; } geom->x = c->x; geom->y = c->y; geom->width = c->width; geom->height = c->height; return True; } Bool mb_wm_theme_is_client_shaped (MBWMTheme * theme, MBWindowManagerClient * client) { #ifdef HAVE_XEXT MBWMXmlClient * c; MBWMClientType c_type; if (!client || !theme || !theme->shaped || client->is_argb32) return False; c_type = MB_WM_CLIENT_CLIENT_TYPE (client); if (theme->xml_clients && (c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type))) { return c->shaped; } return False; #else return False; #endif } /* * Retrieves color to be used for lowlighting (16-bit rgba) */ void mb_wm_theme_get_lowlight_color (MBWMTheme * theme, unsigned int * red, unsigned int * green, unsigned int * blue, unsigned int * alpha) { if (theme) { if (red) *red = (unsigned int)(theme->color_lowlight.r * (double)0xffff); if (green) *green = (unsigned int)(theme->color_lowlight.g * (double)0xffff); if (blue) *blue = (unsigned int)(theme->color_lowlight.b * (double)0xffff); if (alpha) *alpha = (unsigned int)(theme->color_lowlight.a * (double)0xffff); return; } if (red) *red = 0; if (green) *green = 0; if (blue) *blue = 0; if (*alpha) *alpha = 0x8d8d; } /* * Retrieves color to be used for lowlighting (16-bit rgba) */ void mb_wm_theme_get_shadow_color (MBWMTheme * theme, unsigned int * red, unsigned int * green, unsigned int * blue, unsigned int * alpha) { if (theme) { if (red) *red = (unsigned int)(theme->color_shadow.r * (double)0xffff); if (green) *green = (unsigned int)(theme->color_shadow.g * (double)0xffff); if (blue) *blue = (unsigned int)(theme->color_shadow.b * (double)0xffff); if (alpha) *alpha = (unsigned int)(theme->color_shadow.a * (double)0xffff); return; } if (red) *red = 0; if (green) *green = 0; if (blue) *blue = 0; if (*alpha) *alpha = 0xff00; } MBWMCompMgrShadowType mb_wm_theme_get_shadow_type (MBWMTheme * theme) { if (!theme) return MBWM_COMP_MGR_SHADOW_NONE; return theme->shadow_type; } Bool mb_wm_theme_use_compositing_mgr (MBWMTheme * theme) { if (!theme) return False; return theme->compositing; } /* * Expat callback stuff */ static void xml_stack_push (MBWMList ** stack, XmlCtx ctx) { struct stack_data * s = malloc (sizeof (struct stack_data)); s->ctx = ctx; s->data = NULL; *stack = mb_wm_util_list_prepend (*stack, s); } static XmlCtx xml_stack_top_ctx (MBWMList *stack) { struct stack_data * s = stack->data; return s->ctx; } static void * xml_stack_top_data (MBWMList *stack) { struct stack_data * s = stack->data; return s->data; } static void xml_stack_top_set_data (MBWMList *stack, void * data) { struct stack_data * s = stack->data; s->data = data; } static void xml_stack_pop (MBWMList ** stack) { MBWMList * top = *stack; struct stack_data * s = top->data; *stack = top->next; free (s); free (top); } static void xml_stack_free (MBWMList *stack) { MBWMList * l = stack; while (l) { MBWMList * n = l->next; free (l->data); free (l); l = n; } } static void xml_element_start_cb (void *data, const char *tag, const char **expat_attr) { struct expat_data * exd = data; MBWM_DBG ("tag <%s>\n", tag); if (!strcmp (tag, "theme")) { MBWMColor clr; const char ** p = expat_attr; xml_stack_push (&exd->stack, XML_CTX_THEME); while (*p) { if (!strcmp (*p, "engine-version")) exd->version = atoi (*(p+1)); else if (!strcmp (*p, "engine-type")) { if (!strcmp (*(p+1), "default")) exd->theme_type = MB_WM_TYPE_THEME; #if THEME_PNG else if (!strcmp (*(p+1), "png")) exd->theme_type = MB_WM_TYPE_THEME_PNG; #endif else if (custom_theme_type_func) exd->theme_type = custom_theme_type_func (*(p+1), custom_theme_type_func_data); } else if (!strcmp (*p, "shaped")) { if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1")) exd->shaped = 1; } else if (!strcmp (*p, "color-shadow")) { mb_wm_xml_clr_from_string (&clr, *(p+1)); if (clr.set) { exd->color_shadow.r = clr.r; exd->color_shadow.g = clr.g; exd->color_shadow.b = clr.b; exd->color_shadow.a = clr.a; exd->color_shadow.set = True; } } else if (!strcmp (*p, "color-lowlight")) { mb_wm_xml_clr_from_string (&clr, *(p+1)); if (clr.set) { exd->color_lowlight.r = clr.r; exd->color_lowlight.g = clr.g; exd->color_lowlight.b = clr.b; exd->color_lowlight.a = clr.a; exd->color_lowlight.set = True; } } else if (!strcmp (*p, "shadow-type")) { if (!strcmp (*(p+1), "simple")) exd->shadow_type = MBWM_COMP_MGR_SHADOW_SIMPLE; else if (!strcmp (*(p+1), "gaussian")) exd->shadow_type = MBWM_COMP_MGR_SHADOW_GAUSSIAN; } else if (!strcmp (*p, "compositing")) { if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1")) exd->compositing = True; else exd->compositing = False; } p += 2; } } if (!strcmp (tag, "client")) { MBWMXmlClient * c = mb_wm_xml_client_new (); const char **p = expat_attr; XmlCtx ctx = xml_stack_top_ctx (exd->stack); xml_stack_push (&exd->stack, XML_CTX_CLIENT); if (ctx != XML_CTX_THEME) { MBWM_DBG ("Expected context theme"); return; } while (*p) { if (!strcmp (*p, "type")) { if (!strcmp (*(p+1), "app")) c->type = MBWMClientTypeApp; else if (!strcmp (*(p+1), "dialog")) c->type = MBWMClientTypeDialog; else if (!strcmp (*(p+1), "panel")) c->type = MBWMClientTypePanel; else if (!strcmp (*(p+1), "input")) c->type = MBWMClientTypeInput; else if (!strcmp (*(p+1), "desktop")) c->type = MBWMClientTypeDesktop; else if (!strcmp (*(p+1), "notification")) c->type = MBWMClientTypeNote; else if (custom_client_type_func) c->type = custom_client_type_func (*(p+1), custom_client_type_func_data); } else if (!strcmp (*p, "shaped")) { if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1")) c->shaped = 1; } else if (!strcmp (*p, "width")) { c->width = atoi (*(p+1)); } else if (!strcmp (*p, "height")) { c->height = atoi (*(p+1)); } else if (!strcmp (*p, "x")) { c->x = atoi (*(p+1)); } else if (!strcmp (*p, "y")) { c->y = atoi (*(p+1)); } else if (!strcmp (*p, "layout-hints") && *(p+1)) { /* comma-separate list of hints */ char * duph = strdup (*(p+1)); char * comma; char * h = duph; while (h) { comma = strchr (h, ','); if (comma) *comma = 0; if (!strcmp (h, "reserve-edge-north")) { c->layout_hints |= LayoutPrefReserveEdgeNorth; } else if (!strcmp (h, "reserve-edge-south")) { c->layout_hints |= LayoutPrefReserveEdgeSouth; } else if (!strcmp (h, "reserve-edge-west")) { c->layout_hints |= LayoutPrefReserveEdgeWest; } else if (!strcmp (h, "reserve-edge-east")) { c->layout_hints |= LayoutPrefReserveEdgeEast; } if (!strcmp (h, "reserve-north")) { c->layout_hints |= LayoutPrefReserveNorth; } else if (!strcmp (h, "reserve-south")) { c->layout_hints |= LayoutPrefReserveSouth; } else if (!strcmp (h, "reserve-west")) { c->layout_hints |= LayoutPrefReserveWest; } else if (!strcmp (h, "reserve-east")) { c->layout_hints |= LayoutPrefReserveEast; } else if (!strcmp (h, "grow")) { c->layout_hints |= LayoutPrefGrowToFreeSpace; } else if (!strcmp (h, "free")) { c->layout_hints |= LayoutPrefPositionFree; } else if (!strcmp (h, "full-screen")) { c->layout_hints |= LayoutPrefFullscreen; } else if (!strcmp (h, "fixed-x")) { c->layout_hints |= LayoutPrefFixedX; } else if (!strcmp (h, "fixed-y")) { c->layout_hints |= LayoutPrefFixedY; } else if (!strcmp (h, "overlaps")) { c->layout_hints |= LayoutPrefOverlaps; } if (comma) h = comma + 1; else break; } free (duph); } p += 2; } if (!c->type) mb_wm_xml_client_free (c); else { exd->xml_clients = mb_wm_util_list_prepend (exd->xml_clients, c); xml_stack_top_set_data (exd->stack, c); } return; } if (!strcmp (tag, "decor")) { MBWMXmlDecor * d = mb_wm_xml_decor_new (); const char **p = expat_attr; XmlCtx ctx = xml_stack_top_ctx (exd->stack); MBWMXmlClient * c = xml_stack_top_data (exd->stack); xml_stack_push (&exd->stack, XML_CTX_DECOR); if (ctx != XML_CTX_CLIENT || !c) { MBWM_DBG ("Expected context client"); return; } while (*p) { if (!strcmp (*p, "color-fg")) mb_wm_xml_clr_from_string (&d->clr_fg, *(p+1)); else if (!strcmp (*p, "color-bg")) mb_wm_xml_clr_from_string (&d->clr_bg, *(p+1)); else if (!strcmp (*p, "type")) { if (!strcmp (*(p+1), "north")) d->type = MBWMDecorTypeNorth; else if (!strcmp (*(p+1), "south")) d->type = MBWMDecorTypeSouth; else if (!strcmp (*(p+1), "east")) d->type = MBWMDecorTypeEast; else if (!strcmp (*(p+1), "west")) d->type = MBWMDecorTypeWest; } else if (!strcmp (*p, "template-width")) { d->width = atoi (*(p+1)); } else if (!strcmp (*p, "template-height")) { d->height = atoi (*(p+1)); } else if (!strcmp (*p, "template-x")) { d->x = atoi (*(p+1)); } else if (!strcmp (*p, "template-y")) { d->y = atoi (*(p+1)); } else if (!strcmp (*p, "template-pad-offset")) { d->pad_offset = atoi (*(p+1)); } else if (!strcmp (*p, "template-pad-length")) { d->pad_length = atoi (*(p+1)); } else if (!strcmp (*p, "font-size")) { char * end_size = NULL; d->font_units = MBWMXmlFontUnitsPixels; d->font_size = strtol (*(p+1), &end_size, 0); if (end_size && *end_size) { if (*end_size == 'p') { switch (*(end_size+1)) { case 't': d->font_units = MBWMXmlFontUnitsPoints; break; case 'x': default: ; } } } } else if (!strcmp (*p, "font-family")) { d->font_family = strdup (*(p+1)); } else if (!strcmp (*p, "show-title")) { if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1")) d->show_title = 1; } p += 2; } if (!d->type) mb_wm_xml_decor_free (d); else { c->decors = mb_wm_util_list_prepend (c->decors, d); xml_stack_top_set_data (exd->stack, d); } return; } if (!strcmp (tag, "button")) { MBWMXmlButton * b = mb_wm_xml_button_new (); const char **p = expat_attr; XmlCtx ctx = xml_stack_top_ctx (exd->stack); MBWMXmlDecor * d = xml_stack_top_data (exd->stack); xml_stack_push (&exd->stack, XML_CTX_BUTTON); if (ctx != XML_CTX_DECOR || !d) { MBWM_DBG ("Expected context decor"); return; } while (*p) { if (!strcmp (*p, "color-fg")) mb_wm_xml_clr_from_string (&b->clr_fg, *(p+1)); else if (!strcmp (*p, "color-bg")) mb_wm_xml_clr_from_string (&b->clr_bg, *(p+1)); else if (!strcmp (*p, "type")) { if (!strcmp (*(p+1), "minimize")) b->type = MBWMDecorButtonMinimize; else if (!strcmp (*(p+1), "close")) b->type = MBWMDecorButtonClose; else if (!strcmp (*(p+1), "menu")) b->type = MBWMDecorButtonMenu; else if (!strcmp (*(p+1), "accept")) b->type = MBWMDecorButtonAccept; else if (!strcmp (*(p+1), "fullscreen")) b->type = MBWMDecorButtonFullscreen; else if (!strcmp (*(p+1), "help")) b->type = MBWMDecorButtonHelp; else if (custom_button_type_func) b->type = custom_button_type_func (*(p+1), custom_button_type_func_data); } else if (!strcmp (*p, "packing")) { if (!strcmp (*(p+1), "end")) b->packing = MBWMDecorButtonPackEnd; else if (!strcmp (*(p+1), "start")) b->packing = MBWMDecorButtonPackStart; } else if (!strcmp (*p, "template-x")) { b->x = atoi (*(p+1)); } else if (!strcmp (*p, "template-y")) { b->y = atoi (*(p+1)); } else if (!strcmp (*p, "width")) { b->width = atoi (*(p+1)); } else if (!strcmp (*p, "height")) { b->height = atoi (*(p+1)); } else if (!strcmp (*p, "template-active-x")) { b->active_x = atoi (*(p+1)); } else if (!strcmp (*p, "template-active-y")) { b->active_y = atoi (*(p+1)); } else if (!strcmp (*p, "template-inactive-x")) { b->inactive_x = atoi (*(p+1)); } else if (!strcmp (*p, "template-inactive-y")) { b->inactive_y = atoi (*(p+1)); } else if (!strcmp (*p, "press-activated")) { if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1")) b->press_activated = 1; } p += 2; } if (!b->type) { mb_wm_xml_button_free (b); return; } d->buttons = mb_wm_util_list_append (d->buttons, b); xml_stack_top_set_data (exd->stack, b); return; } if (!strcmp (tag, "img")) { const char **p = expat_attr; XmlCtx ctx = xml_stack_top_ctx (exd->stack); xml_stack_push (&exd->stack, XML_CTX_IMG); if (ctx != XML_CTX_THEME) { MBWM_DBG ("Expected context theme"); return; } while (*p) { if (!strcmp (*p, "src")) { exd->img = strdup (*(p+1)); return; } p += 2; } return; } } static void xml_element_end_cb (void *data, const char *tag) { struct expat_data * exd = data; XmlCtx ctx = xml_stack_top_ctx (exd->stack); MBWM_DBG ("tag \n", tag); if (!strcmp (tag, "theme")) { XML_StopParser (exd->par, 0); } else if (!strcmp (tag, "client")) { if (ctx == XML_CTX_CLIENT) { xml_stack_pop (&exd->stack); } else MBWM_DBG ("Expected client on the top of the stack!"); } else if (!strcmp (tag, "decor")) { if (ctx == XML_CTX_DECOR) { xml_stack_pop (&exd->stack); } else MBWM_DBG ("Expected decor on the top of the stack!"); } else if (!strcmp (tag, "button")) { if (ctx == XML_CTX_BUTTON) { xml_stack_pop (&exd->stack); } else MBWM_DBG ("Expected button on the top of the stack!"); } else if (!strcmp (tag, "img")) { if (ctx == XML_CTX_IMG) { xml_stack_pop (&exd->stack); } else MBWM_DBG ("Expected img on the top of the stack!"); } } static void construct_buttons (MBWMTheme * theme, MBWMDecor * decor, MBWMXmlDecor *d) { MBWindowManagerClient *client = decor->parent_client; MBWindowManager *wm = client->wmref; MBWMDecorButton *button; if (d) { MBWMList * l = d->buttons; while (l) { MBWMXmlButton * b = l->data; button = mb_wm_decor_button_stock_new (wm, b->type, b->packing, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); l = l->next; } return; } button = mb_wm_decor_button_stock_new (wm, MBWMDecorButtonClose, MBWMDecorButtonPackEnd, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); #if 0 /* * We probably do not want this in the default client, but for now * it is useful for testing purposes */ button = mb_wm_decor_button_stock_new (wm, MBWMDecorButtonFullscreen, MBWMDecorButtonPackEnd, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); button = mb_wm_decor_button_stock_new (wm, MBWMDecorButtonHelp, MBWMDecorButtonPackEnd, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); button = mb_wm_decor_button_stock_new (wm, MBWMDecorButtonAccept, MBWMDecorButtonPackEnd, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); button = mb_wm_decor_button_stock_new (wm, MBWMDecorButtonMinimize, MBWMDecorButtonPackEnd, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); button = mb_wm_decor_button_stock_new (wm, MBWMDecorButtonMenu, MBWMDecorButtonPackStart, decor, 0); mb_wm_decor_button_show (button); mb_wm_object_unref (MB_WM_OBJECT (button)); #endif } struct DecorData { Pixmap xpix; XftDraw *xftdraw; XftColor clr; XftFont *font; }; static void decordata_free (MBWMDecor * decor, void *data) { struct DecorData * dd = data; Display * xdpy = decor->parent_client->wmref->xdpy; XFreePixmap (xdpy, dd->xpix); XftDrawDestroy (dd->xftdraw); if (dd->font) XftFontClose (xdpy, dd->font); free (dd); } static MBWMDecor * mb_wm_theme_simple_create_decor (MBWMTheme *theme, MBWindowManagerClient *client, MBWMDecorType type) { MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client); MBWMDecor *decor = NULL; MBWindowManager *wm = client->wmref; MBWMXmlClient *c; if (MB_WM_THEME (theme)->xml_clients && (c = mb_wm_xml_client_find_by_type (MB_WM_THEME (theme)->xml_clients, c_type))) { MBWMXmlDecor *d; d = mb_wm_xml_decor_find_by_type (c->decors, type); if (d) { decor = mb_wm_decor_new (wm, type); mb_wm_decor_attach (decor, client); construct_buttons (theme, decor, d); } return decor; } switch (c_type) { case MBWMClientTypeApp: switch (type) { case MBWMDecorTypeNorth: decor = mb_wm_decor_new (wm, type); mb_wm_decor_attach (decor, client); construct_buttons (theme, decor, NULL); break; default: decor = mb_wm_decor_new (wm, type); mb_wm_decor_attach (decor, client); } break; case MBWMClientTypeDialog: decor = mb_wm_decor_new (wm, type); mb_wm_decor_attach (decor, client); break; case MBWMClientTypePanel: case MBWMClientTypeDesktop: case MBWMClientTypeInput: default: decor = mb_wm_decor_new (wm, type); mb_wm_decor_attach (decor, client); } return decor; } static void mb_wm_theme_simple_get_button_size (MBWMTheme *theme, MBWMDecor *decor, MBWMDecorButtonType type, int *width, int *height) { MBWindowManagerClient * client = decor->parent_client; MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client); MBWMXmlClient * c; MBWMXmlDecor * d; /* FIXME -- assumes button on the north decor only */ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) && (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type))) { MBWMXmlButton * b = mb_wm_xml_button_find_by_type (d->buttons, type); if (b) { if (width) *width = b->width; if (height) *height = b->height; return; } } /* * These are defaults when no theme description was loaded */ switch (c_type) { case MBWMClientTypeApp: case MBWMClientTypeDialog: case MBWMClientTypePanel: case MBWMClientTypeDesktop: case MBWMClientTypeInput: default: if (width) *width = SIMPLE_FRAME_TITLEBAR_HEIGHT-4; if (height) *height = SIMPLE_FRAME_TITLEBAR_HEIGHT-4; } } static void mb_wm_theme_simple_get_button_position (MBWMTheme *theme, MBWMDecor *decor, MBWMDecorButtonType type, int *x, int *y) { MBWindowManagerClient * client = decor->parent_client; MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client); MBWMXmlClient * c; MBWMXmlDecor * d; /* FIXME -- assumes button on the north decor only */ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) && (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type))) { MBWMXmlButton * b = mb_wm_xml_button_find_by_type (d->buttons, type); if (b) { if (x) if (b->x >= 0) *x = b->x; else *x = 2; if (y) if (b->y >= 0) *y = b->y; else *y = 2; return; } } if (x) *x = 2; if (y) *y = 2; } static void mb_wm_theme_simple_get_decor_dimensions (MBWMTheme *theme, MBWindowManagerClient *client, int *north, int *south, int *west, int *east) { MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client); MBWMXmlClient * c; MBWMXmlDecor * d; if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type))) { if (north) if ((d = mb_wm_xml_decor_find_by_type (c->decors,MBWMDecorTypeNorth))) *north = d->height; else *north = SIMPLE_FRAME_TITLEBAR_HEIGHT; if (south) if ((d = mb_wm_xml_decor_find_by_type (c->decors,MBWMDecorTypeSouth))) *south = d->height; else *south = SIMPLE_FRAME_EDGE_SIZE; if (west) if ((d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeWest))) *west = d->width; else *west = SIMPLE_FRAME_EDGE_SIZE; if (east) if ((d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeEast))) *east = d->width; else *east = SIMPLE_FRAME_EDGE_SIZE; return; } /* * These are defaults when no theme description was loaded */ switch (c_type) { case MBWMClientTypeDialog: case MBWMClientTypeApp: if (north) *north = SIMPLE_FRAME_TITLEBAR_HEIGHT; if (south) *south = SIMPLE_FRAME_EDGE_SIZE; if (west) *west = SIMPLE_FRAME_EDGE_SIZE; if (east) *east = SIMPLE_FRAME_EDGE_SIZE; break; case MBWMClientTypePanel: case MBWMClientTypeDesktop: case MBWMClientTypeInput: default: if (north) *north = 0; if (south) *south = 0; if (west) *west = 0; if (east) *east = 0; } } static unsigned long pixel_from_clr (Display * dpy, int screen, MBWMColor * clr) { XColor xcol; xcol.red = (int)(clr->r * (double)0xffff); xcol.green = (int)(clr->g * (double)0xffff); xcol.blue = (int)(clr->b * (double)0xffff); xcol.flags = DoRed|DoGreen|DoBlue; XAllocColor (dpy, DefaultColormap (dpy, screen), &xcol); return xcol.pixel; } static XftFont * xft_load_font (MBWMDecor * decor, MBWMXmlDecor *d) { char desc[512]; XftFont * font; Display * xdpy = decor->parent_client->wmref->xdpy; int xscreen = decor->parent_client->wmref->xscreen; int font_size; font_size = d && d->font_size ? d->font_size : SIMPLE_FRAME_TITLEBAR_HEIGHT / 2; if (!d || d->font_units == MBWMXmlFontUnitsPixels) { font_size = mb_wm_util_pixels_to_points (decor->parent_client->wmref, font_size); } snprintf (desc, sizeof (desc), "%s-%i", d && d->font_family ? d->font_family : "Sans", font_size); font = XftFontOpenName (xdpy, xscreen, desc); return font; } static void mb_wm_theme_simple_paint_decor (MBWMTheme *theme, MBWMDecor *decor) { MBWMDecorType type; const MBGeometry *geom; MBWindowManagerClient *client; Window xwin; MBWindowManager *wm = theme->wm; MBWMColor clr_bg; MBWMColor clr_fg; MBWMClientType c_type; MBWMXmlClient *c = NULL; MBWMXmlDecor *d = NULL; struct DecorData *dd; int x, y, w, h; GC gc; Display *xdpy = wm->xdpy; int xscreen = wm->xscreen; const char *title; clr_fg.r = 1.0; clr_fg.g = 1.0; clr_fg.b = 1.0; clr_bg.r = 0.5; clr_bg.g = 0.5; clr_bg.b = 0.5; client = mb_wm_decor_get_parent (decor); xwin = mb_wm_decor_get_x_window (decor); if (client == NULL || xwin == None) return; dd = mb_wm_decor_get_theme_data (decor); type = mb_wm_decor_get_type (decor); geom = mb_wm_decor_get_geometry (decor); c_type = MB_WM_CLIENT_CLIENT_TYPE (client); if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) && (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type))) { if (d->clr_fg.set) { clr_fg.r = d->clr_fg.r; clr_fg.g = d->clr_fg.g; clr_fg.b = d->clr_fg.b; } if (d->clr_bg.set) { clr_bg.r = d->clr_bg.r; clr_bg.g = d->clr_bg.g; clr_bg.b = d->clr_bg.b; } } if (!dd) { XRenderColor rclr; dd = malloc (sizeof (struct DecorData)); dd->xpix = XCreatePixmap(xdpy, xwin, decor->geom.width, decor->geom.height, DefaultDepth(xdpy, xscreen)); dd->xftdraw = XftDrawCreate (xdpy, dd->xpix, DefaultVisual (xdpy, xscreen), DefaultColormap (xdpy, xscreen)); rclr.red = (int)(clr_fg.r * (double)0xffff); rclr.green = (int)(clr_fg.g * (double)0xffff); rclr.blue = (int)(clr_fg.b * (double)0xffff); rclr.alpha = 0xffff; XftColorAllocValue (xdpy, DefaultVisual (xdpy, xscreen), DefaultColormap (xdpy, xscreen), &rclr, &dd->clr); dd->font = xft_load_font (decor, d); XSetWindowBackgroundPixmap(xdpy, xwin, dd->xpix); mb_wm_decor_set_theme_data (decor, dd, decordata_free); } gc = XCreateGC (xdpy, dd->xpix, 0, NULL); XSetLineAttributes (xdpy, gc, 1, LineSolid, CapProjecting, JoinMiter); XSetBackground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_bg)); XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_bg)); w = geom->width; h = geom->height; x = geom->x; y = geom->y; XFillRectangle (xdpy, dd->xpix, gc, 0, 0, w, h); if (d->show_title && (mb_wm_decor_get_type(decor) == MBWMDecorTypeNorth && (title = mb_wm_client_get_name (client)))) { XRectangle rec; int pack_start_x = mb_wm_decor_get_pack_start_x (decor); int pack_end_x = mb_wm_decor_get_pack_end_x (decor); int west_width = mb_wm_client_frame_west_width (client); int y = (decor->geom.height - (dd->font->ascent + dd->font->descent)) / 2 + dd->font->ascent; rec.x = 0; rec.y = 0; rec.width = pack_end_x - 2; rec.height = d ? d->height : SIMPLE_FRAME_TITLEBAR_HEIGHT; XftDrawSetClipRectangles (dd->xftdraw, 0, 0, &rec, 1); XftDrawStringUtf8(dd->xftdraw, &dd->clr, dd->font, west_width + pack_start_x + (h / 5), y, title, strlen (title)); } XFreeGC (xdpy, gc); XClearWindow (xdpy, xwin); } static void mb_wm_theme_simple_paint_button (MBWMTheme *theme, MBWMDecorButton *button) { MBWMDecor *decor; MBWindowManagerClient *client; Window xwin; MBWindowManager *wm = theme->wm; int x, y, w, h; MBWMColor clr_bg; MBWMColor clr_fg; MBWMClientType c_type; MBWMXmlClient *c = NULL; MBWMXmlDecor *d = NULL; MBWMXmlButton *b = NULL; struct DecorData * dd; GC gc; Display *xdpy = wm->xdpy; int xscreen = wm->xscreen; clr_fg.r = 1.0; clr_fg.g = 1.0; clr_fg.b = 1.0; clr_bg.r = 0.0; clr_bg.g = 0.0; clr_bg.b = 0.0; decor = button->decor; client = mb_wm_decor_get_parent (decor); xwin = decor->xwin; dd = mb_wm_decor_get_theme_data (decor); if (client == NULL || xwin == None || dd->xpix == None) return; c_type = MB_WM_CLIENT_CLIENT_TYPE (client); if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) && (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)) && (b = mb_wm_xml_button_find_by_type (d->buttons, button->type))) { clr_fg.r = b->clr_fg.r; clr_fg.g = b->clr_fg.g; clr_fg.b = b->clr_fg.b; clr_bg.r = b->clr_bg.r; clr_bg.g = b->clr_bg.g; clr_bg.b = b->clr_bg.b; } w = button->geom.width; h = button->geom.height; x = button->geom.x; y = button->geom.y; gc = XCreateGC (xdpy, dd->xpix, 0, NULL); XSetLineAttributes (xdpy, gc, 1, LineSolid, CapRound, JoinRound); if (button->state == MBWMDecorButtonStateInactive) { XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_bg)); } else { /* FIXME -- think of a better way of doing this */ MBWMColor clr; clr.r = clr_bg.r + 0.2; clr.g = clr_bg.g + 0.2; clr.b = clr_bg.b + 0.2; XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr)); } XFillRectangle (xdpy, dd->xpix, gc, x, y, w+1, h+1); XSetLineAttributes (xdpy, gc, 3, LineSolid, CapRound, JoinRound); XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_fg)); if (button->type == MBWMDecorButtonClose) { XDrawLine (xdpy, dd->xpix, gc, x + 3, y + 3, x + w - 3, y + h - 3); XDrawLine (xdpy, dd->xpix, gc, x + 3, y + h - 3, x + w - 3, y + 3); } else if (button->type == MBWMDecorButtonFullscreen) { XDrawLine (xdpy, dd->xpix, gc, x + 3, y + 3, x + 3, y + h - 3); XDrawLine (xdpy, dd->xpix, gc, x + 3, y + h - 3, x + w - 3, y + h - 3); XDrawLine (xdpy, dd->xpix, gc, x + w - 3, y + h - 3, x + w - 3, y + 3); XDrawLine (xdpy, dd->xpix, gc, x + w - 3, y + 3, x + 3, y + 3); } else if (button->type == MBWMDecorButtonMinimize) { XDrawLine (xdpy, dd->xpix, gc, x + 3, y + h - 5, x + w - 3, y + h - 5); } else if (button->type == MBWMDecorButtonHelp) { char desc[512]; XftFont *font; XRenderColor rclr; XftColor clr; XRectangle rec; snprintf (desc, sizeof (desc), "%s-%i:bold", d && d->font_family ? d->font_family : "Sans", h*3/4); font = XftFontOpenName (xdpy, xscreen, desc); rclr.red = (int)(clr_fg.r * (double)0xffff); rclr.green = (int)(clr_fg.g * (double)0xffff); rclr.blue = (int)(clr_fg.b * (double)0xffff); rclr.alpha = 0xffff; XftColorAllocValue (xdpy, DefaultVisual (xdpy, xscreen), DefaultColormap (xdpy, xscreen), &rclr, &clr); rec.x = x; rec.y = y; rec.width = w; rec.height = h; XftDrawSetClipRectangles (dd->xftdraw, 0, 0, &rec, 1); XftDrawStringUtf8 (dd->xftdraw, &clr, font, x + 4, y + (h - (font->ascent + font->descent))/2 + font->ascent, "?", 1); XftFontClose (xdpy, font); } else if (button->type == MBWMDecorButtonMenu) { XSetLineAttributes (xdpy, gc, 3, LineSolid, CapRound, JoinMiter); XDrawLine (xdpy, dd->xpix, gc, x + 3, y + 5, x + w/2, y + h - 5); XDrawLine (xdpy, dd->xpix, gc, x + w/2, y + h - 5, x + w - 3, y + 5); } else if (button->type == MBWMDecorButtonAccept) { XDrawArc (xdpy, dd->xpix, gc, x + 4, y + 4, w - 8, h - 8, 0, 64 * 360); } XFreeGC (xdpy, gc); XClearWindow (wm->xdpy, xwin); } /* * Installs a global handler that can be used to translate custom client type * names to their numerical values. * * NB: this is not an object function, since we need it before we allocate the * actual MBWMTheme object in the XML parser. */ void mb_wm_theme_set_custom_client_type_func (MBWMThemeCustomClientTypeFunc func, void *user_data) { custom_client_type_func = func; custom_client_type_func_data = user_data; } /* * Installs a global handler that can be used to translate custom theme names * to their numerical (MBWMObject) values. * * NB: this is not an object function, since we need it before we allocate the * actual MBWMTheme object in the XML parser. */ void mb_wm_theme_set_custom_theme_type_func (MBWMThemeCustomThemeTypeFunc func, void *user_data) { custom_theme_type_func = func; custom_theme_type_func_data = user_data; } /* * Installs a global handler that can be used to translate custom button names * to their numerical values. * * NB: this is not an object function, since we need it before we allocate the * actual MBWMTheme object in the XML parser. */ void mb_wm_theme_set_custom_button_type_func (MBWMThemeCustomButtonTypeFunc func, void *user_data) { custom_button_type_func = func; custom_button_type_func_data = user_data; } /* * Installs a global handler that can be used to allocate a custom * MBWMThemeSubclass. * * NB: this is not an object function, since we need it before we allocate the * actual MBWMTheme object in the XML parser. */ void mb_wm_theme_set_custom_theme_alloc_func (MBWMThemeCustomThemeAllocFunc func) { custom_theme_alloc_func = func; }