/* * Matchbox Window Manager II - A lightweight window manager not for the * desktop. * * Authored By Tomas Frydrych * * Copyright (c) 2007 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" #include "mb-wm-window-type-dialog.h" #include "mb-wm-window-type-app.h" #include static void mb_wm_root_window_class_init (MBWMObjectClass *klass) { MBWMRootWindowClass *rw_class; MBWM_MARK(); rw_class = (MBWMRootWindowClass *)klass; #if MBWM_WANT_DEBUG klass->klass_name = "MBWMRootWindow"; #endif } static void mb_wm_root_window_destroy (MBWMObject *this) { } static Bool mb_wm_root_window_init_attributes (MBWMRootWindow * win); static void mb_wm_root_window_init_properties (MBWMRootWindow * win); static int mb_wm_root_window_init (MBWMObject *this, va_list vap) { MBWMRootWindow *root_window = MB_WM_ROOT_WINDOW (this); MBWMManager *wm; MBWMObjectProp prop; XSetWindowAttributes attr; prop = va_arg(vap, MBWMObjectProp); while (prop) { if (prop == MBWMObjectPropWm) { wm = va_arg(vap, MBWMManager *); break; } else MBWMO_PROP_EAT (vap, prop); prop = va_arg(vap, MBWMObjectProp); } root_window->wm = wm; root_window->xwindow = RootWindow(wm->xdpy, wm->xscreen); if (!mb_wm_root_window_init_attributes (root_window)) { MBWM_DBG ("Failed to initialize root window attributes."); abort (); } attr.override_redirect = True; root_window->hidden_window = XCreateWindow(wm->xdpy, root_window->xwindow, -200, -200, 5, 5, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr); mb_wm_root_window_init_properties (root_window); return 1; } int mb_wm_root_window_class_type () { static int type = 0; if (UNLIKELY(type == 0)) { static MBWMObjectClassInfo info = { sizeof (MBWMRootWindowClass), sizeof (MBWMRootWindow), mb_wm_root_window_init, mb_wm_root_window_destroy, mb_wm_root_window_class_init }; type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); } return type; } MBWMRootWindow* mb_wm_root_window_get (MBWMManager *wm) { static MBWMRootWindow * root_window = NULL; if (!root_window) { root_window = MB_WM_ROOT_WINDOW (mb_wm_object_new (MB_WM_TYPE_ROOT_WINDOW, MBWMObjectPropWm, wm, NULL)); } else mb_wm_object_ref (MB_WM_OBJECT (root_window)); return root_window; } static Bool mb_wm_root_window_init_attributes (MBWMRootWindow * win) { XSetWindowAttributes sattr; MBWMManager *wm = win->wm; sattr.event_mask = SubstructureRedirectMask |SubstructureNotifyMask |StructureNotifyMask |PropertyChangeMask; mb_wm_util_trap_x_errors(); XChangeWindowAttributes(wm->xdpy, win->xwindow, CWEventMask, &sattr); XSync(wm->xdpy, False); if (mb_wm_util_untrap_x_errors()) { /* FIXME: Error codes */ mb_wm_util_fatal_error("Unable to manage display - " "another window manager already active?"); return False; } XSelectInput(wm->xdpy, win->xwindow, sattr.event_mask); return True; } void mb_wm_root_window_update_supported_props (MBWMRootWindow *win) { MBWMManager *wm = win->wm; Window rwin = win->xwindow; CARD32 num_supported = 0; /* * Supported info */ Atom supported[] = { wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR], wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DOCK], wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DIALOG], wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DESKTOP], wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_SPLASH], wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_MENU], wm->atoms[MBWM_ATOM_NET_WM_STATE], wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN], wm->atoms[MBWM_ATOM_NET_WM_STATE_MODAL], wm->atoms[MBWM_ATOM_NET_SUPPORTED], wm->atoms[MBWM_ATOM_NET_CLIENT_LIST], wm->atoms[MBWM_ATOM_NET_NUMBER_OF_DESKTOPS], wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW], wm->atoms[MBWM_ATOM_NET_SUPPORTING_WM_CHECK], wm->atoms[MBWM_ATOM_NET_CLOSE_WINDOW], wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP], wm->atoms[MBWM_ATOM_NET_CLIENT_LIST_STACKING], wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP], wm->atoms[MBWM_ATOM_NET_WM_NAME], wm->atoms[MBWM_ATOM_NET_WM_ICON], wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS], wm->atoms[MBWM_ATOM_NET_WM_ACTION_MOVE], wm->atoms[MBWM_ATOM_NET_WM_ACTION_FULLSCREEN], wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE], wm->atoms[MBWM_ATOM_NET_STARTUP_ID], wm->atoms[MBWM_ATOM_NET_WM_PING], wm->atoms[MBWM_ATOM_NET_WORKAREA], wm->atoms[MBWM_ATOM_NET_DESKTOP_GEOMETRY], wm->atoms[MBWM_ATOM_NET_WM_PING], wm->atoms[MBWM_ATOM_NET_WM_PID], wm->atoms[MBWM_ATOM_CM_TRANSLUCENCY], wm->atoms[MBWM_ATOM_NET_WM_FULL_PLACEMENT], wm->atoms[MBWM_ATOM_NET_FRAME_EXTENTS], 0, 0, 0 }; num_supported = sizeof(supported)/sizeof(Atom) - 3; /* Check to see if the theme supports help / accept buttons */ if (wm->theme) { if (mb_wm_theme_supports (wm->theme, MBWMThemeCapsFrameMainButtonActionAccept)) supported[num_supported++]=wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_ACCEPT]; if (mb_wm_theme_supports (wm->theme, MBWMThemeCapsFrameMainButtonActionHelp)) supported[num_supported++] = wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_HELP]; if (mb_wm_theme_supports (wm->theme, MBWMThemeCapsFrameMainButtonActionCustom)) supported[num_supported++]=wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_CUSTOM]; } XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_SUPPORTED], XA_ATOM, 32, PropModeReplace, (unsigned char *)supported, num_supported); if (wm->theme) { if (wm->theme->path) XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_MB_THEME], XA_STRING, 8, PropModeReplace, (unsigned char *)wm->theme->path, strlen (wm->theme->path) + 1); else XDeleteProperty (wm->xdpy, rwin, wm->atoms[MBWM_ATOM_MB_THEME]); } } static void mb_wm_root_window_init_properties (MBWMRootWindow * win) { MBWMManager *wm = win->wm; Window rwin = win->xwindow; Window hwin = win->hidden_window; CARD32 card32; unsigned long val[2]; char *app_name = "matchbox"; val[0] = hwin; /* Window name */ XChangeProperty(wm->xdpy, hwin, wm->atoms[MBWM_ATOM_NET_WM_NAME], wm->atoms[MBWM_ATOM_UTF8_STRING], 8, PropModeReplace, (unsigned char *)app_name, strlen(app_name)+1); XStoreName(wm->xdpy, hwin, app_name); /* Crack Needed to stop gnome session hanging ? */ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_WIN_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)val, 1); XChangeProperty(wm->xdpy, hwin, wm->atoms[MBWM_ATOM_WIN_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)val, 1); /* Correct way of doing it */ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)val, 1); XChangeProperty(wm->xdpy, hwin, wm->atoms[MBWM_ATOM_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)val, 1); mb_wm_root_window_update_supported_props (win); /* * Desktop info */ card32 = 1; XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_NUMBER_OF_DESKTOPS], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&card32, 1); --card32; XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&card32, 1); XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&card32, 1); val[0] = 0; val[1] = 0; XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_DESKTOP_VIEWPORT], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&val[0], 2); XSync(wm->xdpy, False); } int mb_wm_root_window_handle_message (MBWMRootWindow *win, XClientMessageEvent *e) { MBWMManager *wm = win->wm; MBWindowManagerClient *c = NULL; if (e->message_type == wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW]) { Window xwin = e->window; if ((c = mb_wm_manager_managed_window_from_xwindow (wm, xwin)) != NULL) mb_wm_manager_activate_window (wm, c); return 1; } else if (e->message_type == wm->atoms[MBWM_ATOM_NET_CLOSE_WINDOW]) { if ((c = mb_wm_manager_managed_window_from_xwindow(wm, e->window)) != NULL) mb_wm_client_deliver_delete(c); return 1; } else if (e->message_type == wm->atoms[MBWM_ATOM_WM_PROTOCOLS] && e->data.l[0] == wm->atoms[MBWM_ATOM_NET_WM_PING]) { if ((c = mb_wm_manager_managed_window_from_xwindow(wm, e->data.l[2])) != NULL) mb_wm_manager_handle_ping_reply (wm, c); return 1; } else if (e->message_type == wm->atoms[MBWM_ATOM_NET_WM_STATE]) { MBWMClientWindowStateChange state_op = 0; if (e->data.l[0] == 0) state_op = MBWMClientWindowStateChangeRemove; else if (e->data.l[0] == 1) state_op = MBWMClientWindowStateChangeAdd; else if (e->data.l[0] == 2) state_op = MBWMClientWindowStateChangeToggle; if (e->data.l[1] == wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN] && ((c = mb_wm_manager_managed_window_from_xwindow(wm, e->window)) != NULL) && MB_WM_IS_CLIENT_APP (c)) { mb_wm_client_set_state (c, MBWM_ATOM_NET_WM_STATE_FULLSCREEN, state_op); } else if (e->data.l[1] == wm->atoms[MBWM_ATOM_NET_WM_STATE_ABOVE] && ((c = mb_wm_manager_managed_window_from_xwindow(wm, e->window)) != NULL) && MB_WM_IS_CLIENT_DIALOG (c)) { mb_wm_client_set_state (c, MBWM_ATOM_NET_WM_STATE_ABOVE, state_op); } return 1; } else if (e->message_type == wm->atoms[MBWM_ATOM_WM_CHANGE_STATE]) { switch (e->data.l[0]) { case IconicState: if ((c = mb_wm_manager_managed_window_from_xwindow (wm, e->window))) mb_wm_client_iconize (c); default: MBWM_DBG ("Unhandled value %d for WM_CHANGE_STATE ClientMessage", e->data.l[0]); } } else if (e->message_type == wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP]) { mb_wm_manager_handle_show_desktop (wm, e->data.l[0]); return 1; } else if (e->message_type == wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP]) { mb_wm_manager_select_desktop (wm, e->data.l[0]); return 1; } else if (e->message_type == wm->atoms[MBWM_ATOM_MB_COMMAND]) { switch (e->data.l[0]) { case MB_CMD_EXIT: exit(0); case MB_CMD_NEXT: mb_wm_manager_cycle_apps (wm, False); break; case MB_CMD_PREV: mb_wm_manager_cycle_apps (wm, True); break; case MB_CMD_DESKTOP: mb_wm_manager_toggle_desktop (wm); break; #if ENABLE_COMPOSITE case MB_CMD_COMPOSITE: if (mb_wm_manager_compositing_enabled (wm)) mb_wm_manager_set_compositing_off (wm); else mb_wm_manager_set_compositing_on (wm); break; #endif default: /*FIXME -- not implemented yet */ case MB_CMB_KEYS_RELOAD: ; } } return 0; }