diff options
Diffstat (limited to 'matchbox/mb-wm-client-dialog.c')
-rw-r--r-- | matchbox/mb-wm-client-dialog.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/matchbox/mb-wm-client-dialog.c b/matchbox/mb-wm-client-dialog.c new file mode 100644 index 0000000..b854c7c --- /dev/null +++ b/matchbox/mb-wm-client-dialog.c @@ -0,0 +1,360 @@ +#include "mb-wm-client-dialog.h" +#include "mb-window-manager.h" + +#include "mb-wm-theme.h" + +static Bool +mb_wm_client_dialog_request_geometry (MBWindowManagerClient *client, + MBGeometry *new_geometry, + MBWMClientReqGeomType flags); + +static void +mb_wm_client_dialog_theme_change (MBWindowManagerClient *client); + +static void +mb_wm_client_dialog_show (MBWindowManagerClient *client) +{ + MBWindowManagerClientClass *parent_klass = NULL; + + /* + * We need the parent of the MBWMClientDialogClass to chain up + */ + if (MB_WM_IS_CLIENT_DIALOG (client)) + parent_klass = MB_WM_CLIENT_CLASS (MB_WM_OBJECT_GET_PARENT_CLASS (client)); + else + { + /* + * A derived klass -- need to traverse the klass hierarchy to get to + * the dialog klass + */ + MBWMObjectClass * object_klass = MB_WM_OBJECT_GET_PARENT_CLASS (client); + + while (object_klass && object_klass->type != MB_WM_TYPE_CLIENT_DIALOG) + object_klass = object_klass->parent; + + if (object_klass && object_klass->parent) + parent_klass = MB_WM_CLIENT_CLASS (object_klass->parent); + } + + if (client->transient_for != NULL) + { + MBWindowManager * wm = client->wmref; + + /* + * If an attempt has been made to activate a hidden + * dialog, activate its parent app first. + * + * Note this is mainly to work with some task selectors + * ( eg the gnome one, which activates top dialog ). + */ + MBWindowManagerClient *parent = client->transient_for; + + while (parent->transient_for != NULL) + parent = parent->transient_for; + + if (parent != mb_wm_get_visible_main_client(wm)) + mb_wm_client_show (parent); + } + + if (parent_klass && parent_klass->show) + parent_klass->show(client); +} + +static void +mb_wm_client_dialog_class_init (MBWMObjectClass *klass) +{ + MBWindowManagerClientClass *client; + + MBWM_MARK(); + + client = (MBWindowManagerClientClass *)klass; + + client->client_type = MBWMClientTypeDialog; + client->geometry = mb_wm_client_dialog_request_geometry; + client->show = mb_wm_client_dialog_show; + client->theme_change = mb_wm_client_dialog_theme_change; + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMClientDialog"; +#endif +} + +static void +mb_wm_client_dialog_destroy (MBWMObject *this) +{ +} + +static int +mb_wm_client_dialog_init (MBWMObject *this, va_list vap) +{ + MBWindowManagerClient *client = MB_WM_CLIENT (this); + MBWindowManager *wm = client->wmref; + MBWMClientWindow *win = client->window; + MBGeometry geom; + int n, s, w, e; + Atom actions[] = { + wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE], + wm->atoms[MBWM_ATOM_NET_WM_ACTION_MOVE], + }; + + XChangeProperty (wm->xdpy, win->xwindow, + wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS], + XA_ATOM, 32, PropModeReplace, + (unsigned char *)actions, + sizeof (actions)/sizeof (actions[0])); + + + mb_wm_client_set_layout_hints (client, + LayoutPrefPositionFree | + LayoutPrefMovable | + LayoutPrefVisible); + + if (!client->window->undecorated) + { + mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeNorth); + mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeSouth); + mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeWest); + mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeEast); + } + + if (win->xwin_transient_for + && win->xwin_transient_for != win->xwindow + && win->xwin_transient_for != wm->root_win->xwindow) + { + MBWM_DBG ("Adding to '%lx' transient list", + win->xwin_transient_for); + mb_wm_client_add_transient + (mb_wm_managed_client_from_xwindow (wm, + win->xwin_transient_for), + client); + client->stacking_layer = 0; /* We stack with whatever transient too */ + } + else + { + MBWM_DBG ("Dialog is transient to root"); + /* Stack with 'always on top' */ + client->stacking_layer = MBWMStackLayerTopMid; + } + + /* center if window sets 0,0 + * Only do this for dialogs, not derived classes. + * FIXME needs to work on frame, not window. + */ + if (MB_WM_IS_CLIENT_DIALOG (client) && + client->window->geometry.x == 0 && client->window->geometry.y == 0) + { + MBGeometry avail_geom; + + mb_wm_get_display_geometry (wm, &avail_geom); + + client->window->geometry.x + = (avail_geom.width - client->window->geometry.width) / 2; + client->window->geometry.y + = (avail_geom.height - client->window->geometry.height) / 2; + } + + mb_wm_client_geometry_mark_dirty (client); + mb_wm_client_visibility_mark_dirty (client); + + if (!wm->theme) + return 1; + + /* + * Since dialogs are free-sized, they do not necessarily get a request for + * geometry from the layout manager -- we have to set the initial geometry + * here + */ + mb_wm_theme_get_decor_dimensions (wm->theme, client, &n, &s, &w, &e); + + geom.x = client->window->geometry.x; + geom.y = client->window->geometry.y; + geom.width = client->window->geometry.width + w + e; + geom.height = client->window->geometry.height + n + s; + + mb_wm_client_dialog_request_geometry (client, &geom, + MBWMClientReqGeomForced); + + return 1; +} + +int +mb_wm_client_dialog_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMClientDialogClass), + sizeof (MBWMClientDialog), + mb_wm_client_dialog_init, + mb_wm_client_dialog_destroy, + mb_wm_client_dialog_class_init + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0); + } + + return type; +} + +static Bool +mb_wm_client_dialog_request_geometry (MBWindowManagerClient *client, + MBGeometry *new_geometry, + MBWMClientReqGeomType flags) +{ + const MBGeometry * geom; + Bool change_pos; + Bool change_size; + + /* + * When we get an internal geometry request, like from the layout manager, + * the new geometry applies to the frame; however, if the request is + * external from ConfigureRequest, it is new geometry of the client window, + * so we need to take care to handle this right. + */ + geom = (flags & MBWMClientReqGeomIsViaConfigureReq) ? + &client->window->geometry : &client->frame_geometry; + + change_pos = (geom->x != new_geometry->x || geom->y != new_geometry->y); + + change_size = (geom->width != new_geometry->width || + geom->height != new_geometry->height); + + if (change_size) + { + int north = 0, south = 0, west = 0, east = 0; + MBWindowManager *wm = client->wmref; + + if (client->decor) + mb_wm_theme_get_decor_dimensions (wm->theme, client, + &north, &south, &west, &east); + + if (flags & MBWMClientReqGeomIsViaConfigureReq) + { + /* + * Calculate the frame size from the window size + */ + MBWM_DBG ("ConfigureRequest [%d,%d;%dx%d] -> [%d,%d;%dx%d]\n", + client->window->geometry.x, + client->window->geometry.y, + client->window->geometry.width, + client->window->geometry.height, + new_geometry->x, + new_geometry->y, + new_geometry->width, + new_geometry->height); + + client->window->geometry.x = new_geometry->x; + client->window->geometry.y = new_geometry->y; + client->window->geometry.width = new_geometry->width; + client->window->geometry.height = new_geometry->height; + + client->frame_geometry.x + = client->window->geometry.x - west; + client->frame_geometry.y + = client->window->geometry.y - north; + client->frame_geometry.width + = client->window->geometry.width + (west + east); + client->frame_geometry.height + = client->window->geometry.height + (south + north); + } + else + { + /* + * Internal request, e.g., from layout manager; work out client + * window size from the provided frame size. + */ + client->frame_geometry.x = new_geometry->x; + client->frame_geometry.y = new_geometry->y; + client->frame_geometry.width = new_geometry->width; + client->frame_geometry.height = new_geometry->height; + + client->window->geometry.x + = client->frame_geometry.x + west; + client->window->geometry.y + = client->frame_geometry.y + north; + client->window->geometry.width + = client->frame_geometry.width - (west + east); + client->window->geometry.height + = client->frame_geometry.height - (south + north); + } + + mb_wm_client_geometry_mark_dirty (client); + + return True; /* Geometry accepted */ + } + else if (change_pos) + { + /* + * Change of position only, just move both windows, no need to + * mess about with the decor. + */ + int x_diff = geom->x - new_geometry->x; + int y_diff = geom->y - new_geometry->y; + + client->frame_geometry.x -= x_diff; + client->frame_geometry.y -= y_diff; + client->window->geometry.x -= x_diff; + client->window->geometry.y -= y_diff; + + mb_wm_client_geometry_mark_dirty (client); + + return True; + } + + return True; /* Geometry accepted */ +} + +static void +mb_wm_client_dialog_theme_change (MBWindowManagerClient *client) +{ + MBWMList * l = client->decor; + + while (l) + { + MBWMDecor * d = l->data; + MBWMList * n = l->next; + + mb_wm_object_unref (MB_WM_OBJECT (d)); + free (l); + + l = n; + } + + client->decor = NULL; + + if (!client->window->undecorated) + { + mb_wm_theme_create_decor (client->wmref->theme, + client, MBWMDecorTypeNorth); + + mb_wm_theme_create_decor (client->wmref->theme, + client, MBWMDecorTypeSouth); + + mb_wm_theme_create_decor (client->wmref->theme, + client, MBWMDecorTypeWest); + + mb_wm_theme_create_decor (client->wmref->theme, + client, MBWMDecorTypeEast); + } + + mb_wm_client_geometry_mark_dirty (client); + mb_wm_client_visibility_mark_dirty (client); +} + + +MBWindowManagerClient* +mb_wm_client_dialog_new (MBWindowManager *wm, MBWMClientWindow *win) +{ + MBWindowManagerClient *client; + + client + = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_DIALOG, + MBWMObjectPropWm, wm, + MBWMObjectPropClientWindow, win, + NULL)); + + return client; +} + |