/* Metacity X window decorations */ /* * Copyright (C) 2001 Havoc Pennington * * 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 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "frame.h" #include "errors.h" #include "keybindings.h" #define EVENT_MASK (SubstructureRedirectMask | \ StructureNotifyMask | SubstructureNotifyMask | \ ExposureMask | \ ButtonPressMask | ButtonReleaseMask | \ PointerMotionMask | PointerMotionHintMask | \ EnterWindowMask | LeaveWindowMask | \ FocusChangeMask) void meta_window_ensure_frame (MetaWindow *window) { MetaFrame *frame; XSetWindowAttributes attrs; g_return_if_fail (window->display->server_grab_count > 0); if (window->frame) return; frame = g_new (MetaFrame, 1); frame->window = window; frame->xwindow = None; frame->rect = window->rect; frame->child_x = 0; frame->child_y = 0; frame->bottom_height = 0; frame->right_width = 0; frame->mapped = FALSE; attrs.event_mask = EVENT_MASK; frame->xwindow = XCreateWindow (window->display->xdisplay, window->screen->xroot, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, 0, window->depth, InputOutput, window->xvisual, CWEventMask, &attrs); /* So our UI can find the window ID */ XFlush (window->display->xdisplay); meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); meta_display_register_x_window (window->display, &frame->xwindow, window); /* Reparent the client window; it may be destroyed, * thus the error trap. We'll get a destroy notify later * and free everything. Comment in FVWM source code says * we need a server grab or the child can get its MapNotify * before we've finished reparenting and getting the decoration * window onscreen, so ensure_frame must be called with * a grab. */ meta_error_trap_push (window->display); window->mapped = FALSE; /* the reparent will unmap the window, * we don't want to take that as a withdraw */ window->unmaps_pending += 1; window->rect.x = 0; window->rect.y = 0; XReparentWindow (window->display->xdisplay, window->xwindow, frame->xwindow, window->rect.x, window->rect.y); meta_error_trap_pop (window->display); /* stick frame to the window */ window->frame = frame; meta_ui_add_frame (window->screen->ui, frame->xwindow); if (window->title) meta_ui_set_frame_title (window->screen->ui, window->frame->xwindow, window->title); /* Move keybindings to frame instead of window */ meta_window_grab_keys (window); } void meta_window_destroy_frame (MetaWindow *window) { MetaFrame *frame; if (window->frame == NULL) return; frame = window->frame; meta_ui_remove_frame (window->screen->ui, frame->xwindow); /* Unparent the client window; it may be destroyed, * thus the error trap. */ meta_error_trap_push (window->display); window->mapped = FALSE; /* Keep track of unmapping it, so we * can identify a withdraw initiated * by the client. */ window->unmaps_pending += 1; XReparentWindow (window->display->xdisplay, window->xwindow, window->screen->xroot, /* FIXME where to put it back depends on the gravity */ window->frame->rect.x, window->frame->rect.y); meta_error_trap_pop (window->display); meta_display_unregister_x_window (window->display, frame->xwindow); window->frame = NULL; /* Move keybindings to window instead of frame */ meta_window_grab_keys (window); /* should we push an error trap? */ XDestroyWindow (window->display->xdisplay, frame->xwindow); g_free (frame); /* Put our state back where it should be */ meta_window_queue_calc_showing (window); } MetaFrameFlags meta_frame_get_flags (MetaFrame *frame) { MetaFrameFlags flags; flags = META_FRAME_ALLOWS_MENU; if (frame->window->has_close_func) flags |= META_FRAME_ALLOWS_DELETE; if (frame->window->has_maximize_func) flags |= META_FRAME_ALLOWS_MAXIMIZE; if (frame->window->has_minimize_func) flags |= META_FRAME_ALLOWS_MINIMIZE; if (frame->window->has_shade_func) flags |= META_FRAME_ALLOWS_SHADE; if (frame->window->has_move_func) flags |= META_FRAME_ALLOWS_MOVE; if (frame->window->has_resize_func) flags |= META_FRAME_ALLOWS_RESIZE; if (frame->window->has_focus) flags |= META_FRAME_HAS_FOCUS; if (frame->window->shaded) flags |= META_FRAME_SHADED; if (frame->window->on_all_workspaces) flags |= META_FRAME_STUCK; if (frame->window->maximized) flags |= META_FRAME_MAXIMIZED; return flags; } void meta_frame_calc_geometry (MetaFrame *frame, MetaFrameGeometry *geomp) { MetaFrameGeometry geom; MetaWindow *window; window = frame->window; meta_ui_get_frame_geometry (window->screen->ui, frame->xwindow, &geom.top_height, &geom.bottom_height, &geom.left_width, &geom.right_width); *geomp = geom; } static void set_background_none (MetaFrame *frame) { XSetWindowAttributes attrs; attrs.background_pixmap = None; XChangeWindowAttributes (frame->window->display->xdisplay, frame->xwindow, CWBackPixmap, &attrs); } void meta_frame_sync_to_window (MetaFrame *frame, gboolean need_move, gboolean need_resize) { meta_verbose ("Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, frame->rect.x + frame->rect.width, frame->rect.y + frame->rect.height); /* set bg to none to avoid flicker */ if (need_resize) set_background_none (frame); if (need_move && need_resize) XMoveResizeWindow (frame->window->display->xdisplay, frame->xwindow, frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); else if (need_move) XMoveWindow (frame->window->display->xdisplay, frame->xwindow, frame->rect.x, frame->rect.y); else if (need_resize) XResizeWindow (frame->window->display->xdisplay, frame->xwindow, frame->rect.width, frame->rect.height); if (need_resize) meta_ui_reset_frame_bg (frame->window->screen->ui, frame->xwindow); } void meta_frame_queue_draw (MetaFrame *frame) { meta_ui_queue_frame_draw (frame->window->screen->ui, frame->xwindow); } gboolean meta_frame_event (MetaFrame *frame, XEvent *event) { switch (event->type) { case KeyPress: case KeyRelease: meta_display_process_key_event (frame->window->display, frame->window, event); break; case ButtonPress: break; case ButtonRelease: break; case MotionNotify: break; case EnterNotify: /* We handle it here if a decorated window * is involved, otherwise we handle it in display.c */ /* do this even if window->has_focus to avoid races */ meta_window_focus (frame->window, event->xcrossing.time); break; case LeaveNotify: break; case FocusIn: case FocusOut: meta_window_notify_focus (frame->window, event); break; case KeymapNotify: break; case Expose: break; case GraphicsExpose: break; case NoExpose: break; case VisibilityNotify: break; case CreateNotify: break; case DestroyNotify: { MetaDisplay *display; meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", frame->xwindow); display = frame->window->display; meta_error_trap_push (display); meta_window_destroy_frame (frame->window); meta_error_trap_pop (display); return TRUE; } break; case UnmapNotify: break; case MapNotify: break; case MapRequest: break; case ReparentNotify: break; case ConfigureNotify: break; case ConfigureRequest: break; case GravityNotify: break; case ResizeRequest: break; case CirculateNotify: break; case CirculateRequest: break; case PropertyNotify: break; case SelectionClear: break; case SelectionRequest: break; case SelectionNotify: break; case ColormapNotify: break; case ClientMessage: break; case MappingNotify: break; default: break; } return FALSE; }