/* * Matchbox Window Manager II - A lightweight window manager not for the * desktop. * * Authored By Matthew Allum * * 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 "matchbox.h" #include "mb-wm-theme.h" static void mb_wm_decor_destroy (MBWMObject *obj); static void mb_wm_decor_button_sync_window (MBWMDecorButton *button); static void mb_wm_decor_class_init (MBWMObjectClass *klass) { #if MBWM_WANT_DEBUG klass->klass_name = "MBWMDecor"; #endif } static int mb_wm_decor_init (MBWMObject *obj, va_list vap) { MBWMDecor *decor = MB_WM_DECOR (obj); MBWMManager *wm = NULL; MBWMDecorType type = 0; MBWMObjectProp prop; int abs_packing = 0; prop = va_arg(vap, MBWMObjectProp); while (prop) { switch (prop) { case MBWMObjectPropWm: wm = va_arg(vap, MBWMManager *); break; case MBWMObjectPropDecorType: type = va_arg(vap, MBWMDecorType); break; case MBWMObjectPropDecorAbsolutePacking: abs_packing = va_arg(vap, int); default: MBWMO_PROP_EAT (vap, prop); } prop = va_arg(vap, MBWMObjectProp); } if (!wm) return 0; decor->type = type; decor->dirty = MBWMDecorDirtyFull; /* Needs painting */ decor->absolute_packing = abs_packing; return 1; } int mb_wm_decor_class_type () { static int type = 0; if (UNLIKELY(type == 0)) { static MBWMObjectClassInfo info = { sizeof (MBWMDecorClass), sizeof (MBWMDecor), mb_wm_decor_init, mb_wm_decor_destroy, mb_wm_decor_class_init }; type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); } return type; } static void mb_wm_decor_repaint (MBWMDecor *decor) { MBWMTheme *theme = decor->parent_client->wmref->theme; mb_wm_theme_paint_decor (theme, decor); } static void mb_wm_decor_resize (MBWMDecor *decor) { const MBGeometry *geom; MBWMTheme *theme = decor->parent_client->wmref->theme; GList *l; int btn_x_start, btn_x_end; int abs_packing = decor->absolute_packing; geom = mb_wm_decor_get_geometry (decor); btn_x_end = geom->width; btn_x_start = 0; l = decor->buttons; /* * Notify theme of resize */ mb_wm_theme_resize_decor (theme, decor); if (abs_packing) { int width = btn_x_end; width /= 2; while (l) { int off_x, off_y, bw, bh; MBWMDecorButton *btn = (MBWMDecorButton *)l->data; mb_wm_theme_get_button_position (theme, decor, btn->type, &off_x, &off_y); mb_wm_theme_get_button_size (theme, decor, btn->type, &bw, &bh); mb_wm_decor_button_move_to (btn, off_x, off_y); /* * We need to simulate packing when placing buttons at absolute * positions (e.g., in png-based theme) so that we know the size * of the area into which we can place the document title */ if (off_x + bw < width) { int x = off_x + bw; if (x > btn_x_start) btn_x_start = x + 2; } else { if (off_x < btn_x_end) btn_x_end = off_x - 2; } l = l->next; } } else { while (l) { int off_x, off_y; MBWMDecorButton *btn = (MBWMDecorButton *)l->data; mb_wm_theme_get_button_position (theme, decor, btn->type, &off_x, &off_y); if (btn->pack == MBWMDecorButtonPackEnd) { btn_x_end -= (btn->geom.width + off_x); mb_wm_decor_button_move_to (btn, btn_x_end, off_y); } else { mb_wm_decor_button_move_to (btn, btn_x_start + off_x, off_y); btn_x_start += btn->geom.width; } l = l->next; } } decor->pack_start_x = btn_x_start; decor->pack_end_x = btn_x_end; } typedef struct { MBWMDecor *decor; int orig_x, orig_y; int orig_p_x, orig_p_y; } DecorGrabClosure; static Bool mb_wm_decor_grab_handler (XEvent *xev, void *userdata) { DecorGrabClosure *closure = userdata; MBWMDecor *decor = closure->decor; MBWMManager *wm = decor->parent_client->wmref; switch (xev->type) { case MotionNotify: { XMotionEvent *pev = (XMotionEvent*)xev; MBGeometry geom; int diff_x = pev->x_root - closure->orig_p_x; int diff_y = pev->y_root - closure->orig_p_y; geom.x = closure->orig_x + diff_x; geom.y = closure->orig_y + diff_y; geom.width = decor->parent_client->frame_geometry.width; geom.height = decor->parent_client->frame_geometry.height; mb_wm_client_request_geometry (decor->parent_client, &geom, MBWMClientReqGeomIsViaUserAction); } break; case ButtonRelease: { XUngrabPointer (wm->xdpy, CurrentTime); mb_wm_manager_remove_event_handler (wm, ButtonRelease, decor->release_cb_id); decor->release_cb_id = 0; mb_wm_manager_remove_event_handler (wm, MotionNotify, decor->motion_cb_id); decor->motion_cb_id = 0; g_slice_free (DecorGrabClosure, closure); return False; } default: ; } return True; } static Bool mb_wm_decor_press_handler (XButtonEvent *xev, void *userdata) { MBWMDecor *decor = userdata; MBWMManager *wm = decor->parent_client->wmref; Bool retval = True; if (xev->window == decor->xwin) { if (XGrabPointer(wm->xdpy, xev->subwindow, False, ButtonPressMask|ButtonReleaseMask| PointerMotionMask|EnterWindowMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) == GrabSuccess) { DecorGrabClosure *closure = g_slice_new (DecorGrabClosure); MBGeometry geom; mb_wm_client_get_coverage (decor->parent_client, &geom); closure->decor = decor; closure->orig_x = geom.x; closure->orig_y = geom.y; closure->orig_p_x = xev->x_root; closure->orig_p_y = xev->y_root; decor->release_cb_id = mb_wm_manager_add_event_handler ( wm, decor->xwin, ButtonRelease, (MBWMXEventFunc)mb_wm_decor_grab_handler, closure); decor->motion_cb_id = mb_wm_manager_add_event_handler ( wm, decor->xwin, MotionNotify, (MBWMXEventFunc)mb_wm_decor_grab_handler, closure); } } return retval; } static Bool mb_wm_decor_reparent (MBWMDecor *decor); static Bool mb_wm_decor_sync_window (MBWMDecor *decor) { MBWMManager *wm; XSetWindowAttributes attr; if (decor->parent_client == NULL) return False; wm = decor->parent_client->wmref; if (decor->xwin == None) { attr.override_redirect = True; attr.background_pixel = BlackPixel(wm->xdpy, wm->xscreen); attr.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; mb_wm_util_trap_x_errors(); decor->xwin = XCreateWindow(wm->xdpy, wm->root_win->xwindow, decor->geom.x, decor->geom.y, decor->geom.width, decor->geom.height, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect|CWBackPixel|CWEventMask, &attr); MBWM_DBG("g is +%i+%i %ix%i", decor->geom.x, decor->geom.y, decor->geom.width, decor->geom.height); if (mb_wm_util_untrap_x_errors()) return False; mb_wm_decor_resize(decor); g_list_foreach(decor->buttons, (GFunc)mb_wm_decor_button_sync_window, NULL); /* * If this is a decor with buttons, then we install button press handler * so we can drag the window, if it is movable. */ if (decor->type == MBWMDecorTypeNorth && decor->parent_client->layout_hints & LayoutPrefMovable) { decor->press_cb_id = mb_wm_manager_add_event_handler (wm, decor->xwin, ButtonPress, (MBWMXEventFunc)mb_wm_decor_press_handler, decor); } return mb_wm_decor_reparent (decor); } else { /* Resize */ mb_wm_util_trap_x_errors(); XMoveResizeWindow(wm->xdpy, decor->xwin, decor->geom.x, decor->geom.y, decor->geom.width, decor->geom.height); /* Next up sort buttons */ g_list_foreach(decor->buttons, (GFunc)mb_wm_decor_button_sync_window, NULL); if (mb_wm_util_untrap_x_errors()) return False; } return True; } static Bool mb_wm_decor_reparent (MBWMDecor *decor) { MBWMManager *wm; if (decor->parent_client == NULL) return False; MBWM_MARK(); wm = decor->parent_client->wmref; /* FIXME: Check if we already have a parent here */ mb_wm_util_trap_x_errors(); XReparentWindow (wm->xdpy, decor->xwin, decor->parent_client->xwin_frame, decor->geom.x, decor->geom.y); if (mb_wm_util_untrap_x_errors()) return False; return True; } static void mb_wm_decor_calc_geometry (MBWMDecor *decor) { MBWMManager *wm; MBWindowManagerClient *client; int n, s, w, e; if (decor->parent_client == NULL) return; client = decor->parent_client; wm = client->wmref; mb_wm_theme_get_decor_dimensions (wm->theme, client, &n, &s, &w, &e); switch (decor->type) { case MBWMDecorTypeNorth: decor->geom.x = 0; decor->geom.y = 0; decor->geom.height = n; decor->geom.width = client->frame_geometry.width; break; case MBWMDecorTypeSouth: decor->geom.x = 0; decor->geom.y = client->window->geometry.height + n; decor->geom.height = s; decor->geom.width = client->frame_geometry.width; break; case MBWMDecorTypeWest: decor->geom.x = 0; decor->geom.y = n; decor->geom.height = client->window->geometry.height; decor->geom.width = w; break; case MBWMDecorTypeEast: decor->geom.x = client->window->geometry.width + w; decor->geom.y = n; decor->geom.height = client->window->geometry.height; decor->geom.width = e; break; default: /* FIXME: some kind of callback for custom types here ? */ break; } MBWM_DBG("geom is +%i+%i %ix%i, Type %i", decor->geom.x, decor->geom.y, decor->geom.width, decor->geom.height, decor->type); return; } void mb_wm_decor_handle_map (MBWMDecor *decor) { /* Not needed as XMapSubWindows() is used */ } void mb_wm_decor_handle_repaint (MBWMDecor *decor) { GList *l; if (decor->parent_client == NULL) return; if (decor->dirty) { mb_wm_decor_repaint(decor); l = decor->buttons; while (l) { MBWMDecorButton * button = l->data; mb_wm_decor_button_handle_repaint (button); l = l->next; } decor->dirty = MBWMDecorDirtyNot; } } void mb_wm_decor_handle_resize (MBWMDecor *decor) { if (decor->parent_client == NULL) return; mb_wm_decor_calc_geometry (decor); mb_wm_decor_sync_window (decor); /* Fire resize callback */ mb_wm_decor_resize(decor); /* Fire repaint callback */ mb_wm_decor_mark_dirty (decor); } MBWMDecor* mb_wm_decor_new (MBWMManager *wm, MBWMDecorType type) { MBWMObject *decor; decor = mb_wm_object_new (MB_WM_TYPE_DECOR, MBWMObjectPropWm, wm, MBWMObjectPropDecorType, type, NULL); return MB_WM_DECOR(decor); } Window mb_wm_decor_get_x_window (MBWMDecor *decor) { return decor->xwin; } MBWMDecorType mb_wm_decor_get_type (MBWMDecor *decor) { return decor->type; } MBWindowManagerClient* mb_wm_decor_get_parent (MBWMDecor *decor) { return decor->parent_client; } const MBGeometry* mb_wm_decor_get_geometry (MBWMDecor *decor) { return &decor->geom; } int mb_wm_decor_get_pack_start_x (MBWMDecor *decor) { return decor->pack_start_x; } int mb_wm_decor_get_pack_end_x (MBWMDecor *decor) { return decor->pack_end_x; } /* Mark a client in need of a repaint */ void mb_wm_decor_mark_dirty (MBWMDecor *decor) { decor->dirty |= MBWMDecorDirtyPaint; if (decor->parent_client) mb_wm_client_decor_mark_dirty (decor->parent_client); } void mb_wm_decor_mark_title_dirty (MBWMDecor *decor) { decor->dirty |= MBWMDecorDirtyTitle; if (decor->parent_client) mb_wm_client_decor_mark_dirty (decor->parent_client); } MBWMDecorDirtyState mb_wm_decor_get_dirty_state (MBWMDecor *decor) { return decor->dirty; } void mb_wm_decor_attach (MBWMDecor *decor, MBWindowManagerClient *client) { decor->parent_client = client; client->decor = g_list_append(client->decor, decor); mb_wm_decor_mark_dirty (decor); return; } void mb_wm_decor_detach (MBWMDecor *decor) { } static void mb_wm_decor_destroy (MBWMObject* obj) { MBWMDecor * decor = MB_WM_DECOR(obj); GList * l = decor->buttons; MBWMManager * wm = decor->parent_client->wmref; if (decor->themedata && decor->destroy_themedata) { decor->destroy_themedata (decor, decor->themedata); decor->themedata = NULL; decor->destroy_themedata = NULL; } mb_wm_decor_detach (decor); while (l) { GList * old = l; mb_wm_object_unref (MB_WM_OBJECT (l->data)); l = l->next; g_list_free_1 (old); } if (decor->press_cb_id) mb_wm_manager_remove_event_handler (wm, ButtonPress, decor->press_cb_id); if (decor->release_cb_id) mb_wm_manager_remove_event_handler (wm, ButtonRelease, decor->release_cb_id); if (decor->motion_cb_id) mb_wm_manager_remove_event_handler (wm, MotionNotify, decor->motion_cb_id); if (decor->enter_cb_id) mb_wm_manager_remove_event_handler (wm, EnterNotify, decor->enter_cb_id); if (decor->leave_cb_id) mb_wm_manager_remove_event_handler (wm, LeaveNotify, decor->leave_cb_id); } void mb_wm_decor_set_theme_data (MBWMDecor * decor, void *userdata, MBWMDecorDestroyUserData destroy) { if (decor->themedata && decor->destroy_themedata) decor->destroy_themedata (decor, decor->themedata); decor->themedata = userdata; decor->destroy_themedata = destroy; } void * mb_wm_decor_get_theme_data (MBWMDecor * decor) { return decor->themedata; } /* Buttons */ static void mb_wm_decor_button_destroy (MBWMObject* obj); static void mb_wm_decor_button_stock_button_action (MBWMDecorButton *button) { MBWindowManagerClient *client = button->decor->parent_client; MBWMManager *wm = client->wmref; switch (button->type) { case MBWMDecorButtonClose: mb_wm_client_deliver_delete (client); break; case MBWMDecorButtonMinimize: mb_wm_client_iconize (client); break; case MBWMDecorButtonFullscreen: mb_wm_client_set_state (client, MBWM_ATOM_NET_WM_STATE_FULLSCREEN, MBWMClientWindowStateChangeAdd); break; case MBWMDecorButtonAccept: mb_wm_client_deliver_wm_protocol (client, wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_ACCEPT]); break; case MBWMDecorButtonHelp: mb_wm_client_deliver_wm_protocol (client, wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_HELP]); break; case MBWMDecorButtonMenu: mb_wm_client_deliver_wm_protocol (client, wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_CUSTOM]); default: break; } return; } void mb_wm_decor_button_set_theme_data (MBWMDecorButton * button, void *themedata, MBWMDecorButtonDestroyUserData destroy) { if (button->themedata && button->destroy_themedata) button->destroy_themedata (button, button->themedata); button->themedata = themedata; button->destroy_themedata = destroy; } void * mb_wm_decor_button_get_theme_data (MBWMDecorButton * button) { return button->themedata; } static Bool button_grab_handler (XEvent *xev, void *userdata) { MBWMDecorButton *button = userdata; MBWMDecor *decor = button->decor; MBWMManager *wm = decor->parent_client->wmref; int xmin, ymin, xmax, ymax; xmin = button->geom.x; ymin = button->geom.y; xmax = button->geom.x + button->geom.width; ymax = button->geom.y + button->geom.height; switch (xev->type) { case MotionNotify: { XMotionEvent *pev = (XMotionEvent*)xev; if (pev->x < xmin || pev->x > xmax || pev->y < ymin || pev->y > ymax) { if (button->state == MBWMDecorButtonStatePressed) { button->state = MBWMDecorButtonStateInactive; mb_wm_theme_paint_button (wm->theme,button); } } else { if (button->state != MBWMDecorButtonStatePressed) { button->state = MBWMDecorButtonStatePressed; mb_wm_theme_paint_button (wm->theme,button); } } } break; case EnterNotify: if (button->state == MBWMDecorButtonStateInactive) { button->state = MBWMDecorButtonStatePressed; mb_wm_theme_paint_button (wm->theme, button); } break; case LeaveNotify: if (button->state != MBWMDecorButtonStateInactive) { button->state = MBWMDecorButtonStateInactive; mb_wm_theme_paint_button (wm->theme, button); } break; case ButtonRelease: { XButtonEvent *pev = (XButtonEvent*)xev; if (button->state != MBWMDecorButtonStateInactive) { button->state = MBWMDecorButtonStateInactive; mb_wm_theme_paint_button (wm->theme, button); } XUngrabPointer (wm->xdpy, CurrentTime); XSync (wm->xdpy, False); /* necessary */ if (pev->x < xmin || pev->x > xmax || pev->y < ymin || pev->y > ymax) return False; if (button->release) button->release(wm, button, button->userdata); else mb_wm_decor_button_stock_button_action (button); mb_wm_manager_remove_event_handler (wm, MotionNotify, decor->motion_cb_id); decor->motion_cb_id = 0; mb_wm_manager_remove_event_handler (wm, EnterNotify, decor->enter_cb_id); decor->enter_cb_id = 0; mb_wm_manager_remove_event_handler (wm, LeaveNotify, decor->leave_cb_id); decor->leave_cb_id = 0; mb_wm_manager_remove_event_handler (wm, ButtonRelease, decor->release_cb_id); decor->release_cb_id = 0; return False; } } return True; } static Bool mb_wm_decor_button_press_handler (XButtonEvent *xev, void *userdata) { MBWMDecorButton *button = (MBWMDecorButton *)userdata; MBWMDecor *decor = button->decor; MBWMManager *wm = decor->parent_client->wmref; GList *l = NULL; Bool retval = True; int xmin, ymin, xmax, ymax; if (xev->window != decor->xwin) return True; l = mb_wm_client_get_transients (decor->parent_client); /* Ignore events on the main window decor if transients other than * input methods are present */ while (l) { MBWindowManagerClient * c = l->data; if (MB_WM_CLIENT_CLIENT_TYPE (c) != MBWMClientTypeInput && mb_wm_client_is_modal (c)) { g_list_free (l); return True; } l = l->next; } g_list_free (l); xmin = button->geom.x; ymin = button->geom.y; xmax = button->geom.x + button->geom.width; ymax = button->geom.y + button->geom.height; if (xev->x < xmin || xev->x > xmax || xev->y < ymin || xev->y > ymax) return True; if (button->state != MBWMDecorButtonStatePressed) { button->state = MBWMDecorButtonStatePressed; mb_wm_theme_paint_button (wm->theme, button); } if (button->press_activated) { XUngrabPointer(wm->xdpy, CurrentTime); mb_wm_client_deliver_message (decor->parent_client, wm->atoms[MBWM_ATOM_MB_GRAB_TRANSFER], xev->time, xev->subwindow, xev->button, 0, 0); XSync (wm->xdpy, False); /* Necessary */ if (button->press) button->press(wm, button, button->userdata); else mb_wm_decor_button_stock_button_action (button); } else { XEvent ev; /* * First, call the custom function if any. */ if (button->press) button->press(wm, button, button->userdata); if (XGrabPointer(wm->xdpy, xev->subwindow, False, ButtonPressMask|ButtonReleaseMask| PointerMotionMask|EnterWindowMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) == GrabSuccess) { decor->motion_cb_id = mb_wm_manager_add_event_handler ( wm, decor->xwin, MotionNotify, (MBWMXEventFunc)button_grab_handler, button); decor->enter_cb_id = mb_wm_manager_add_event_handler ( wm, decor->xwin, EnterNotify, (MBWMXEventFunc)button_grab_handler, button); decor->leave_cb_id = mb_wm_manager_add_event_handler ( wm, decor->xwin, LeaveNotify, (MBWMXEventFunc)button_grab_handler, button); decor->release_cb_id = mb_wm_manager_add_event_handler ( wm, decor->xwin, ButtonRelease, (MBWMXEventFunc)button_grab_handler, button); if (button->state == MBWMDecorButtonStateInactive) { button->state = MBWMDecorButtonStatePressed; mb_wm_theme_paint_button (wm->theme, button); } } } return True; } static void mb_wm_decor_button_class_init (MBWMObjectClass *klass) { #if MBWM_WANT_DEBUG klass->klass_name = "MBWMDecorButton"; #endif } static int mb_wm_decor_button_init (MBWMObject *obj, va_list vap) { MBWMDecorButton *button = MB_WM_DECOR_BUTTON (obj); MBWMManager *wm = NULL; MBWMDecor *decor = NULL; MBWMDecorButtonPressedFunc press = NULL; MBWMDecorButtonReleasedFunc release = NULL; MBWMDecorButtonFlags flags = 0; MBWMDecorButtonType type = 0; MBWMDecorButtonPack pack = MBWMDecorButtonPackEnd; MBWMObjectProp prop; prop = va_arg(vap, MBWMObjectProp); while (prop) { switch (prop) { case MBWMObjectPropWm: wm = va_arg(vap, MBWMManager *); break; case MBWMObjectPropDecor: decor = va_arg(vap, MBWMDecor*); break; case MBWMObjectPropDecorButtonPressedFunc: press = va_arg(vap, MBWMDecorButtonPressedFunc); break; case MBWMObjectPropDecorButtonReleasedFunc: release = va_arg(vap, MBWMDecorButtonReleasedFunc); break; case MBWMObjectPropDecorButtonFlags: flags = va_arg(vap, MBWMDecorButtonFlags); break; case MBWMObjectPropDecorButtonType: type = va_arg(vap, MBWMDecorButtonType); break; case MBWMObjectPropDecorButtonPack: pack = va_arg(vap, MBWMDecorButtonPack); break; default: MBWMO_PROP_EAT (vap, prop); } prop = va_arg(vap, MBWMObjectProp); } if (!wm || !decor) return 0; /* * Decors must be attached before we can start adding buttons to them, * otherwise we cannot work out the button geometry. */ MBWM_ASSERT (decor->parent_client); button->geom.width = 0; button->geom.height = 0; mb_wm_theme_get_button_size (wm->theme, decor, type, &button->geom.width, &button->geom.height); button->press = press; button->release = release; button->decor = decor; button->type = type; button->pack = pack; button->press_activated = mb_wm_theme_is_button_press_activated (wm->theme, decor, type); decor->buttons = g_list_append (decor->buttons, button); /* the decor assumes a reference, so add one for the caller */ mb_wm_object_ref (obj); return 1; } int mb_wm_decor_button_class_type () { static int type = 0; if (UNLIKELY(type == 0)) { static MBWMObjectClassInfo info = { sizeof (MBWMDecorButtonClass), sizeof (MBWMDecorButton), mb_wm_decor_button_init, mb_wm_decor_button_destroy, mb_wm_decor_button_class_init }; type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); } return type; } static void mb_wm_decor_button_destroy (MBWMObject* obj) { MBWMDecorButton * button = MB_WM_DECOR_BUTTON (obj); MBWMManager * wm = button->decor->parent_client->wmref; if (button->userdata && button->destroy_userdata) { button->destroy_userdata (button, button->userdata); button->userdata = NULL; button->destroy_userdata = NULL; } if (button->themedata && button->destroy_themedata) { button->destroy_themedata (button, button->themedata); button->themedata = NULL; button->destroy_themedata = NULL; } mb_wm_manager_remove_event_handler (wm, ButtonPress, button->press_cb_id); } static void mb_wm_decor_button_realize (MBWMDecorButton *button) { MBWMDecor *decor = button->decor; MBWMManager *wm = decor->parent_client->wmref; button->press_cb_id = mb_wm_manager_add_event_handler (wm, decor->xwin, ButtonPress, (MBWMXEventFunc)mb_wm_decor_button_press_handler, button); button->realized = True; } static void mb_wm_decor_button_sync_window (MBWMDecorButton *button) { if (!button->realized) { mb_wm_decor_button_realize (button); } } void mb_wm_decor_button_show (MBWMDecorButton *button) { button->visible = True; } void mb_wm_decor_button_hide (MBWMDecorButton *button) { button->visible = False; } void mb_wm_decor_button_move_to (MBWMDecorButton *button, int x, int y) { /* FIXME: set a sync flag so it know X movewindow is needed */ button->geom.x = x; button->geom.y = y; MBWM_DBG ("####### moving to %i, %i\n", button->geom.x, button->geom.y); } MBWMDecorButton* mb_wm_decor_button_new (MBWMManager *wm, MBWMDecorButtonType type, MBWMDecorButtonPack pack, MBWMDecor *decor, MBWMDecorButtonPressedFunc press, MBWMDecorButtonReleasedFunc release, MBWMDecorButtonFlags flags) { MBWMObject *button; button = mb_wm_object_new (MB_WM_TYPE_DECOR_BUTTON, MBWMObjectPropWm, wm, MBWMObjectPropDecorButtonType, type, MBWMObjectPropDecorButtonPack, pack, MBWMObjectPropDecor, decor, MBWMObjectPropDecorButtonPressedFunc, press, MBWMObjectPropDecorButtonReleasedFunc, release, MBWMObjectPropDecorButtonFlags, flags, NULL); return MB_WM_DECOR_BUTTON(button); } MBWMDecorButton* mb_wm_decor_button_stock_new (MBWMManager *wm, MBWMDecorButtonType type, MBWMDecorButtonPack pack, MBWMDecor *decor, MBWMDecorButtonFlags flags) { MBWMObject *button; button = mb_wm_object_new (MB_WM_TYPE_DECOR_BUTTON, MBWMObjectPropWm, wm, MBWMObjectPropDecorButtonType, type, MBWMObjectPropDecorButtonPack, pack, MBWMObjectPropDecor, decor, MBWMObjectPropDecorButtonFlags, flags, NULL); return MB_WM_DECOR_BUTTON(button); } void mb_wm_decor_button_handle_repaint (MBWMDecorButton *button) { MBWMDecor * decor = button->decor; MBWMTheme * theme = decor->parent_client->wmref->theme; if (decor->parent_client == NULL) return; mb_wm_theme_paint_button (theme, button); } void mb_wm_decor_button_set_user_data (MBWMDecorButton * button, void *userdata, MBWMDecorButtonDestroyUserData destroy) { button->userdata = userdata; button->destroy_userdata = destroy; } void * mb_wm_decor_button_get_user_data (MBWMDecorButton * button) { return button->userdata; }