/* There is code in here from metacity and from fvwm. FIXME: add copyright statements */ /* Some principles: * * - We can only deal with one screen (but know about monitors) * * - We don't reparent * * - Compositing manager only * * - XRender, not OpenGL * * - No theming * * - No workspaces. They are crack. * * - There is very little configuation */ #include #include #include "ocm.h" static uint32_t get_time (ocm_app_t *app) { if (app->timestamp == CurrentTime) { XEvent event; /* Using the property XA_PRIMARY because it's safe; nothing * would use it as a property. The type doesn't matter. */ XChangeProperty (app->display, app->no_focus, XA_PRIMARY, XA_STRING, 8, PropModeAppend, NULL, 0); XWindowEvent (app->display, app->no_focus, PropertyChangeMask, &event); app->timestamp = event.xproperty.time; } return app->timestamp; } static ocm_window_t * app_find_xwindow (ocm_app_t *app, Window xwindow) { ocm_window_t *w; for (w = app->windows; w != NULL; w = w->next) { if (w->xwindow == xwindow) return w; } return NULL; } static void app_unmanage_window (ocm_app_t *app, Window xwindow) { ocm_window_t *prev, *window; prev = NULL; window = app->windows; while (window) { if (window->xwindow == xwindow) { if (prev) prev->next = window->next; else app->windows = window->next; ocm_window_free (window); return; } prev = window; window = window->next; } } static Window create_offscreen_window (ocm_app_t *app) { XSetWindowAttributes attrs; attrs.override_redirect = TRUE; attrs.event_mask = NoEventMask; return XCreateWindow (app->display, app->root, -100, -100, 1, 1, 0, CopyFromParent, CopyFromParent, (Visual *)CopyFromParent, CWOverrideRedirect | CWEventMask, &attrs); } static void acquire_manager_selection (ocm_app_t * app, const char * selection, Window new_owner, bool replace) { Atom atom = XInternAtom (app->display, selection, FALSE); Window existing; XSetWindowAttributes attr; uint32_t managed_since; XClientMessageEvent event; existing = XGetSelectionOwner (app->display, atom); if (existing) { if (!replace) ocm_error ("Could not acquire %s - try -r", selection); attr.event_mask = StructureNotifyMask; XChangeWindowAttributes (app->display, existing, CWEventMask, &attr); } managed_since = get_time (app); XSetSelectionOwner (app->display, atom, app->no_focus, managed_since); /* Announce ourself as the new owner */ event.type = ClientMessage; event.window = app->root; event.message_type = XInternAtom (app->display, "MANAGER", FALSE); event.format = 32; event.data.l[0] = managed_since; event.data.l[1] = atom; XSendEvent (app->display, app->root, FALSE, StructureNotifyMask, (XEvent*)&event); if (existing) { XEvent event; do { XWindowEvent (app->display, existing, StructureNotifyMask, &event); } while (event.type != DestroyNotify); } } static ocm_app_t * ocm_app_new (int argc, char **argv) { ocm_app_t *app = malloc (sizeof (*app)); int render_event, render_error; int composite_major, composite_minor; int damage_event, damage_error; XSetWindowAttributes attr; unsigned int n_children; Window *children, r, p; bool replace; int i; replace = FALSE; for (i = 0; i < argc; ++i) { char *arg = argv[i]; if (strcmp (arg, "-r") == 0) replace = TRUE; } app->display = XOpenDisplay (NULL); if (!app->display) ocm_error ("Could not open X display"); app->root = DefaultRootWindow (app->display); app->timestamp = CurrentTime; app->error_handler = NULL; app->error_nesting = 0; app->windows = NULL; if (!XRenderQueryExtension ( app->display, &render_event, &render_error)) { ocm_error ("No Render extension"); } if (!XCompositeQueryVersion ( app->display, &composite_major, &composite_minor)) { ocm_error ("No Composite extension"); } if (composite_major == 0 && composite_minor < 2) ocm_error ("No NamePixmap\n"); if (!XDamageQueryExtension ( app->display, &damage_event, &damage_error)) { ocm_error ("No Damage extensions\n"); } attr.event_mask = StructureNotifyMask | PropertyChangeMask | KeyPressMask | KeyReleaseMask; attr.override_redirect = TRUE; attr.background_pixmap = None; attr.border_pixel = 0x00000000; app->no_focus = XCreateWindow (app->display, app->root, -10, -10, 10, 10, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask | CWOverrideRedirect | CWBackPixmap | CWBorderPixel, &attr); app->wm_owner = create_offscreen_window (app); acquire_manager_selection (app, "WM_S0", app->wm_owner, replace); app->cm_owner = create_offscreen_window (app); acquire_manager_selection (app, "WM_CM_S0", app->cm_owner, replace); XCompositeRedirectSubwindows ( app->display, app->root, CompositeRedirectManual); /* Now manage all the windows */ if (!XQueryTree (app->display, app->root, &r, &p, &children, &n_children)) ocm_error ("XQueryTree() failed"); for (i = 0; i < n_children; ++i) { ocm_window_t *owindow = ocm_window_new (app, children[i]); if (owindow) { owindow->next = app->windows; app->windows = owindow; } } if (children) XFree (children); return app; } static void ocm_app_run (ocm_app_t *app) { while (1) { XEvent event; XNextEvent (app->display, &event); } } int main (int argc, char **argv) { ocm_app_t *app = ocm_app_new (argc, argv); ocm_app_run (app); return 0; }