diff --git a/.gitignore b/.gitignore index 8a319fa2e..0bf82c3c9 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ src/50-mutter-navigation.xml src/50-mutter-system.xml src/50-mutter-windows.xml src/mutter-wm.desktop -src/mutter.desktop +src/mutter-wayland.desktop *.o *.a *.lo @@ -46,12 +46,13 @@ POTFILES po/*.pot 50-metacity-desktop-key.xml 50-metacity-key.xml -libmutter.pc -mutter -mutter-theme-viewer -mutter.desktop +libmutter-wayland.pc +mutter-wayland +mutter-launch org.gnome.mutter.gschema.valid org.gnome.mutter.gschema.xml +org.gnome.mutter.wayland.gschema.valid +org.gnome.mutter.wayland.gschema.xml testasyncgetprop testboxes testgradient @@ -75,9 +76,15 @@ src/mutter-enum-types.[ch] src/stamp-mutter-enum-types.h src/mutter-marshal.[ch] src/stamp-mutter-marshal.h -src/meta-dbus-xrandr.[ch] +src/meta-dbus-display-config.[ch] src/meta-dbus-idle-monitor.[ch] src/mutter-plugins.pc +src/gtk-shell-protocol.c +src/gtk-shell-server-protocol.h +src/xdg-shell-protocol.c +src/xdg-shell-server-protocol.h +src/xserver-protocol.c +src/xserver-server-protocol.h doc/reference/*.args doc/reference/*.bak doc/reference/*.hierarchy @@ -95,3 +102,11 @@ doc/reference/meta-undocumented.txt doc/reference/meta-unused.txt doc/reference/meta-docs.sgml doc/reference/meta.types +gtk-doc.m4 +intltool.m4 +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 +.dirstamp diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 9971ab08a..000000000 --- a/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Havoc Pennington diff --git a/COMPLIANCE b/COMPLIANCE deleted file mode 100644 index b45a6724f..000000000 --- a/COMPLIANCE +++ /dev/null @@ -1,159 +0,0 @@ -Metacity Standards Compliance -============================= -$Id$ - -1) Introduction -2) EWMH Compliance - a. Root Window Properties - b. Root Window Messages - c. Application Window Properties - d. Window Manager Protocols -3) ICCCM Compliance - -1) Introduction ---------------- - -This document details metacity compliance with the relevent standards. -The format of this document is as follows: - -[-/+?] Hint Name/Feature Name (Version number) - Errata/Comments - -The first character indicates the level of compliance as follows: - - none - / partial - + complete - ? unknown - -The title indicates a feature or a hint in the specification, and the -version number indicates the minimum version of the specification -supported by metacity. Later versions may be supported if no -incompatible changes have been made in the specification. - -2) EWMH Compliance ------------------- - -The EWMH, or Extended Window Manager Hints is a freedesktop.org- -developed standard to support a number of conventions for -communication between the window manager and clients. It builds on -and extends the ICCCM (See Section 3). A copy of the current EWMH -standard is available at http://freedesktop.org/Standards/wm-spec/ - - a. Root Window Properties - ------------------------- - -+ _NET_SUPPORTED (1.3) - -+ _NET_CLIENT_LIST (1.3) - -+ _NET_NUMBER_OF_DESKTOPS (1.3) - -+ _NET_DESKTOP_GEOMETRY (1.3) - Metacity does not implement large desktops, so this is kept set to - the screen size. - -+ _NET_DESKTOP_VIEWPORT (1.3) - Metacity does not implement viewports, so this is a constant (0,0). - -+ _NET_CURRENT_DESKTOP (1.3) - -+ _NET_DESKTOP_NAMES (1.3) - -+ _NET_ACTIVE_WINDOW (1.3) - -+ _NET_WORKAREA (1.3) - -+ _NET_SUPPORTING_WM_CHECK (1.3) - -+ _NET_VIRTUAL_ROOTS (1.3) - Metacity does not read or set this property, but it does not use - virtual roots to implement virtual desktops, so it complies with the - specification. - -+ _NET_DESKTOP_LAYOUT (1.3) - -+ _NET_SHOWING_DESKTOP (1.3) - - b. Root Window Messages - ----------------------- - -+ _NET_CLOSE_WINDOW (1.3) - -- _NET_MOVERESIZE_WINDOW (1.3) - Metacity supports this message, but the specification is unclear on - the layout of the detail value, and as such it is #if 0'd in the code - -+ _NET_WM_MOVERESIZE (1.3) - -- _NET_RESTACK_WINDOW (1.3) - Metacity will raise or lower windows in response to this message, - but the sibling restack modes are not supported, and it is currently - #if 0'd in the code. - -+ _NET_REQUEST_FRAME_EXTENTS (1.3) - - c. Application Window Properties - -------------------------------- - -+ _NET_WM_NAME (1.3) - -+ _NET_WM_VISIBLE_NAME (1.3) - Metacity does not set this property, but metacity will never display - a name different from _NET_WM_NAME - -+ _NET_WM_ICON_NAME (1.3) - -+ _NET_WM_VISIBLE_ICON_NAME (1.3) - Metacity does not set this property, but metacity will never display - a name different from _NET_WM_NAME - -+ _NET_WM_DESKTOP (1.3) - -+ _NET_WM_WINDOW_TYPE (1.3) - -/ _NET_WM_STATE (1.3) - This property is read and updated according to the specification, - but see caveat below. - Metacity does not recognize separate vertical and horizontal - maximization states. Currently metacity will do a two-dimensional - maximization if either property is set. - See: http://bugzilla.gnome.org/show_bug.cgi?id=113601 - Metacity doesn't implement viewports so _NET_WM_STATE_STICKY is - unimplemented. - -+ _NET_WM_ALLOWED_ACTIONS (1.3) - Metacity keeps this hint up to date. The code is somewhat crufty - and should be rewritten, though it is functional. - See: http://bugzilla.gnome.org/show_bug.cgi?id=90420 - -+ _NET_WM_STRUT (1.3) - -+ _NET_WM_STRUT_PARTIAL (1.3) - -+ _NET_WM_ICON_GEOMETRY (1.3) - Metacity uses this property to draw minimize/restore animations - -+ _NET_WM_ICON (1.3) - -+ _NET_WM_PID (1.3) - -+ _NET_WM_HANDLED_ICONS (1.3) - Metacity does not read or set this property. However, metacity - never manages iconified windows, and so has no need to do so. - -+ _NET_WM_USER_TIME (1.3) - Metacity uses this property to prevent applications from stealing - focus if supported by the toolkit. - -+ _NET_FRAME_EXTENTS (1.3) - If set in response to a _NET_REQUEST_FRAME_EXTENTS message received - prior to the window being mapped, this may be an estimate. This is, - however, expressly allowed by the specification. - - d. Window Manager Protocols - --------------------------- -+ _NET_WM_PING (1.3) - -3) ICCCM Compliance -------------------- -TODO \ No newline at end of file diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index e68822de0..000000000 --- a/ChangeLog +++ /dev/null @@ -1,15414 +0,0 @@ -2009-03-16 Thomas Thurman - - * NEWS: 2.26.0 release. - -2009-02-04 Neil Jagdish Patel - - * src/core/frame.c: queue resize on window undecorate - -2009-02-03 Luca Ferretti - - * src/include/all-keybindings.h: Fix description, focus the - desktop, not desktop backgroung (Closes bug #569649) - -2009-02-02 Matt Kraai - - * src/core/schema-bindings.c: Wrap g_error calls in braces. - -2009-02-01 Thomas Thurman - - * configure.in: Post-release bump to 2.25.233. - -2009-02-01 Thomas Thurman - - * NEWS: 2.25.144 release. - -2009-02-01 Matt Kraai - - Set prop_hooks_table to NULL after freeing it. - - * src/core/window-props.c: - -2009-01-29 Thomas Thurman - - Window properties are looked up in a hash table rather than - by iteration over an array. Saves ~44us per window, but - also makes the code cleaner. - - * src/core/display-private.h: - * src/core/window-props.c: - -2009-01-27 Matthias Claesen - - * src/core/edge-resistance.c: some lists failed to keep track - of their contents and therefore didn't free correctly. - Closes #552303. - -2009-01-27 Matthias Claesen - - * src/core/prefs.c: Free name of old theme when new theme - is loaded. Closes #552973. - -2009-01-27 Matthias Claesen - - * src/ui/ui.c: free the result of gdk_text_property_to_utf8_list() - even when it returns no data. - -2009-01-27 Owen Taylor - - GtkStyle is specific to a particular colormap. Metacity - uses different colormaps for windows with different - visuals, so it must specialize the GtkStyle. - - Closes #568365 and #513944. - - * src/ui/frames.[ch]: Keep a GtkStyle for each MetaUIFrame, which is - obtained by calling gtk_style_attach() on the style for the - MetaFrames. When the style of the MetaFrames changes, reattach - everything. When we call gtk_style_set_background() pass in the - right style. - - * src/ui/themes.[ch]: Create a _with_style() variant of functions that - previously took the style from widget->style passed in, so we - can draw with the right style for the colormap. - -2009-01-27 Thomas Thurman - - Added a gconf key to swap the meanings of the right and - middle buttons when the modifier key is held down. - Closes #437910. Thanks to Matt Kraai for looking over - the patch. - - * src/core/display.c: - * src/core/prefs.c: - * src/include/prefs.h: - * src/metacity.schemas.in.in: - -2009-01-27 Thomas Thurman - - All the window properties are now handled using simple - window property handlers. Closes #549886. - - * src/core/window-private.h: - * src/core/window-props.c: - * src/core/window.c: - -2009-01-26 Thomas Thurman - - More of the window properties are checked using simple - window property handlers. The ones which remain don't - actually look up the new value in the ordinary way, and - so are a little trickier to merge. Added an "initial" - flag to be on the safe side that the behaviour is the - same as before (so we don't do things when a window's - first mapped that we only used to do when a property - changed). Partial fix for bug #549886. - - * src/core/window-props.c: - * src/core/window-props.h: - * src/core/window.c: - -2009-01-25 Elijah Newren - - * src/core/window.c: add support for _NET_WM_MOVERESIZE_CANCEL. - -2009-01-10 Thomas Thurman - - * src/ui/theme.[ch]: add meta_theme_draw_frame_by_name, which - is needed for the theme editor. - -2008-12-26 Thomas Thurman - - * configure.in: Post-release bump to 2.25.144. - -2008-12-26 Thomas Thurman - - * NEWS: 2.25.89 release. - -2008-12-25 Thomas Thurman - - * src/include/all-keybindings.h: alt-F10 toggles maximisation, - alt-F5 only restores. Also rename "unmaximize" to "restore". - * src/ui/frames.c: Rename "unmaximize" to "restore". - Closes #343824. - -2008-12-25 Frederic Peters - - * src/core/main.c: (main): added call to g_thread_init(), as ORBit2 - stopped doing it and Metacity is using gconf; closes #565517. - -2008-12-24 Yanko Kaneti - - * src/metacity.schemas.in.in: add screenshot commands which had - mistakenly been removed; closes #564343, Launchpad bug 298463, - Red Hat bug 474635, and probably others. - -2008-12-24 Thomas Thurman - - * src/include/all-keybindings.h: fix move_to_corner_se - -2008-12-21 Colin Walters - - * src/core/window.c: windows which attempt to present themselves - but are offscreen end up demanding attention, unless they - are transient, when they move to the current workspace - as before. Closes #482354. - -2008-12-19 Thomas Thurman - - * src/ui/frames.c: when the user double-clicks the title bar, - end the grab op. Closes #401028. - -2008-12-16 Thomas Thurman - - * configure.in: Post-release bump to 2.25.89. - -2008-12-16 Thomas Thurman - - * NEWS: 2.25.55 release. - -2008-12-15 Erwann Chenede - - * configure.in: fix build on Solaris. Closes #564123. - -2008-12-02 Thomas Thurman - - * configure.in: Post-release bump to 2.25.55. - -2008-12-02 Thomas Thurman - - * NEWS: 2.25.34 release. - -2008-12-02 Matt Kraai - - * src/core/iconcache.c: patches to fixes for -Wall. Closes #562939. - -2008-12-01 Thomas Thurman - - * configure.in: Post-release bump to 2.25.34. - -2008-12-01 Thomas Thurman - - * NEWS: 2.25.21 release. - -2008-12-01 Thomas Thurman - - * configure.in: gnome-doc-tools version doesn't need to be so high. - * src/compositor/compositor-xrender.c: disable the entire file if the - compositor is disabled. - * src/core/async-getprop.[ch]: fixes for -Wall - * src/core/iconcache.c: fixes for -Wall - * src/core/testasyncgetprop.c: fixes for -Wall - * src/core/xprops.c: fixes for -Wall - -2008-11-26 Thomas Thurman - - * tools/announce-wrangler.py: linked language codes to po files - * tools/commit-wrangler.py: print revision url - -2008-11-26 Thomas Thurman - - * tools/announce-wrangler.py: renamed ini file - * tools/commit-wrangler.py: rewriting in terms of moap - -2008-11-25 Thomas Thurman - - * configure.in: Post-release bump to 2.25.21. - -2008-11-25 Thomas Thurman - - * NEWS: 2.25.13 release. - -2008-11-26 Thomas Thurman - - * tools/announce-wrangler.py (added): script to produce announcements - -2008-11-26 Thomas Thurman - - * src/core/xprops.c: add casts (#562106) - -2008-11-25 Thomas Thurman - - * metacity.doap: change to standard description. - -2008-11-23 Thomas Thurman - - * configure.in: Post-release bump to 2.25.13. - -2008-11-23 Thomas Thurman - - * NEWS: 2.25.8 release. - -2008-11-23 Thomas Thurman - - * po/POTFILES.in: add new bindings file - -2008-11-23 Daniel Macks - - reviewed by: Thomas Thurman - - * src/Makefile.am: reorder compiler flags so local includes come last. - Closes #562033. - -2008-11-23 Daniel Macks - - reviewed by: Thomas Thurman - - * configure.in: only accept --enable-compositor if we find we can - actually composite. Closes #560990. - -2008-11-23 Thomas Thurman - - * src/core/display.c: remove apparently spurious warnings about - operations on window "none" - -2008-11-23 Thomas Thurman - - * src/core/util.c: Set _POSIX_C_SOURCE to 200112L as it should always - have been, in an attempt to close #561962. - -2008-11-22 Thomas Thurman - - * configure.in: Set -ansi so people stop complaining about C99. - -2008-11-22 Thomas Thurman - - * src/core/prefs.c: fix stupid infinite loop when GConf is turned off. - -2008-11-22 Thomas Thurman - - * src/core/prefs.c: fix two places where there was a warning - if GConf was turned off. - -2008-11-22 Thomas Thurman - - * src/core/all-keybindings.h: "backward", not "backwards" throughout. - -2008-11-20 Thomas Thurman - - * configure.in: turned on -Wall and -Werror in order to - trap as many problems as possible. - * src/ui/resizepopup.c: added correct #include. - * src/ui/theme-viewer.c: initialised variable. - * src/core/xprops.c: corrected cast. - * src/core/main.c: added warning if chdir() fails. - * src/core/schema-bindings.c: checking the return - result of fgets(). - -2008-11-20 Thomas Thurman - - Merged screen and window keybinding tables so that - we can use just one file for the both. Also incidentally - closes #528337. Further efficiencies of scale to come. - - * src/include/prefs.h: replace META_PREF_*_KEYBINDINGS - with META_PREF_KEYBINDINGS - * src/core/keybindings.c: replace *_bindings with key_bindings - and similar throughout; all window-based functions are now - guaranteed to receive a window so don't need to check for - themselves - (find_handler): moved so it can also be called from - rebuild_binding_table - * src/core/display-private.h: replace *_bindings with key_bindings - * src/core/prefs.c: update_*_binding becomes update_key_binding; - (change_notify): tidy up references to "enormous if statement" - since it's almost entirely gone now - * src/core/all-keybindings.h: new merged version of - screen-bindings.h and window-bindings.h. - -2008-11-16 David Trowbridge - - This change adds support for the new _NET_WM_FULLSCREEN_MONITORS - property and client message. This allows client applications to request - that a fullscreen window cover more than one monitor. - - * src/include/boxes.h: - * src/core/boxes.c: Add meta_rectangle_union - - * src/core/window-private.h: - * src/core/window.c: - (meta_window_new_with_attrs, meta_window_free, set_net_wm_state, - meta_window_update_fullscreen_monitors, meta_window_client_message): Add - MetaWindow property to store fullscreen monitors field, update - _NET_WM_FULLSCREEN_MONITORS property on windows, and handle client - message. - - * src/core/atomnames.h: Add _NET_WM_FULLSCREEN_MONITORS atom. - - * src/core/constraints.c (setup_constraint_info): If - _NET_WM_FULLSCREEN_MONITORS is interesting, use the data stored in - MetaWindow::fullscreen_monitors to determine the fullscreen area instead - of the basic xinerama_info area. - -2008-11-11 Thomas Thurman - - Removed deprecated calls. Closes #560445. - - * src/core/delete.c: remove deprecated g_strcasecmp. - * src/include/main.h: no actual deprecated call, but - a mention of one which was out of date. - -2008-11-11 Maxim Ermilov - - Clean up #includes according to the GNOME Goal. - Closes #560449. Patch is 122467. - - * src/core/place.c: - * src/ui/draw-workspace.h: - * src/ui/gradient.h: - * src/ui/metaaccellabel.c: - * src/ui/metaaccellabel.h: - * src/ui/preview-widget.c: - * src/ui/preview-widget.h: - * src/ui/resizepopup.c: - * src/ui/theme.c: - * src/ui/theme.h: - * src/ui/themewidget.h: - -2008-11-10 Elijah Newren - - * src/metacity.schemas.in.in: updated description of - raise_on_click: - http://bugzilla.gnome.org/show_bug.cgi?id=445447#c6 - -2008-11-08 Thomas Thurman - - * configure.in: added dependency on Zenity - * src/core/keybindings.c: remove error_on_generic_command() and - error_on_terminal_command(); rewrite error_on_command - in terms of meta_show_dialog() - * src/core/util.c: add meta_show_dialog() to call Zenity - * src/include/util.h: ditto - -2008-11-03 Olav Vitters - - * src/ui/theme-parser.c: Fix build by readding accidentally removed - '}'. - -2008-10-29 Thomas Thurman - - * src/ui/theme-parser.c: variable names in messages should be - double-quoted. Closes #558309. - -2008-10-28 Thomas Thurman - - * src/include/screen-bindings.h: fix accidental name change of - run_command_terminal. Closes #557943. - -2008-10-27 Thomas Thurman - - * src/core/prefs.c (titlebar_handler, handle_preference_update_enum): - Add initialisation which I missed on the previous checkin. Also - an extra comment. - -2008-10-27 Brian Cameron - - Fix some crashes with the new GDM 2.24. Closes #558058. - - * src/ui/ui.c (meta_ui_parse_modifier): another null check - * src/core/prefs.c (titlebar_handler, button_layout_handler): - more null checks. - -2008-10-26 Thomas Thurman - - * src/core/prefs.c (mouse_button_mods_handler): Ignore values - of .../mouse_button_modifier key if the key's missing. - Closes Launchpad bug #258054, Launchpad bug #266929. - -2008-10-23 Frederic Peters - - * doc/creating_themes/C/creating-metacity-themes.xml: added missing @id - on top element. - -2008-10-23 Frederic Peters - - * doc/creating_themes/Makefile.am: - * doc/creating_themes/C/creating_metacity_themes.xml: renamed document - to creating-metacity-themes to match other manuals usage of dashes. - -2008-10-23 Thomas Thurman - - * configure.in: Post-release bump to 2.25.8. - -2008-10-23 Thomas Thurman - - * NEWS: 2.25.5 release. - -2008-10-23 Thomas Thurman - - * src/core/schema-bindings.c: fix stupid thinko which - caused defaults to be incorrect - * src/include/window-bindings.h: "space" needs to be - lowercase - -2008-10-23 Thomas Thurman - - Support _NET_WM_STATE_STICKY (i.e. allow third-party apps to decide - whether a window is on all workspaces). Bug found by Ka-Hing - Cheung. Closes #557536. - - * src/core/window.c (set_net_wm_state): report it - * src/core/window.c (meta_window_client_message): set sticky - if we receive it - * src/core/window-props.c: set sticky if we find it - * src/core/atomnames.h: add _NET_WM_STATE_STICKY - -2008-10-22 Thomas Thurman - - * src/core/schema-bindings.c: support builds outside tree properly. - * src/Makefile.am: ditto. - * po/POTFILES.skip: ditto. - -2008-10-22 Thomas Thurman - - * configure.in: Post-release bump to 2.25.5. - -2008-10-22 Thomas Thurman - - * NEWS: 2.25.3 release. - -2008-10-22 Thomas Thurman - - * configure.in: bump to 2.25.3 (thought the release script - had already done this) - -2008-10-22 Thomas Thurman - - Fixes to make distcheck work again. - - * src/Makefile.am: include *-binding.h, and make the schema - building work when builddir != srcdir - * po/POTFILES.in (src/core/keybindings.): include *-binding.h - -2008-10-22 Götz Waschk - - * configure.in: add libm reference. Closes #557357. - -2008-10-22 Murray Cumming - - * doc/creating_themes/C/creating_metacity_themes.xml: - Fixed various tags to make this validate. - Bug #557337 - -2008-10-22 Thomas Thurman - - * NEWS: 2.25.2 release. - -2008-10-22 Thomas Thurman - - * NEWS: 2.25.2 release. - -2008-10-22 Thomas Thurman - - * NEWS: 2.25.2 release. - -2008-10-22 Joe Marcus Clarke - - * src/core/main.c (meta_finalize, sigterm_handler): new functions - * src/core/main.c (main): add sigterm_handler in case we receive - a SIGTERM. Closes #553980. - -2008-10-22 Matthew Martin - - * src/core/window.c (meta_window_set_demands_attention): minimised - windows are necessarily obscured. Closes #528927. - -2008-10-22 Thomas Thurman - - Slight transformation of the x-macros used in keybindings - to make them clearer: write handler names out in full - because the old suffix system was confusing to people - skim-reading, and switched the order of the last two - parameters so more would generally fit on a screen. - - * src/core/keybindings.c, src/core/schema-bindings.c - src/core/prefs.c: sympathy changes - * src/core/window-bindings.h, src/core/screen-bindings.h: - transformation as above - -2008-10-21 Christian Persch - - * src/Makefile.am: fix build when schemas are not installed. - Closes #557335. - -2008-10-21 Tomas Frydrych - - * src/core/screen-bindings.h: Fix off-by-one error. - * src/core/window-bindings.h: Fix off-by-one error. - Closes #557201. - -2008-10-18 Thomas Thurman - - During a discussion with Rodney Dawes about making life easier - for the translators, he pointed out that the short and long - forms of almost all the keybindings say much the same thing - in different words. I believe this is an unconscionable burden - to place on translators, and have therefore merged the short - and long descriptions into the short description. The long - is now a general explanation of the format, plus possibly a - notice about reversibility. Closes #469361, and should solve - the l10n issue previously mentioned. - - * src/core/keybindings.c: reflect changes in *-bindings.h - * src/core/schema-bindings.c: reflect changes in *-bindings.h - * src/core/prefs.c: reflect changes in *-bindings.h - * src/core/window-bindings.h: Add flags field, always the same - currently, so that it's the same as screen-bindings.h. - Also, lose ONLY_BOUND_BY_DEFAULT, since we already had a - rather more elegant way to perform the same effect. - And merge the long and short descriptions. - * src/core/screen-bindings.h (, item): Merge the long and - short descriptions. - -2008-10-17 Murray Cumming - - * configure.in: Call GNOME_DOC_INIT() so we can use the gnome-doc-utils - variables in our Makefile.am: - * doc/Makefile.am: - * doc/creating_themes/Makefile.am - * doc/creating_themes/C/creating_metacity_themes.xml: - Added this new DocBook document, converted from the HTML here - http://blogs.gnome.org/metacity/2008/05/30/themes/ - This will be installed for yelp and can be translated and hosted on - library.gnome.org. - -2008-10-15 Thomas Thurman - - Since Patrick Niklaus's checkin of 2008-08-14 dealt with windows with - no icons not using fallback icons, we don't need fallback icons. - - * src/ui/theme.h: remove fallback icons from struct. - * src/core/iconcache.c (meta_read_icons): don't look for fallbacks. - * src/*/ui.[ch] (meta_ui_get_fallback_icons): removed - * src/ui/theme-parser.c (typedef, parse_toplevel_element): don't - parse fallback specifications. - -2008-10-13 Thomas Thurman - - * po/POTFILES.in: add screen-bindings.h - -2008-10-13 Thomas Thurman - - * po/POTFILES.in: raw schemas is now .in.in - * po/LINGUAS: add Latin - -2008-10-12 Thomas Thurman - - Make the bindings in src/core/*-bindings.h generate - GConf schemas too. Note that there's an i18n issue - (documented in schema-bindings.c) which will be fixed - next checkin. - - * src/core/schema-bindings.c: major fixup to make it - ready for use as part of the actual build process. - * src/Makefile.am: added magic to make it call schema-bindings - after it builds it. - * src/core/window-bindings.h: added comments; - also, window menu was listed variously as alt-Space - and alt-Print; it should have been alt-Space. - * src/metacity.schemas.in.in: renamed from s/\.in$//, - sentinel added for the generated bindings, - warning at the top now untrue, and removed. - -2008-10-12 Thomas Thurman - - Fix annoying bug where alt-tab and friends would jump - backwards a space on initial movement. - - * src/core/screen-bindings.h: although reversed bindings - are necessarily reversible, don't set both bits in the - constant, or when we test for them we'll get confused. - -2008-10-12 Thomas Thurman - - An attempt to make life a little easier for our beloved translators; - this has the same behaviour as before, but removes over thirty - translation strings. - - * src/core/session.c (start_element_handler): all "attribute not found - on element" strings are identical - * src/ui/theme-parser.c (locate_attributes): allow attribute names to - be preceded with "!" (in the code) to show they're required. - (parse_aspect_ratio, parse_distance, parse_toplevel_element, - parse_style_element, parse_gradient_element, static, parse_border, - parse_style_set_element, parse_draw_op_element): use the new "!" - prefix for locate_attributes(), or in some cases just the identical - constant, for generating this error. - * src/ui/theme.c (check_state, meta_theme_validate): add - translator comments - * src/ui/resizepopup.c (update_size_window): add - translator comments - -2008-10-06 William Lachance - - Pass modified mouse button events down to panel windows - instead of dealing with them ourselves. Closes #554428. - - * src/core/display.c (prefs_changed_callback): don't grab mouse - buttons on panels - * src/core/window.c (meta_window_new_with_attrs): ditto - -2008-10-05 Thomas Thurman - - Second half of the switch to using x-macros for keybindings so that - we don't have lots of places with the same information which must - stay in the same order. This time it's screen bindings. - - * src/core/screen-bindings.h: New file, containing screen bindings. - * src/core/schema-bindings.c: added ability to output screen bindings. - * src/core/window-bindings.h: tiny tweak to comment - * src/core/keybindings.c: generate function prototypes using s-b.h; - several handlers modified to use ints rather than ints cast into - pointers, or renamed. - * src/include/prefs.h: generate names of bindings using s-b.h; - generate screen_handlers using s-b.h; - arguments to bindings are ints and not ints cast to pointers; - several handler functions renamed to consistent names. - * src/core/prefs.c (meta_prefs_set_num_workspaces, init_bindings): - generate screen_handlers using s-b.h; - generate screen_string_bindings using s-b.h (and add check for - null bindings in init_bindings to enable this simply). - -2008-10-05 Thomas Thurman - - * tools/ppa-magic.py: experimental tool for Launchpad upload - -2008-10-05 Thomas Thurman - - * metacity.doap: Havoc is an author; Thomas has an email address; - add a ton of release information going back to the early days, - although not right to the beginning. - -2008-09-26 Thomas Thurman - - * autogen.sh: not all versions of /bin/sh can handle this script, - so specify one. Also update the error message because we don't - use CVS these days. - -2008-09-20 Thomas Thurman - - * po/POTFILES.in: fix name of window-bindings.h - -2008-09-20 Thomas Thurman - - * po/POTFILES.in: added new files and re-sorted - -2008-09-12 Vincent Untz - - Install desktop files in both - .../share/applications and .../share/gnome/wm-properties. - Copied in from the 2.23.x branch. Closes #549479. - - * src/metacity-wm.desktop.in: new file - * src/.cvsignore: include the above - * src/Makefile.am: install the above - -2008-09-06 Thomas Thurman - - An attempt to keep all information about window bindings - in the same place. Screen bindings to come. - - * src/core/window-bindings.h: new file, list of all window bindings - * src/include/prefs.h: drop all the existing window-binding macros - - * src/core/schema-bindings.c (): output all the schema blocks that - would appear in metacity.schema for these window bindings. This - ought to become part of the build process, and hopefully will soon. - When this works it will also close #469361. - - * src/core/keybindings.c: generate handle_* prototypes using - x-macros; populate window_handlers using x-macros; rename several - functions to have consistent names; do_handle_move_to_workspace(), - handle_move_to_workspace_flip(), and handle_move_to_workspace() all - merged into handle_move_to_workspace. - - * src/core/prefs.c: generate window_bindings and window_string_bindings - using x-macros; (meta_prefs_set_compositing_manager) fix unrelated - problem with use of GConf functions when GConf was disabled. - - * src/core/core.c (meta_core_get_menu_accelerator): binding names - given as literals since this is the only place in the code they - now appear - - -2008-09-03 Thomas Thurman - - * src/metacity.desktop.in: removed invalid "Window Manager" group - at request of Matthias Clasen. - -2008-09-02 Thomas Thurman - - Desktop file moved, according to policy change. Closes #549479. - - * src/metacity.desktop.in: Don't display the desktop file - * src/Makefile.am: Desktop file goes in apps directory - -2008-09-01 Thomas Thurman - - * configure.in: Post-release bump to 2.25.2. - -2008-09-01 Thomas Thurman - - * NEWS: 2.25.1 release. - -2008-09-01 Thomas Thurman - - * src/core/workspace.c: When a workspace's list of struts - is freed, free the struts too. Closes #549952, and #468075. - -2008-09-01 Thomas Thurman - - Add new move_to_center keybinding, requested by Khanh-Dang Nguyen - Thu Lam; closes #549979. - - * src/include/prefs.h (void): add name of new binding - * src/core/prefs.c: added pref for it - * src/core/keybindings.c (handle_move_to_center): new function - * src/metacity.schemas.in: included new binding - -2008-08-31 Thomas Thurman - - * src/core/prefs.[ch] (meta_prefs_set_compositing_manager): new - function. - * src/core/main.c (meta_parse_options): turn the compositing - manager on or off as necessary. - -2008-08-30 Thomas Thurman - - * src/core/window.c (process_property_notify): moving all - messages about properties to the top, as a start at #549886 - -2008-08-18 Thomas Thurman - - * NEWS: fix version number which broke - -2008-08-18 Thomas Thurman - - * configure.in: Post-release version bump to 2.25.1. - -2008-08-18 Thomas Thurman - - * configure.in: correct incorrect version number - -2008-08-18 Thomas Thurman - - * NEWS: 2.25.1 release. - -2008-08-18 Thomas Thurman - - Adding doxygen headers to some files. - - * src/core/metacity-Xatomtype.h - * src/core/main.c - * src/core/screen-private.h - * src/core/window-private.h - * src/core/keybindings.h - * src/core/session.h - * src/core/workspace.h - * src/core/window-props.h () - -2008-08-18 Eric Piel - - * src/core/workspace.c (ensure_work_areas_validated): add a copy of - each strut in a window to the workspace's strut list, instead of - using the copy in the list (which would mean it was double-freed). - Believed to fix #468075. - -2008-08-16 Ted Percival - - Ensure the user_rect is set sanely for windows that start maximized. - Prevents maximized windows from warping across the screen. - Fixes bug #504692. - - * src/core/window.c (save_user_placement): renamed version of - meta_window_save_user_rect(). - * src/core/window.c (force_save_user_placement): similar, but will - always save user_rect even if the window is maximised or fullscreen. - * src/core/window.c (meta_window_move_resize_internal): unplaced - windows have force_save_user_placement() called instead of - save_user_placement(). - -2008-08-14 Patrick Niklaus - - Icons for windows are taken from the desktop theme, not from - the Metacity theme or from the fallback icon that Metacity - provided. Closes #524343. - - * src/ui/ui.c: Use GtkIconTheme to load the default window icon. - Assumes the existence of an icon called "window", otherwise - falls back to "gtk-missing-image". Fixes #524343. - * src/ui/preview-widget: See above. - * src/include/common.h: Add META_DEFAULT_ICON_NAME. - * src/Makefile.am: Remove default_icon.png from inlinepixbufs.h. - * src/default_icon.png: Removed. - -2008-08-14 Akira TAGOH - - * doc/man/metacity-message.1: new manual page. - * doc/man/Makefile.am: added new reference. - -2008-08-13 Thomas Thurman - - * configure.in: Post-branch bump to 2.25.0. - -2008-08-04 Thomas Thurman - - * configure.in: Post-release bump to 2.23.144. - -2008-08-04 Thomas Thurman - - * NEWS: 2.23.89 release. - -2008-07-26 Thomas Thurman - - * metacity.doap (added): DOAP file (first pass, anyway). - -2008-07-14 Thomas Thurman - - * configure.in: Post-release bump to 2.23.89. - -2008-07-14 Thomas Thurman - - * NEWS: 2.23.55 release. - -2008-07-13 Thomas Thurman - - * src/core/display.c (event_callback): meta_display_screen_for_root() - can return NULL, so check for that. Fixes #422242. Also tidying. - -2008-07-13 Elijah Newren - - * src/core/workspace.c (meta_workspace_free): Don't attempt to - double-free struts, edges and regions if work areas have already - been invalidated at the time of freeing a workspace. - Possible fix to #361804. - -2008-07-12 Thomas Thurman - - * src/core/constraints.c (do_screen_and_xinerama_relative_constraints): - Don't allocate memory for log messages unless we're logging. - -2008-07-12 Thomas Thurman - - * src/core/group.c (meta_window_get_group): This function can now - officially return NULL. - * src/core/window.c (meta_window_same_application): Two windows can't - belong to the same application unless they both belong to some - application. (Both belonging to no application is not the same.) - -2008-06-30 Thomas Thurman - - * src/core/bell.c (meta_bell_set_audible): Fix typo that - slipped through. - -2008-06-30 Thomas Thurman - - * src/core/bell.[ch]: Move comments for non-statics from the .c to .h. - * Doxyfile: adapt better for C, and make quiet. - -2008-06-29 Thomas Thurman - - * src/ui/theme-viewer.c (main): display the theme name - in the title bar. Closes #430198. - -2008-06-29 Thomas Thurman - - Allow toggling of non-compositor effects (since there's a - non-Metacity key to do so: /desktop/gnome/interface/enable_animations). - Closes #92867. - - * src/include/prefs.h: add META_PREFS_GNOME_ANIMATIONS key and - meta_prefs_get_gnome_animations() function - * src/include/prefs.c: added meta_prefs_get_gnome_animations() - function, and made supporting changes to structs. - * src/core/effects.c (run_handler): checked whether enable_animations - is set before running an effect. - * src/core/effects.c (meta_effect_run_minimize): remove debug message. - -2008-06-29 Thomas Thurman - - * src/core/bell.c: remove meta_ prefix on all static functions. - -2008-06-29 Thomas Thurman - - * src/core/stack.c (stack_sync_to_server): lose meta prefix - since it's static. - * src/core/stack.c (meta_stack_remove, stack_do_window_deletions): - replace our own cast with glib macro designed to do the same thing - -2008-06-28 Thomas Thurman - - * src/core/display.c, src/compositor/compositor-xrender.c: add checks - for HAVE_SHAPE where appropriate. - * src/core/xprops.c: fix type error which was causing warnings. - -2008-06-28 Thomas Thurman - - Some refactoring, simplifying, and commenting of the non-composited - effects code. effects.c could still do with some polish, which will - come along later. - - * src/core/effects.h (meta_push_effect_handler): removed since it's - never used and does nothing very useful. - * src/core/effects.h (meta_pop_effect_handler): removed since its - only effect is to crash the program. - * src/core/effects.h (META_MINIMIZE_ANIMATION_LENGTH, - META_SHADE_ANIMATION_LENGTH): move to effects.c because they're used - nowhere else. - * src/core/effects.c: there were three versions of the box-zoom effect. - Remove the one which was never used, and make only the ones which - are used with certain configure settings be compiled. - * src/core/effects.h (meta_effect_end): move to effects.c, make static, - and rename to effect_free. - * src/core/effects.h (meta_effects_draw_box_animation): move to - effects.c, make static, and rename to draw_box_animation. - * src/core/effects.h (MetaEffectType): remove the values which weren't - used. - * src/core/window.c (meta_window_shade): remove commented-out code to - call effect for shading. - * src/core/effects.h (MetaEffectFinish): remove useless MetaEffect - parameter. - * src/core/window.c (finish_minimize): remove MetaEffect parameter. - -2008-06-27 Thomas Thurman - - * src/core/stack.h: Commented everything. - -2008-06-26 Thomas Thurman - - Keep the compiler from giving some warnings. - - * src/compositor/compositor-xrender.c (xrender_begin_move, - xrender_update_move, xrender_end_move, xrender_free_window): four - functions which were never called and contain no code #iffed out. - * src/tools/metacity-mag.c (grab_area_at_mouse): fixed typecast error. - -2008-06-26 Thomas Thurman - - Refactor so the long scary stack functions are less long and scary: - - * stack.c (stack_ensure_sorted): the five parts of this long function - broken out into the new functions stack_do_window_deletions, - stack_do_window_additions, stack_do_relayer, stack_do_constrain - (which was already separate: see next) and stack_do_resort. - * stack.c (constrain_stacking): renamed to stack_do_constrain. - * stack.c (stack_ignore_sorted): lose meta prefix since it's static. - -2008-06-16 Thomas Thurman - - * configure.in: Post-release bump to 2.23.55. - -2008-06-16 Thomas Thurman - - * NEWS: 2.23.34 release. - -2008-06-16 Thomas Thurman - - * NEWS: 2.23.34 release. - -2008-06-13 Thomas Thurman - - * src/core/window-props.c: Some commenting. - - * src/core/prefs.c: Added unified handling of integer preferences. - Re-ordered fields in existing preferences so that changing to - a union-based system will be easier in the future. - -2008-06-10 Thomas Thurman - - * test/tokentest/tokentest.c (draw_string_to_spec): doubles are - %f or %g, not %d - * test/tokentest/tokentest.ini: re-created fair copy accordingly - -2008-06-10 Thomas Thurman - - * test/tokentest: A preliminary attempt at a test for the - theme expression tokeniser. - -2008-06-05 Thomas Thurman - - * src/compositor/compositor-xrender.c (paint_root, destroy_win, - create_root_buffer, paint_windows, repair_screen, window_has_shadow, - xrender_set_active_window, paint_dock_shadows, unmap_win, restack_win, - make_shadow, resize_win, process_property_notify, free_win, - process_configure_notify, process_circulate_notify, add_damage): - defensive programming; check meta_screen_get_compositor_data() - throughout in case it returns NULL. In particular, when this - happened in a certain situation in xrender_set_active_window - this caused a segfault; refs #530702 (and LP#178953 has more data) - but this doesn't close them. - -2008-06-02 Thomas Thurman - - * NEWS: 2.23.34 release. - -2008-06-02 Thomas Thurman - - * src/core/display.c: make sure compositor things don't get - compiled when we're not using the compositor. - -2008-06-02 Thomas Thurman - - * test/metacity-test: new test script, imported from - branch. - -2008-05-30 Thomas Thurman - - * src/core/window-props.h: fix comments (number) - -2008-05-30 Thomas Thurman - - * src/core/window-props.h: commenting - -2008-05-28 Thomas Thurman - - * src/core/prefs.c (handle_preference_update_string, - meta_prefs_remove_listener, queue_changed): Make disabling - gconf work again. Closes #530870. - -2008-05-26 Thomas Thurman - - * configure.in: Post-release bump to 2.23.34. - -2008-05-26 Thomas Thurman - - * NEWS: 2.23.21 release. - -2008-05-26 Thomas Thurman - - * src/Makefile.am: added in two files needed for Iain's - changes earlier to work in a release tarball - -2008-05-24 Iain Holmes - - * src/compositor/compositor-xrender.c: Add Dropdown menu atoms so we - can add shadows to them. Fixes #517442 - Handle tooltips as well. Fixes #517524 - -2008-05-24 Iain Holmes - - * src/compositor/compositor.c: Check the compositor isn't NULL before - dereferencing it. Fixes #534569 - (meta_compositor_get_window_pixmap): Actually return a value - -2008-05-19 Iain Holmes - - * src/core/window.c: Applied patch from Ed Catmur to fix #528787 - -2008-05-19 Iain Holmes - - * src/include/frame.h - * src/include/display.h - * src/include/xprops.h - * src/include/compositor.h - * src/include/types.h - * src/include/window.h - * src/include/errors.h - * src/include/screen.h: New basic public API for compositor. - - * src/compositor/*: Separate the compositor out into its own separate - directory and set it up for backends. Initial XRender backend. - - * src/core/compositor.[ch]: Remove - - * src/core/frame.h - * src/core/screen.h - * src/core/display.h - * src/core/window.h: Rename to -private.h so as not to clash with the - new files in include - - * src/core/delete.c - * src/core/workspace.h - * src/core/stack.[ch] - * src/core/keybindings.[ch] - * src/core/errors.c - * src/core/effects.[ch] - * src/core/core.c - * src/core/group.h - * src/core/edge-resistance.[ch] - * src/core/window-props.[ch] - * src/core/constraints.h - * src/core/bell.[ch] - * src/core/iconcache.h - * src/core/session.[ch] - * src/core/main.c - * src/core/place.h - * src/core/xprops.c - * src/ui/tabpopup.c: Use the new -private headers - - * src/core/display.c - * src/core/frame.c - * src/core/window.c - * src/core/screen.c: Add the API functions required by the compositor - - * src/Makefile.am: Relocate the new files - -2008-05-13 Robert Escriva - - * src/ui/theme.h (struct): remove color_set flag - * src/ui/theme.c (meta_color_spec_render, - meta_color_spec_new_from_string): remove check of color_set flag - before rendering (we always do it now). Closes #511826. - -2008-05-12 Thomas Thurman - - * tools/xlib.py: Basic Python-based Xlib client for testing - and building upon. - -2008-05-09 Elijah Newren - - * src/ui/color.[ch]: - Remove these two unused files - -2008-05-04 Thomas Thurman - - Added curly brackets in two places to keep -pedantic happy. - - * src/core/window-props.c (meta_display_init_window_prop_hooks) - * src/core/group-props.c (meta_display_init_group_prop_hooks) - -2008-05-03 Matt Krai - - * src/core/delete.c (io_from_ping_dialog): fix type of "len" variable - (refs #526049) -2008-05-02 Thomas Thurman - - All information should live in exactly one place. This means - that the list of atoms should not be replicated anywhere. - Therefore, we include it via x-macros. Closes #530843. - - * src/core/atomnames.h: added list of atom names - * src/Makefile.am: added reference to new file - * src/core/display.h - * src/core/display.c (twice) - * src/core/screen.c: #included atomnames.h instead of having - an enormous list of atoms - * src/core/group-props.c - * src/core/window.c - * src/core/compositor.c - * src/core/window-props.c - * src/core/delete.c - * src/core/workspace.c - * src/core/stack.c - * src/core/keybindings.c - * src/core/iconcache.c - * src/core/group.c - * src/core/xprops.c: changed to new, simpler identifiers - for atoms - -2008-04-29 Chris Wang - - * src/core/window.c (meta_window_new): XGetWindowAttributes - can return an error value, and if it does its other results - are invalid! (#530485) - -2008-04-29 Thomas Thurman - - * src/ui/fixedtip.[ch]: documentation - -2008-04-27 Thomas Thurman - - * configure.in: Post-release bump to 2.23.21. - -2008-04-27 Thomas Thurman - - * NEWS: 2.23.13 release. - -2008-04-27 Erwann Chenede - - * src/core/place.c (meta_window_place): re-enable cascade - code which was wrongly removed a year ago. Closes #529925. - -2008-04-22 Carlos Garnacho - - * src/core/compositor.c (process_property_notify, - find_window_in_display): Propagate opacity to frame window. - -2008-04-22 Thomas Thurman - - * configure.in: Post-release bump to 2.23.13. - -2008-04-22 Thomas Thurman - - * NEWS: 2.23.8 release. - -2008-04-22 Thomas Thurman - - * configure.in: Post-release bump to 2.21.8. - (Which was seriously belated. Sorry, folks.) - -2008-04-22 Thomas Thurman - - * src/core/effects.c: a few comments - -2008-04-10 Lucas Rocha - - * src/Makefile.am: no need to create a symlink to .desktop file in - default-session directory anymore as gnome-session will find - metacity's .desktop in its original place. - -2008-04-07 iain - - * src/core/compositor.c (hide_overlay_window): Hide the overlay window - (meta_compositor_unmanage_screen): Release the compositor overlay. - (#526770) - -2008-04-07 Jens Granseuer - - * src/core/session.c: (save_state), - (warn_about_lame_clients_and_finish_interact): - reorder declarations so we don't break C89 compilers. - -2008-04-06 Thomas Thurman - - * NEWS: 2.23.5 release. - -2008-04-03 Thomas Thurman - - * src/core/prefs.c (handle_preference_update_bool): preferences - which have a null target don't get updated! (#526016) - -2008-03-29 Lucas Rocha - - * src/metacity.desktop.in, src/Makefile.am: make Metacity - install its desktop files in the default session directory - as required by the new gnome-session. (Closes #525051.) - -2008-03-29 Thomas Thurman - - * src/ui/preview-widget.c (meta_preview_get_clip_region): - prevent null dereference if the theme was invalid, which - caused crashes in gnome-appearance-properties. No GNOME - bug number, but I believe this is a fix for Launchpad bug - #199402 and its many duplicates. - -2008-03-28 Owen Taylor - - * src/core/window.c (meta_window_new_with_attrs): Don't - immediately unminimize an initially iconic window (#491090) - -2008-03-27 Thomas Thurman - - * src/core/session.c (regenerate_save_file, save_state, load_state): - files are saved in ~/.config/metacity/sessions and checked for there - and in ~/.metacity/sessions. Fixes #518596. - -2008-03-27 Thomas Thurman - - * src/core/display.c (meta_display_close): fix regression - where Metacity sometimes wouldn't quit when replaced - -2008-03-26 Thomas Thurman - - * src/core/display.c (event_callback): meta_display_screen_for_root - is quite capable of returning NULL. - -2008-03-25 Thomas Thurman - - * src/core/display.c (meta_display_queue_retheme_all_windows, - meta_set_syncing, meta_display_set_cursor_theme, disable_compositor, - meta_display_for_x_display, meta_display_open, meta_display_close, - meta_display_ungrab): MetaDisplay becomes a singleton. The static - variable which holds this singleton is renamed "the_display" so as - not to mask the this parameter in the methods. - - * src/core/main.c (main): - * src/core/session.c (warn_about_lame_clients_and_finish_inte, - save_state, io_from_warning_dialog): - * src/core/core.c (meta_core_increment_event_serial): - * src/core/delete.c (release_window_with_fd, search_and_destroy_window): - sympathy changes for this, and consequent simplification. - Closes #499301. - -2008-03-21 Thomas Thurman - - * configure.in: Post-release bump to 2.23.5. - -2008-03-21 Thomas Thurman - - * NEWS: 2.23.3 release. - -2008-03-21 Thomas Thurman - - * src/ui/menu.c (activate_cb, get_workspace_name_with_accel): Workspaces - whose name is the standard name plus a non-empty string are handled - correctly in menus. Closes #453678. - -2008-03-19 Iain Holmes - - * src/core/compositor.c (meta_compositor_set_active_window): Handle - compositor being disabled and don't crash. - -2008-03-19 Iain Holmes - - * src/core/compositor.c (meta_compositor_set_active_window): Add a - screen argument. - (process_property_notify): Damage the whole screen when the background - changes. Fixes 522599 - (add_repair): Use the idle instead of the timeout. Fixes 522166 - (unmap_win): If the window is also focus window NULLify it. - - * src/core/window.c (meta_window_notify_focus): Notify when a window - has lost focus, pass in screen as well. - -2008-03-18 Iain Holmes - - * src/core/compositor.c (window_has_shadow): Allow shaped windows - _with frames_ to have shadows. - (meta_compositor_set_active_window): Watch for the focus of windows - and change the size of the drop shadows. - (generate_shadows): Create differently sized shadows. - (meta_compositor_get_window_pixmap): Get the xwindow correctly. - - * src/core/window.c (meta_window_notify_focus): Set the active window - in the compositor. - -2008-03-18 Marco Pesenti Gritti - - * src/core/window.c (window_would_be_covered): newly created windows - can't be considered to be above themselves; fixes bug #519188. - -2008-03-11 Matthew Wilson - - * src/core/keybindings.c (meta_display_process_key_event, process_event, - find_handler, process_mouse_move_resize_grab): allow moving workspace - while moving window with modifier - * src/core/workspace.c (meta_workspace_activate_with_focus): remove the - correct window on jumping workspace while moving - -2008-03-10 Josh Lee - - * src/core/compositor.c (window_has_shadow): Don't shadow - shaped windows. - -2008-03-07 Thomas Thurman - - * configure.in: Post-release bump to 2.23.3. - -2008-03-07 Thomas Thurman - - * NEWS: 2.23.2 release. - -2008-03-07 Thomas Thurman - - * src/core/prefs.c (mouse_button_mods_handler): remove - debug statements (*blush*) - -2008-03-06 Thomas Thurman - - * configure.in: Post-release bump to 2.23.2. - -2008-03-06 Thomas Thurman - - * NEWS: 2.23.1 release. - -2008-03-06 Thomas Thurman - - * tools/release-wrangler.py: basic md5 printing (not used yet); - also print release announcements to stdout (eventually will - need to be emailed to release list and blogged) - -2008-03-06 Thomas Thurman - - Part three of the great prefs refactor, this time - dealing with string preferences. (This was the most - complicated part, and has been especially tested and - valground before committing. As ever, though, let us - know if you find a problem.) - - * src/core/prefs.c (MetaStringPreference): new struct. - * src/core/prefs.c (update_*): replaced with *_handler - * src/core/prefs.c (meta_prefs_init): uses new string prefs - init; uses array of gconf dirs to monitor rather than - repeating code. - * src/core/prefs.c (handle_preference_init_enum): tidying - * src/core/prefs.c (change_notify): uses new string prefs - -2008-03-04 Thomas Thurman - - * MAINTAINERS: added some spacing to see whether it - helps Pulse - -2008-03-03 Cosimo Cecchi - - Add ability to vertically and horizontally maximise - using the mouse, by clicking the titlebar in various - ways. A very similar patch was received from Jason Ribero. - Thanks also go to Tony Houghton and Carlo Wood, who - both submitted patches which solved this differently. - Closes #358674. - - * src/include/common.h (MetaActionTitlebar): new values - for the new actions - * src/core/core.c (meta_core_maximize_{vertic|horizont}ally): - new functions. - * src/ui/frames.c (meta_frame_titlebar_event): handle the - new action values - * src/core/window.h: new macros (for regularity, not really - necessary) - * src/core/prefs.c (symtab_titlebar_action): new string - representations of the action values - * src/metacity.schemas.in: documentation - -2008-02-29 Andrea Del Signore - - Add support for "spacer" as a button type which adds some - empty space. Closes #509165. - - * src/ui/theme.c (meta_frame_layout_calc_geometry), - src/include/common.h (MetaButtonLayout), - src/core/prefs.c (update_button_layout, button_layout_equal), - src/metacity.schemas.in: add spacer support - -2008-02-28 Thomas Thurman - - * src/core/compositor.h: removed unnecessary #include which - should have been in Jim's patch (not sure how it slipped - through the tests!) - -2008-02-27 Jim Huang - - * src/core/spring-model.[ch]: deleted as no longer used - * src/Makefile.am: modified accordingly - -2008-02-27 Thomas Thurman - - Lots of tiny fixes to make sure we compile with - "gcc -ansi -Werror". - -2008-02-26 Jens Granseuer - - * src/core/constraints.c (constrain_aspect_ratio, - constrain_size_limits, constrain_size_increments): - reorder declarations so we don't break C89 compilers. - Closes #518917. - -2008-02-26 Thomas Thurman - - * configure.in: Post-release bump to 2.23.1. - -2008-02-26 Thomas Thurman - - * NEWS: 2.23.0 release. - -2008-02-26 Thomas Thurman - - * tools/release-wrangler.py: ANY post-release bump is now the - most recent, not just the one that matches the current version. - Otherwise, you can't use these tools straight after a branch. - The changeset before this one was mislabelled because of this. - It has now been excised from the changelog. - -2008-02-25 Thomas Wood - - * src/ui/preview-widget.[ch] (meta_preview_get_clip_region): - allow users of the preview widget to get a mask for windows - in the correct shape for the current theme. - -2008-02-23 Thomas Thurman - - Refactor handling of boolean preferences. - - * src/core/prefs.c (handle_preference_init_bool, - handle_preference_update_bool): new functions. - * src/core/prefs.c (meta_prefs_init, change_notify): - use the new functions. - * src/core/prefs.c (update_*): several of these removed whose - only purpose was to receive boolean preferences. - * src/core/prefs.c (cleanup_error, get_bool): moved down to make - the flow of ideas more obvious. - * src/core/prefs.c (maybe_give_disable_workarounds_warning): new - function containing duplicated code from elsewhere. - * src/core/prefs.c (init_button_layout): only compiled when - HAVE_GCONF is not defined. Removed a compiler warning. - -2008-02-23 Thomas Thurman - - * tools/commit-wrangler.py: Print URL of changeset on success. - -2008-02-23 Thomas Thurman - - Refactored handling of enumerated preferences. - - * src/core/prefs.c (handle_preference_init_enum, - handle_preference_update_enum): new functions. - (meta_prefs_init, change_notify): use regularised - forms and remove old copy-and-pasted code. - Also many small similar functions removed which - only existed to deal with each kind of enum. - Also some amount of correction of which parts were - and weren't inside "#ifdef HAVE_GCONF" blocks. - - -2008-02-21 Mikkel Kamstrup Erlandsen - - * src/core/constraints.c: Respect requested position on - _NET_MOVERESIZE_WINDOW. Closes #448183. - -2008-02-18 Matthias Clasen - - * src/core/window.h: Make skip-taskbar windows appear in the - Ctrl-Alt-Tab list. Closes #106249. - -2008-02-18 Thomas Thurman - - * configure.in: if we have libSM and its headers, - that means we did find it, not that we didn't. - Closes #328210. - -2008-02-18 Thomas Thurman - - * src/core/window.c (warp_grab_pointer): When - resizing a window with the keyboard, stay one - pixels from the edges so that the cursor remains - resting on a window edge even if we escape, - whatever side it was on. Closes #436257. - -2008-02-17 Thomas Thurman - - * tools/commit-wrangler.py: added new script to manage commits - -2008-02-17 Jim Huang - - * src/core/prefs.c (update_binding): Allow compilation - when gconf mode is disabled. Closes #515019. - -2008-02-14 Jim Huang - - * src/core/display.c, src/core/util.c: fixups to allow - compilation in non-verbose mode. Closes #515152. - -2008-02-12 Thomas Thurman - - * configure.in: Correct help for verbose option name. - -2008-02-12 Thomas Thurman - - * configure.in: Post-branch bump to 2.23.0. - -2008-02-12 Thomas Thurman - - * configure.in: Post-release bump to 2.21.21. - -2008-02-11 Thomas Thurman - - * NEWS: 2.21.13 release. - -2008-02-04 Thomas Thurman - - * src/core/compositor.c: only use compositor version if - we have a compositor. Closes #514453. - -2008-02-04 Thomas Thurman - - * configure.in, src/ui/ui.c: remove workaround for a problem - in GTK 1.3.9(!) which was causing problems. Closes #513737. - -2008-01-28 Michael Meeks - - * src/core/display.c (meta_display_open), - * src/core/compositor.c: fetch & use composite - version, for remote screens that don't match the - compile system's version. - (meta_compositor_manage_screen): bin erroneous FIXME. - (add_win): remove common warning churn for (very) - transient windows - -2008-02-03 Thomas Thurman - - * tools/patch-wrangler.py: another program I use for maintenance - which other people might find useful and which should probably - be in svn. Also not very polished. - -2008-02-03 Thomas Thurman - - * test/tokentest/tokentest.c, test/tokentest/tokentest.ini: added - new files for a regression test on the tokeniser. (They aren't very - polished at the moment and aren't included in the autotools build.) - -2008-02-03 Thomas Thurman - - * configure.in: Post-release bump to 2.21.13. - -2008-02-03 Thomas Thurman - - * NEWS: 2.21.8 release. - -2008-02-03 Thomas Thurman - - * tools/release-wrangler.py: Fix quoting error and added some - more error checking. - -2008-02-03 Thomas Thurman - - * tools/release-wrangler.py: basic release script; needs work, - but probably good enough for the current unstable release - -2008-02-02 Thomas Thurman - - * src/Makefile.am: core.h is in include, not core. (Last one, I - promise.) - -2008-02-02 Thomas Thurman - - * src/Makefile.am: main.h is in include, not core. - -2008-02-02 Thomas Thurman - - * src/Makefile.am: draw-workspace.h is in ui, not core. - -2008-02-01 Alex R.M. Turner - - * src/core/display.c (meta_get_tab_entry_list): Have the list also pull - windows that are in other workspaces that have the - wm_state_needs_attention flag set - * src/core/window.c (meta_window_set_demands_attention): Make windows that - are on other workspaces that demand attention that aren't obscured - count as being obscured - Bug #333548. - -2008-01-28 Christian Persch - - * src/core/display.c (convert_property): - * src/core/screen.c (meta_screen_calc_workspace_layout): - * src/core/xprops.c (meta_prop_get_values): - Use G_STRFUNC instead of the deprecated G_GNUC_FUNCTION. - Bug #512561. - -2008-01-21 Thomas Thurman - - * src/ui/theme.[ch]: more commenting. - -2008-01-18 Thomas Thurman - - * src/ui/theme.[ch]: some more commenting. - -2008-01-16 Thomas Thurman - - * src/core/bell.c: Correct comment. - * src/core/main.c: Correct comment. - * src/ui/theme.c: Much commenting; #ifdeffed-out - debug code removed. - * src/ui/theme.h: Much commenting. - -2008-01-13 Thomas Thurman - - * src/core/bell.c: Commenting. - * src/core/main.c: Commenting, and fixing existing comments. - -2008-01-12 Thomas Thurman - - * src/core/main.c: Refactor repeated lines in main() to - iterate instead. - -2008-01-12 Thomas Thurman - - * src/core/main.[ch] (meta_get_main_loop): removed as it - was never used. - * src/core/main.c: lots of comments. - * src/core/main.c (version): copyright year is 2008. - * src/core/c-screen.[ch], src/core/c-window.[ch]: removed - files from Søren's compositor which were removed by the - merge with Iain's compositor but reintroduced by the split - to separate subdirectories. - * src/core/display.c: fix comments. - -2008-01-12 Thomas Thurman - - * src/core/display.c: reinstated missing first character! - * Doxyfile: correct reordering of blank fields. - -2008-01-12 Thomas Thurman - - * src/core/display.c: change comments from /*! to /** because the - other way makes doxygen think they are Qt comments, which messes - up brief descriptions. - * Doxyfile: check in so other people can generate documentation - too. - -2008-01-07 Thomas Thurman - - * src/core/display.c: further commenting (trying to keep comment - addings down to once a day at most so you don't all get spammed - too much). - -2008-01-07 Thomas Thurman - - * src/core/main.c (main): g_free is a no-op on nulls; there is no - need to test. - -2008-01-06 Thomas Thurman - - * src/core/display.c: Function commenting marathon; more to come. - -2008-01-02 Thomas Thurman - - * src/core/xprops.c (meta_prop_get_cardinal), src/core/compositor.c - (timeout_debug): Two really minor coding standards layout tweaks. - -2007-12-27 Iain Holmes - - * src/core/compositor.c: Don't do anything in - meta_compositor_free_window, it doesn't seem to be needed and breaks - things very badly. http://bugzilla.gnome.org/show_bug.cgi?id=504876 - -2007-12-27 Iain Holmes - - * src/core/compositor.c: When a window is mapped, don't set damaged to - TRUE. Fixes a bug when redrawing shadows. - -2007-12-25 Iain Holmes - - * src/core/compositor.c: USe the compositor overlay window instead of - the root window. - -2007-12-21 Paolo Borelli - - * src/core/core.c (meta_invalidate_default_icons): do not leak list. - - * src/core/edge-resistance.c - (meta_display_compute_resistance_and_snapping_edges): ditto. - - * src/core/workspace.c (meta_workspace_index): small cleanup in list - handling. - -2007-12-19 Havoc Pennington - - * src/core/display.c (meta_display_open): fix a third warning - about %d and long int - - * src/core/delete.c (io_from_ping_dialog): fix another warning - about long int to %d - - * src/core/compositor.c (meta_compositor_new): fix a warning about - long int to %d - - * src/core/iconcache.c (meta_read_icons): use - meta_ui_get_fallback_icons() instead of incorrectly including theme.h - - * src/ui/ui.c (meta_ui_get_fallback_icons): new function - -2007-12-19 Havoc Pennington - - * src/ui, src/core, src/include: sort source files into these - directories according to which part of the WM they are supposed to - be in. In an eventual plan, we should also create - src/compositor/render, src/compositor/fallback and move some of - the compositor stuff into that. - - * autogen.sh: require a newer automake, so we don't have to use - a recursive build - - * src/ui/tabpopup.c: put in a hack to make the build temporarily - work, want to commit the large rearrangement before fixing this - not to include workspace.h or frame.h - - * src/core/iconcache.c (meta_read_icons): temporarily break this - to get the build to work, want to commit the large rearrangement - before fixing this file not to include theme.h - -2007-12-19 Thomas Thurman - - * configure.in: Post-release bump to 2.21.8. - -2007-12-19 Thomas Thurman - - * NEWS: 2.21.5 release. - -2007-12-19 Thomas Thurman - - * configure.in: print "Subversion" and not "CVS". - -2007-12-18 Thomas Thurman - - * configure.in: compositor enabled by default. - -2007-12-18 Iain Holmes - - * configure.in, src/theme.c, src/display.c, - src/theme.h, src/display.h, src/theme-parser.c, - src/compositor.c, src/c-screen.c, src/compositor.h, - src/c-screen.h, src/ui.c, src/screen.c, src/ui.h, - src/screen.h, src/c-window.c, src/c-window.h, - src/theme-viewer.c, src/Makefile.am: Merge compositor branch. - -2007-12-14 Thomas Thurman - - * configure.in: Post-release bump to 2.21.5. - -2007-12-14 Thomas Thurman - - * NEWS: 2.21.3 release. - -2007-12-11 Thomas Thurman - - * src/theme-parser.c: remove dead code; closes #501365. - -2007-12-08 Thomas Thurman - - * src/metacity.schemas.in: rewrite long description of - /schemas/apps/metacity/general/focus_new_windows because we - love the translators really. Closes #474889. - -2007-12-08 Matthias Clasen - - * src/menu.c (meta_window_menu_new): check for null before adding - menu; closes #496054. - -2007-12-08 Thomas Thurman - - * src/keybindings.c (meta_display_process_key_event): Recur if the - keypress ended a grab, so it can be processed in its own right. - Closes #112560. - -2007-12-08 Martin Meyer - - * src/theme-parser.c (parse_draw_op_element): Fix - typo where wrong variable was checked (reported by - Kjartan Maraas). Closes #501362. - -2007-11-19 Lucas Rocha - - * src/main.c (main): try to get the session client ID from - DESKTOP_AUTOSTART_ID environment variable in case the --sm-client-id - is not used. Closes #498033. - -2007-11-17 Thomas Thurman - - * configure.in: Post-release bump to 2.21.3. - -2007-11-17 Thomas Thurman - - * NEWS: 2.21.2 release. - -2007-11-17 Benjamin Gramlich - - * src/theme-parser.c (meta_theme_load): make our theme - search compliant to the XDG Base Directory Specification. - Closes #480026. - -2007-11-15 Thomas Thurman - - * src/api.[ch]: remove almost-unused files. - * src/colors.[ch]: move the used parts of api.[ch] in here. - Closes #496947. - -2007-11-13 Peter Bloomfield - - * src/window.c: (meta_window_save_user_rect): new helper, saves - only unmaximized dimensions, and not when fullscreen. - (meta_window_move_resize_internal, - meta_window_move_resize_request): use it. (#461927) - -2007-11-11 Thomas Thurman - - * configure.in: Post-release bump to 2.21.2. - -2007-11-11 Thomas Thurman - - * NEWS: 2.21.1 release. - -2007-11-11 Thomas Thurman - - * src/window.c (meta_window_show): adjust expression which decides - whether new windows should not go on top, so that restacking happens - only the first time a window is mapped. Thanks to Olav Vitters for - pointing out the problem. Re-fixes #486445. - -2007-11-11 Alex R.M. Turner - - * src/tabpopup.c (tab_entry_new, meta_ui_tab_popup_new): Instruct the - GtkLabel in the tabpopup to ellipsize text that is too big. Set the - maximum window width of the tabpopup to screen_width/4, which seems a - sensible size for the popup. - -2007-11-09 Elijah Newren - - * src/window.c (meta_window_new_with_attrs): If a window is - launched without any kind of launch timestamp, grab the current - time and stash it away. When transients of that window are also - launched without a timestamp, we can use the stashed timestamp - from the parent. Fixes #488468. - -2007-11-07 Federico Mena Quintero - - * src/window-props.c (reload_net_wm_user_time_window): Fix typo; - the arguments to meta_window_reload_property_from_xwindow() were - reversed. This is why the wm_user_time wasn't getting initialized - properly from the _NET_WM_USER_TIME_WINDOW. Fixes part of - http://bugzilla.gnome.org/show_bug.cgi?id=488468 - -2007-11-06 Peter Bloomfield - - * src/window.c (meta_window_move_resize_internal): save - unmaximized part of client root coords. (#461927) - -2007-11-06 Peter Bloomfield - - * src/window.c (meta_window_move_resize_internal): do not save - client root coords while window is maximized. (#461927) - -2007-10-30 iain Holmes - - * src/main.c (meta_parse_options): Add --sync option - (main): Check if the --sync option was passed on command line. - -2007-10-28 Jans Granseuer - - * src/preview-widget.c (meta_preview_finalize): Free title of - preview when the preview is destroyed. Closes #469682. - -2007-10-27 Alex R.M. Turner - - * src/tabpopup.c (tab_entry_new): Truncate the string to - max_char_per_title before adding bold tags and fix general flow of - function. - -2007-10-16 Thomas Thurman - - * src/window.c (window_would_be_covered): new function. - * src/window.c (meta_window_show): rewrite assertion not - to put window on top in terms of window_would_be_covered(); - remove assertion because it's no longer valid; explicitly - don't focus windows that shouldn't be focussed; closes #486445. - -2007-10-14 Thomas Thurman - - * configure.in: Post-branch bump to 2.21.1. - -2007-10-03 Kjartan Maraas - - * configure.in: Remove circular dep metacity<->gnomecc. - -2007-09-15 Elijah Newren - - * configure.in: post-release version bump to 2.20.1 - -2007-09-15 Elijah Newren - - * configure.in: - * NEWS: - 2.20.0 release - -2007-09-15 Elijah Newren - - * src/session.c (warn_about_lame_clients_and_finish_interact): - Patch from Alexey Rusakov to prevent a crash on logout with - metacity subsequently not being restored in future sessions. - Fixes #433253. - -2007-09-01 Elijah Newren - - * HACKING: update; cvs->svn & mention GConf needed - * MAINTAINERS: Make it match idiotic format requirements (I love - you Olav!) - -2007-08-07 Thomas Thurman - - * configure.in: post-release bump to 2.19.89. - -2007-08-07 Thomas Thurman - - * NEWS: 2.19.55 release. - -2007-08-06 Thomas Thurman - - If KEY_AUTO_RAISE_DELAY is undefined or non-integer, it is not treated - as zero. - - * src/prefs.c (meta_prefs_init): check type of key, and behave sensibly - if it's unexpected. - * src/prefs.c (find_and_update_list_binding): remove old comment. - -2007-08-03 Frederic Crozat - - * src/delete.c: Fix mangled window title in "Force Quit" - dialog when using non-UTF8 locale. Close #462734. - -2007-08-02 Thomas Thurman - - Move "close" to bottom of window menu; allow workspace list to appear - at any position in the menu. Closes #104026. - - * src/menu.c (MetaMenuItemType): added new MENU_ITEM_WORKSPACE_LIST - item. - * src/menu.c (menuitems): reordered "close", added a workspace list. - * src/menu.c (menu_item_new): return null for workspace lists. - * src/menu.c (meta_window_menu_new): handle workspace lists. - -2007-07-31 Thomas Thurman - - * src/window.c (meta_window_show_menu): windows which are - always on top have the "stick" menu option insensitive. (#460997). - -2007-07-23 Thomas Thurman - - * src/window.h (MetaWindow): Put all bitfields together to - help with optimisation. Closes #450271 (for real this time). - -2007-07-23 Matthias Clasen - - * configure.in: - * src/Makefile.am: Use the correct directory when - installing keybindings. (#454055) - -2007-07-22 Thomas Thurman - - * configure.in: post-release bump to 2.19.55. - -2007-07-22 Thomas Thurman - - * NEWS: 2.19.34 release. - -2007-07-22 Rob Bradford - - Fix a bug where the window can be focused without being raised - if the maximize is aborted. Fixes #459027. - - * src/frames.c (meta_frames_button_press_event, - meta_frames_button_release_event): When maximising only focus - the window once the button press is released. - -2007-07-22 Cosimo Cecchi - - Unset fullscreen is an allowed action where relevant. Fixes #449427. - - * src/window.c (set_allowed_actions_hint): Separate FULLSCREEN action - from RESIZE action. - -2007-07-22 Yair Hershkovitz - - Reverse window buttons and align them to the left for RTL locales. - Fixed #92212. - - * src/prefs.c (button_layout, init_button_layout, update_button_layout): - Support reversing and left-aligning of buttons for both Gconf and - NO-Gconf modes. - * src/main.c (main): Call meta_ui_init() before meta_prefs_init(). - meta_prefs_init() check for RTL locales which is initialized in - meta_ui_init(). - * src/theme.c (meta_frame_layout_calc_geometry): Fixed access to - button_layout to stop iterating when getting to a - META_BUTTON_FUNCTION_LAST value. - -2007-06-23 Thomas Thurman - - * src/window.c (MetaWindow): Put all bitfields together to - help with optimisation. Closes #450271. - -2007-06-18 Thomas Thurman - - * src/main.c (version): Update copyright year because it was - five years out of date. - -2007-06-18 Thomas Thurman - - * configure.in: post-release bump to 2.19.34. - -2007-06-18 Thomas Thurman - - * NEWS: 2.19.21 release. - -2007-06-18 Thomas Thurman - - * src/place.c (find_first_fit, meta_window_place): Only open new - windows on the current xinerama. Closes #145503, for now. - -2007-06-17 Thomas Thurman - - * src/screen.[ch] (meta_screen_apply_startup_properties): return a - boolean instead a void, to show whether startup properties were - applied. Also some commenting. - * src/window-props.c: (reload_net_startup_id): Only activate the - window if the startup_id was actually changed. Closes #400167. - -2007-06-16 Damien Carbery - - * effects.h: MetaCloseEffect and MetaFocusEffect, which were empty - structs, #ifdeffed out because they broke the build on Solaris. - Closes #397296. - -2007-06-16 Damien Carbery - - * window.h: make prototype of meta_window_unqueue match - implementation. Closes #446535. - -2007-06-10 Thomas Thurman - - * configure.in: post-release bump to 2.19.21. - -2007-06-10 Thomas Thurman - - * NEWS: 2.19.13 release. - -2007-06-10 Thomas Thurman - - Refactor thrice-duplicated queue code in window.c. Closes #376760. - - * src/window.c (meta_window_queue, meta_window_unqueue): - New functiortl.patchns. - * src/window.[ch] (meta_window_unqueue_*, meta_window_queue_*): - Removed functions. - * src/window.c (meta_window_new_with_attrs, meta_window_free, - meta_window_flush_calc_showing, queue_calc_showing_func, - meta_window_minimize, meta_window_unminimize, meta_window_maximize, - meta_window_make_fullscreen, meta_window_shade, - meta_window_unshade, meta_window_move_resize_internal, - window_stick_impl, window_unstick_impl, - meta_window_client_message, process_property_notify): Modified to - use new queueing functions. - * src/window.c (idle_move_resize, idle_update_icon, - idle_calc_showing): update to receive queue number from pointer. - * src/window.h (MetaQueueType): new enum. - * src/window.h (MetaWindow): *_queued replaced with is_in_queue - bitfield. - * src/core.c (meta_core_queue_frame_resize): - * src/display.c (event_callback, - meta_display_queue_retheme_all_windows): Using new queueing functions. - * src/frame.c (meta_window_destroy_frame): Using new queueing functions. - * src/screen.c (queue_resize, meta_screen_resize_func, - queue_windows_showing): Using new queueing functions. - * src/window-props.c (reload_mwm_hints, reload_wm_hints, - reload_transient_for): Using new queueing functions. - * src/workspace.c (meta_workspace_add_window, - meta_workspace_remove_window, meta_workspace_queue_calc_showing, - meta_workspace_invalidate_work_area): Using new queueing functions. - -2007-06-09 Thomas Thurman - - * src/50-metacity-key.xml.in: added switch_group; closes #444879. - -2007-06-08 Elijah Newren - - * src/metacity.schemas.in: - Update the raise_on_click description to try to prevent misuses, - to appropriately warn users, and to stop wasting the time of - application developers. #445447, #389923 - -2007-06-06 Thomas Thurman - - * frames.c, core.[ch]: changed all tabs to spaces. - * core.[ch] (meta_core_get_client_size, meta_core_window_has_frame, - meta_core_titlebar_is_onscreen, meta_core_get_client_xwindow, - meta_core_get_frame_flags, meta_core_get_frame_type, - meta_core_get_mini_icon, meta_core_get_icon, meta_core_get_position, - meta_core_get_size, meta_core_get_frame_workspace, - meta_core_get_frame_extents, meta_core_get_screen_size): Removed - and replaced with meta_core_get(). - * core.[ch] (meta_core_get): New function. - * core.h (MetaCoreGetType): New enum. - * frames.c (meta_frames_ensure_layout, meta_frames_calc_geometry, - meta_frames_get_geometry, meta_frames_apply_shapes, - meta_frame_titlebar_event, meta_frames_button_press_event, - populate_cache, clip_to_screen, meta_frames_paint_to_drawable, - meta_frames_set_window_background, get_control): Replace use of - removed functions in ui.c with meta_core_get(). - - All this should make things a little faster. Closes #377495. - -2007-06-04 Thomas Thurman - - * NEWS: Added translators' names from 2.19.8 (sorry, folks: - I forgot to save NEWS with their names in it before shipping.) - -2007-06-04 Thomas Thurman - - * configure.in: post-release bump to 2.19.13. - -2007-06-04 Thomas Thurman - - * NEWS: 2.19.8 release. - -2007-06-04 Thomas Thurman - - * src/metaaccellabel.c (meta_accel_label_expose_event): fix - label layout for RTL languages. Closes #433400. - -2007-06-03 Thomas Thurman - - * src/frames.c (meta_frames_ensure_layout): Pango layout for - titlebars should take LTR/RTL-ness from the underlying widget - and not from sniffing the content. Closes #438944. - -2007-05-25 Yair Hershkovitz - - * src/workspace.c (meta_workspace_get_neighbor): Add support - for RTL languages so that alt-tab, etc., go the other way. - * src/keybindings.c (handle_activate_menu): In RTL locales, - pop up the menu on the right-hand side when the menu keystroke - is pressed. - * src/fixedtip.c (meta_fixed_tip_show): right-justify tooltips - in RTL locales. - * src/menu.c (popup_position_func): popup menus in RTL locales - are flush with the right-hand side of the window where possible. - * src/frames.c (show_tip_now, meta_frames_button_press_event): - tooltips are aligned with the right-hand side of buttons in - RTL locales. - * src/ui.[ch] (meta_ui_get_direction, enum MetaUIDirection): - New content. - * src/window.c (meta_window_show_menu): "move left" appears above - "move right" in the window menu for LTR locales, and vice versa - for RTL locales. - - This is all to close bug #387893. - -2007-04-24 Linus Torvalds - - * src/prefs.[ch] (init_action_meta_prefs, meta_prefs_init, - action_change_titlebar, change_notify, update_action_titlebar, - meta_preference_to_string): Add code to configure what happens - when the titlebar is right or middle clicked as well as - double clicked. - -2007-04-23 Elijah Newren - - * configure.in: post-release bump to 2.19.8. - -2007-04-23 Elijah Newren - - * NEWS: 2.19.5 release. - -2007-04-23 Elijah Newren - - Fix some uninitialized memory usage errors. #427385 - - * src/frame.c (meta_window_ensure_frame): - * src/frames.c (meta_frames_manage_window): - Do not try to set the window background in - meta_frames_manage_window() since the frame window is not yet - created and not yet registered with the corresponding MetaWindow. - Do it inside meta_window_ensure_frame() instead. - -2007-04-17 Elijah Newren - - Fix some fallout from #426519; update user_rect for all position - changes prior to the window being marked as placed. Prevents - emacs in particular from flickering on start and always being - shoved to the upper-left corner. - - * src/window.c (meta_window_move_resize_internal): - Record position in user_rect if the window is not yet marked as - placed too - - * src/window.c (struct MetaWindow, meta_window_new_with_attrs, - meta_window_move_resize_internal): - Remove window->user_has_move_resized; it's not needed or used - anymore. - - * src/window.[ch] (meta_window_get_user_position): - Remove this function as it is no longer needed or used. - -2007-04-16 Elijah Newren - - Prevent metacity from "forgetting" which machine a window is on. - #418552 - - * src/window.c (meta_window_new_with_attrs): reorder the property - loading so that we know the wm_client_machine when we load the - name of the window and can modify the window name accordingly. - -2007-04-16 Elijah Newren - - * configure.in: post-release bump to 2.19.5. - -2007-04-16 Elijah Newren - - * NEWS: 2.19.3 release. - -2007-04-15 Elijah Newren - - Preserve stacking order across restarts. - - * src/display.c (meta_display_unmanage_windows_for_screen): - unmap windows in stacking order so that stacking is preserved upon - shutdown - - * src/display.[ch] (meta_display_stack_cmp): - * src/session.c (stack_cmp, save_state): - rename stack_cmp() -> meta_display_stack_cmp() and move it to a - different function so that it can be used in both - session.c:save_state() and - meta_display_unmanage_windows_for_screen() - -2007-04-15 Elijah Newren - - Remove incorrect usage of window.h from menu.c. See #426791 & - #382962. - - * src/menu.c (enum MetaMenuItemType, variable menuitems, - meta_menu_item_new): - cleanup: add a MENU_ITEM_RADIOBUTTON for the sticky stuff - - * src/menu.c (variable menuitems): - * src/core.c (meta_core_get_menu_accelerator): - * src/window.c (menu_callback, meta_window_show_menu): - * src/common.h (enum MetaMenuOp): - reinstate META_MENU_OP_UNABOVE - - * src/menu.c (meta_window_menu_new): - remove hacks (using inappropriate data) for STICK/UNSTICK/ABOVE - and clean it up while just setting STICK/UNSTICK activeness as - necessary - - * src/menu.[ch] (meta_window_menu_new): - * src/ui.[ch] (meta_ui_window_menu_new): - make the active_workspace parameter an unsigned long - -2007-04-15 Bruno Boaventura - - * src/menu.c (meta_window_menu_new): don't show the current - workspace as a possible workspace to switch to. Fixes #426791. - -2007-04-12 Elijah Newren - - * src/place.c (meta_window_place): do not auto-maximize windows - larger than the workarea in only a single direction. Fixes - #419810. - -2007-04-11 Elijah Newren - - Make sure apps have correct info about their coordinates, even on - unmap. Fixes temporary hang with libXt (XtVaSetValues setting x & - y coordinates). #399552. - - * src/frame.c (meta_window_destroy_frame): Add a comment noting - that the current choice causes the need for a ConfigureNotify - event - - * src/window.c (meta_window_free): Send a configure notify event - due to our XReparentWindow coordinate choices on withdrawal, - (unmaximize_window_before_freeing): no need to send a configure - notify from here since it is always done in meta_window_free new, - (send_configure_notify): have to special case the coordinates used - when withdrawing the window - -2007-04-11 Thomas Thurman - - Workaround for a gdk bug which dies with BadAlloc if you try - to allocate an insanely huge rectangle for an insanely huge - window. Fixes #399529. - -2007-04-11 Elijah Newren - - Advertise support of Above and Below operations (assuming the - proposed EWMH additions of _NET_WM_ACTION_(ABOVE|BELOW) will be - accepted, otherwise these changes will have to be modified). Part - of #115247. - - * src/display.[ch] (meta_display_open, struct MetaDisplay): - * src/screen.c (set_wm_check_hint): - Add support for _NET_WM_ACTION_ABOVE and _NET_WM_ACTION_BELOW - - * src/window.c (set_allowed_actions_hints): - add active_above and action_below - -2007-04-10 Elijah Newren - - * src/window.c (recalc_window_features): make sure to set - _NET_WM_ALLOWED_ACTIONS so that libwnck menus don't have sensitive - but ineffective menu items. The "On Top" item is now buggy, but - due to the fact that _NET_WM_ACTION_ABOVE is not yet defined in - the EWMH. Fixes #115247. - -2007-04-09 Elijah Newren - - Add support for _NET_MOVERESIZE_WINDOW. Based on patch from - Magnus Therning. #344521. - - * src/display.c (handle_net_moveresize_window, event_callback): - Remove handle_net_moveresize_window() and the call to it; this - code was highly buggy, though to be fair it was never tested and - had simply been put into the code in commented out form. - - * src/screen.c (set_supported_hint): - add atom_net_moveresize_window - - * src/window.[ch]: - (meta_window_configure_request, meta_window_move_resize_request): - Split out the moving/resize part of the configure request and put - it into meta_window_move_resize_request - - (meta_window_client_message): - check for NET_MOVERESIZE_WINDOW messages and call - meta_window_move_resize_request() with the appropriate parameters - to handle them - - (meta_window_move_resize_internal): - fix some of the big comment at this function -- it wasn't quite - right, use the passed in gravity instead of - window->size_hints.win_gravity when calling adjust_for_gravity() - to make sure the correct adjustments are used. - - (meta_window_get_gravity_position, - meta_window_get_geometry, meta_window_move_resize_request): - add a gravity parameter to meta_window_get_gravity_position and - have it use that gravity instead of window->size_hints.win_gravity - -2007-04-09 Elijah Newren - - * configure.in: post-release bump to 2.19.3. - -2007-04-09 Elijah Newren - - * NEWS: 2.19.2 release. - -2007-04-08 Elijah Newren - - Remove grab_start_serial, which we expect to be an ancient attempt - to workaround sloppy/mouse focus bugs that have since been - correctly fixed. May fix some race conditions. May cause nasty - bugs in sloppy/mouse focus modes. We'll find out soon enough... - See #304430. - - * src/display.c (event_callback): - remove event->xany.serial >= display->grab_start_serial in several - event callback handlers - - * src/display.[ch] (struct _MetaDisplay, meta_display_begin_grab_op): - * src/keybindings.c (do_choose_window, handle_workspace_switch): - * src/frames.c (meta_frames_button_press_event): - * src/core.[ch] (meta_core_begin_grab_op): - * src/window.c (meta_window_client_message, meta_window_begin_grab_op): - don't require an event_serial to be passed to - meta_display_begin_grab_op () and don't record it anymore. - - * src/ui.c (struct _EventFunc, filter_func, - meta_ui_get_last_event_serial) - * src/core.h (meta_ui_get_last_event_serial): - remove meta_ui_get_last_event_serial() function (don't ask me why - it was declared in core.h) and the last_even_serial field of - _EventFunc - -2007-04-08 Elijah Newren - - Fix move/resize events in relation to combinations of - ConfigureRequest and WM_NORMAL_HINTS change notifications (plus a - few code cleanups). Fixes #426519. - - * src/window.c (meta_window_move_resize_now): - move to the user_rect position, not some weird combination of rect - and user_rect - - * src/window.c (meta_window_configure_request): - set user_rect in response to ConfigureRequest events (after the - ConfigureRequest values have been constrained) and add a big - comment explaining this change, remove unused only_resize variable - and irrelevant huge FIXME comment about it - - * src/window.[ch] (meta_window_get_client_root_coords): - new function - - * src/display.c (meta_display_begin_grab_op): - * src/keybindings.c (process_keyboard_move_grab): - * src/window.c (meta_window_unmaximize, - meta_window_move_resize_internal, meta_window_begin_wireframe, - update_move, meta_window_refresh_resize_popup, - warp_grab_pointer) - combine multi-step client rect root coord setting into a single - function call to meta_window_get_client_root_coords() - -2007-04-08 Thomas Thurman - - * ChangeLog: removed conflict line. - -2007-04-07 Elijah Newren - - * src/prefs.[ch] (screen_bindings array, - META_KEYBINDING_SET_SPEW_MARK definition): - * src/keybindings.c (handle_spew_mark, screen_handlers array): - Add an (unbound by default) keybinding for setting spew marks in - verbose debugging logs. I'm not sure why this was ever removed; - I've wanted it so many times. - - * HACKING: - valgrind wants --log-file not --logfile. - -2007-04-07 Elijah Newren - - * src/window.c (meta_window_free): Fix memory bug (invalid free) - introduced in 2007-04-02 strut cleanup commit. Part of #427385. - -2007-04-05 Thomas Thurman - - * src/theme_parser.c: if theme is invalid and therefore got - freed, don't attempt to read from it. Closes #423855. - -2007-04-05 Bastien Nocera - - * src/50-metacity-desktop-key.xml.in: - * src/50-metacity-key.xml.in: - * src/Makefile.am: - Add new control-center key bindings definitions (Closes: #420145) - -2007-04-04 Elijah Newren - - * configure.in: post-release bump to 2.19.2. - -2007-04-04 Elijah Newren - - * NEWS: 2.19.1 release. - -2007-04-04 Elijah Newren - - * src/window.c (meta_window_move_resize_internal): send synthetic - configurenotify events also in response to MapRequest events when - the window has a frame and the application specifies PPosition or - UPosition hints. I believe they are already sent for all other - cases. Should fix #322840. Fixes the testcase at least. :) - -2007-04-04 Elijah Newren - - Fix lots of little issues with min/max constraints and size - increment constraints. Fixes #329152, #418395, and possibly - others. - - * src/window-props.c (meta_set_normal_hints): - Do more checking to make sure application specified constraints - are self-consistent, modifying the size_hints as necessary to - achieve self-consistency. - - * src/constraints.c (setup_constraint_info): remove ugly - copy-pasto, (constrain_size_increments): be careful that fixing - violation of the constraints doesn't cause a violation of the - minimum size constraints. - - * src/window.c (ensure_size_hints_satisfied): new function, - (meta_window_unmaximize, meta_window_unmake_fullscreen): the - saved_rect may no longer be valid (as in the case of #329152) so - call ensure_size_hints_satisfied to fix it up. - - * doc/how-to-get-focus-right.txt: Some minor spacing and wording - fixes completely unrelated to the rest of this commit - -2007-04-03 Elijah Newren - - * src/window.c (meta_window_unmaximize): - Only use saved_rect for determining the position to unmaximize to - for the previously-maximized direction(s). Fixes #355497. - -2007-04-03 Elijah Newren - - * MAINTAINERS: Update. #412319. - -2007-04-03 Elijah Newren - - * src/display.c (meta_display_update_active_window_hint): - _NET_ACTIVE_WINDOW is a single xwindow id, not two. - -2007-04-03 Elijah Newren - - * src/keybindings.c (handle_panel_keybinding): turn mouse_mode off - to prevent focus issues with the run application dialog. Fixes - #374752. - -2007-04-03 Elijah Newren - - Avoid some crashes when dragging windows partially offscreen. - Possible (or at least partial) fix for #353513. - - * src/edge-resistance.c (apply_edge_resistance): be more careful - about calls to find_index_of_edge_near_position() returning - possibly invalid indices. Also, add a warning comment to - find_index_of_edge_near_position(). - -2007-04-03 Elijah Newren - - Patch from Carlo Wood to do some miscellaneous code cleanups found - while working on #358311. - - * src/constraints.c (do_screen_and_xinerama_relative_constraints): - nicer way of avoiding compilation warning - - * src/boxes.c (meta_rectangle_clamp_to_fit_into_region, - meta_rectangle_clip_to_region, meta_rectangle_shove_into_region): - Much cleaner way of ignoring invalid boxes in comparisons - -2007-04-02 Elijah Newren - - Patch from Carlo Wood to fix handling of unidirectional - maximization and partial struts. #358311. - - * src/constraints.c (constrain_maximization): - determine target size for unidirectionally maximized windows by - determining how far they can be maximized without hitting - orthogonal struts. Avoids weird "empty spaces". - - * src/boxes.[ch] (meta_rectangle_expand_to_avoiding_struts): - new function - -2007-04-02 Elijah Newren - - Make the strut lists (stored in workspaces) record both the - rectangle and the side that the strut is on. Lots of code - cleanups relating to struts. - - * src/boxes.h (struct MetaStrut): - new struct for struts - - * src/window.[ch] (struct MetaStruts, struct MetaWindow, - meta_window_update_struts): - overhaul to make window's struts remember their side as well as - their rectangular location, and just use a list instead of several - copies of near-identical code for left/right/top/bottom (allowing - us to nuke MetaStruts struct as well) - - * src/testboxes.c (new_meta_strut, get_strut_list): - * src/workspace.c (ensure_work_areas_validated): - * src/boxes.c (meta_rectangle_get_minimal_spanning_set_for_region, - meta_rectangle_expand_to_avoiding_struts, - get_disjoint_strut_rect_list_in_region, fix_up_edges, - meta_rectangle_find_onscreen_edges, - meta_rectangle_find_nonintersected_xinerama_edges): - modify to handle struts being rectangle + side instead of just rectangle - - * src/workspace.c (ensure_work_areas_validated): - simplify strut list creation considerably given MetaWindow change, - modify work_area computations to take advantage of region - computations being done (makes the code shorter as well as more - robust against pathological cases). - - * src/util.[ch] (meta_free_gslist_and_elements): - new convenience function - - * src/common.h (enum MetaDirection): - * src/edge-resistance.c (movement_towards_edge): - * src/boxes.c (meta_rectangle_edge_aligns, - rectangle_and_edge_intersection, split_edge): - Add more MetaDirection fields for convenience - - * src/boxes.h (enum FixedDirections): - * src/constraints.c (setup_constraint_info, place_window_if_needed): - add a FIXED_DIRECTION_NONE to the FixedDirections enum to make - code more clear - -2007-04-01 Bruno Boaventura - - * src/theme.c (kill_window_question): Fallback to NORMAL state after - checking for the middle button. Fixes bug #419043. - Patch from Benjamin Berg . - -2007-03-31 Elijah Newren - - Clean up event mask handling and meta_create_offscreen_window, to - prevent nasty metacity/gdk interactions causing hangs. See #354213. - - * src/screen.[ch] (meta_create_offscreen_window): - * src/display.c (meta_display_open): - * src/screen.c (meta_screen_new): - Add a valuemask parameter to meta_create_offscreen_window - - * src/display.c (meta_display_open): - make it explicit that we can't rely on PropertyNotify events for - the leader_window due to nasty metacity/gdk interaction - - * src/session.c (warn_about_lame_clients_and_finish_interact): - remove cut-and-paste code for timestamp pinging and just call - meta_display_get_current_time_roundtrip - -2007-03-30 Elijah Newren - - Add support for _NET_WM_USER_TIME_WINDOW in order to cut down on - context switches. Fixes #354213. - - * src/display.c (meta_display_open): - * src/display.h (struct _MetaDisplay): - * src/screen.c (set_supported_hint): - new atom - - * src/display.c (meta_display_open, - meta_display_get_current_time_roundtrip): - * src/display.h (struct _MetaDisplay): - create a dedicated timestamp pinging window instead of reusing - display->leader_window - - * src/display.c (event_callback): - * src/window-props.c (reload_net_wm_user_time_window): - * src/window.c (meta_window_new_with_attrs, meta_window_free, - process_property_notify): - * src/window.h (struct _MetaWindow): - monitor property notify events on _NET_WM_USER_TIME_WINDOW windows too - - * src/window-props.[ch]: - new meta_window_reload_propert(y|ies)_from_xwindow() functions - - * src/window-props.[ch] - (init_net_wm_user_time_window, reload_net_wm_user_time_window, - meta_display_init_window_prop_hooks): - * src/window.c (meta_window_new_with_attrs): - new hooks to handle new atom - -2007-03-26 Josselin Mouette - - * src/session.c (meta_session_init): if previous client ID - was supplied, use it in filename. - * src/session.c (set_clone_restart_commands): use --sm-client-id - in command line to restore session, not original file name. - * src/session.c (regenerate_save_file): generate filename using - client ID and not original file name. - * src/session.c (base_save_file): removed function. - Closes GNOME 407981, Debian 391287, Debian 315169. - -2007-03-25 Elijah Newren - - * configure.in: bump version to 2.19.1; doesn't make sense to have - the development version have a version number less than the stable - version. ;-) - -2007-03-20 Arthur Taylor - - * src/frames.c (meta_frames_apply_shapes): adjusted the rounded - corners so that they fit nicely with the arcs around them. - Fixes #399373. - -2007-03-17 Kjartan Maraas - - * src/ui.c: Remove #include since it's - apparently not installed anymore. Builds just fine without it too. - -2007-03-10 Charlie Brej - - * src/metacity.schemas.in: add action_{middle|right}_click_titlebar. - Closes #408903. - -2007-03-09 Linus Torvalds - - * src/frames.c (meta_frame_middle_click_event, - meta_frame_right_click_event): honour preferences. - * src/prefs.[ch] (meta_prefs_get_action_middle_click_titlebar, - meta_prefs_get_action_right_click_titlebar): new functions. - -2007-02-20 Kjartan Maraas - - * Makefile.am: Add MAINTAINERS to EXTRA_DIST so others - can find out where to send patches. Hi Linus :-) - -2007-02-17 Linus Torvalds - - * src/common.h (MetaActionTitleBar): renamed from - MetaActionDoubleClickTitleBar; added _LOWER and _MENU. - * src/frames.c (meta_frame_titlebar_event): renamed - enums as above; added code to handle _LOWER and _MENU, - which is moved in from meta_frame_{middle|right}_click_event. - * src/frames.c (meta_frame_middle_click_event, - meta_frame_right_click_event): rewrote in terms of - meta_frame_titlebar_event. - * src/prefs.c: removed "DoubleClick" from names as above. - * src/prefs.c (action_titlebar_from_string): added cases - for "lower" and "menu". - Fixes #408902. - -2007-02-17 Linus Torvalds - - * src/frames.c (meta_frames_button_press_event): Split out - code for different kinds of click into separate functions. - Fixes #408899. - * src/frames.c (meta_frame_titlebar_event, - meta_frame_double_click_event, meta_frame_middle_click_event, - meta_frame_right_click_event): new functions. - -2007-01-27 Bruno Boaventura - - * src/metacity-dialog.c (kill_window_question): Change dialog - icon because gnome-icon-theme have no more "panel-force-quit". - Patch from Jaap A. Haitsma . - -2007-01-16 Thomas Thurman - - * doc/compositor-control.txt: fix silly thinko. - -2007-01-16 Thomas Thurman - - * configure.in: post-release bump to 2.17.8. - -2007-01-16 Thomas Thurman - - * doc/compositor-control.txt: New file. - -2007-01-16 Thomas Thurman - - * src/compositor.c (meta_compositor_new): Removed - #ifdef SPIFFY_COMPOSITOR throughout the file. Replaced with check - for environment variable METACITY_BLING, which may be temporary. - -2007-01-13 Bruno Boaventura - - * src/frames.c (meta_frames_motion_notify_event): Unmaximize - button must keep preesed appearence when clicked (hold down), - move off, and back over the button. Fixes #395560. Patch from - Mad Alex . - -2007-01-02 Thomas Thurman - - * src/c-screen.c (meta_comp_screen_redirect): Remove double unref - of stacker object. Fixes #387761. - -2006-12-27 Bruno Boaventura - - Move "On Top" option in menu. Fix #382962. - - * src/common.h, src/core.c: Remove META_MENU_OP_UNABOVE. - * src/menu.c: remove unabove menu item and put above item - next "Always on Visible Viewport". - * src/window.c: remove handles of META_MENU_OP_UNABOVE. - -2006-12-21 Thomas Thurman - - * src/compositor.c: Disabled bling for now; added function for - handling CirculateNotify XEvent; some commenting. - * src/compositor.h, src/c-window.c: fix function prototype visibility. - -2006-12-12 Thomas Thurman - - * src/compositor.c (do_effect): Sanity check to avoid dereferencing - a null pointer. - -2006-12-10 Thomas Thurman - - * configure.in: post-release bump to 2.17.5. - -2006-12-10 Thomas Thurman - - * NEWS: 2.17.3 release. - -2006-12-05 Christof Krüger - - * src/window.c (update_move): Fix flickering about when dragging - maximised windows between xineramas. Closes #358715. - -2006-12-03 Federico Mena Quintero - - Fix http://bugzilla.gnome.org/show_bug.cgi?id=381127: - - * src/window.c (idle_calc_showing): Grab the server while the - windows are being shuffled. First show the windows to be shown, - and then hide the windows to be hidden, in order to minimize - the number of expose events. - -2006-11-15 Bruno Boaventura -2006-11-15 Björn Lindqvist - - * src/menu.c: added MetaMenuItemType enum; added it - to MenuItem; added values of this type to menuitems - array. - * src/menu.c (menu_item_new): rewrite to take a MenuItem - instead of a set of parameters describing the menu item. - * src/menu.c (meta_window_menu_new): use proper checkboxes - or radio buttons on the window menu. (#343108) - * src/window.c (meta_window_show_menu): unstick and stick - are always shown. - -2006-11-06 Thomas Thurman - - * configure.in: post-release bump to 2.17.3. - -2006-11-06 Thomas Thurman - - * configure.in: pre-release bump to 2.17.2. - * NEWS: 2.17.2 release. - -2006-11-05 Priit Laes - - * src/main.c, src/ui.c: remove deprecated gtk stuff. - -2006-11-05 Bruno Boaventura - - * src/theme.c, src/testgradient.c: remove deprecated gtk stuff. - -2006-11-05 Kjartan Maraas - - * src/ui.c: use g_strdup to allocate a string, not strdup. Fixes - #363354. - * src/metacity-dialog.c: add missing spaces to string. Fixes - #363355. - -2006-11-05 Justin Mason - - * src/keybindings.c: implement handle_move_to_{side|corner}_* to - allow the user to flip a window to the side or corner of the - screen. Fixes #317884. - * src/prefs.h: keybindings for the above. - * src/metacity.schemas.in: keybindings for the above. - -2006-11-05 Elijah Newren - - * src/frames.c: improved rounding of rounded corners. Fixes #360542, - mostly. - -2006-10-30 Dan Mick - - * src/window.c: (__window_is_terminal): Fix strict focus - mode by picking up on res_class. Fixes #361054, strict focus - mode still not working; should look for res_class, not res_name - -2006-10-16 Elijah Newren - - * NEWS: 2.17.1 release. - -2006-10-13 Carlo Wood - - Fix cases when titlebar is allowed offscreen and shouldn't be (and - vice-versa). #333995. - - * src/display.[ch] (struct _MetaDisplay): add grab_frame_action - member - - * src/display.[ch] (meta_display_begin_grab_op): - * src/window.[ch] (meta_window_begin_grab_op): - * src/core.[ch] (meta_core_begin_grab_op): - Add frame_action parameter (core & window versions pass it on to - display) - - * src/display.c (event_callback): - * src/window.c (meta_window_begin_grab_op, - meta_window_client_message, menu_callback): - * frames.c (meta_frames_button_press_event): - * keybindings.c (do_choose_window, handle_begin_move, - handle_begin_resize, handle_workspace_switch): - Pass whether the action should be considered a 'frame_action', - which will be used to determine whether to force the titlebar to - remain onscreen, to meta_*_begin_grab_op - - * constraints.c (constrain_titlebar_visible): - Replace previous ugly hack by using grab_frame_action (and whether - the action is a user action) to determine whether to enforce the - titlebar_visible constraint. - -2006-10-10 Elijah Newren - - * src/draw-workspace.c (draw_window, wnck_draw_workspace): Patch - from Bruno Boaventura to sync metacity workspace previews with - libwnck. #341893 - -2006-10-07 Thomas Thurman - - * configure.in: post-release bump to 2.17.1. - -2006-10-07 Thomas Thurman - - * NEWS: 2.17.0 release. - -2006-10-07 Thomas Thurman - - * src/themes/Crux/metacity-theme-2.xml: removed hide_buttons. - Closes #360498. - -2006-10-07 Thomas Thurman - - * MAINTAINERS: added myself. - -2006-10-07 Thomas Thurman - - * doc/theme-format.txt: described new theme format. - - * src/themes/Bright, src/themes/Crux: added version 2 themes. - -2006-10-07 Thomas Thurman - - * common.h: Added "above" to the list of flags a frame can have, so - that we know when to mark it as always on top. Added six grab ops, - one to do and one to undo each of the three new titlebar buttons - (shade, above, stick). Added six new button functions, similarly. - (#96229) - - * frame.c (meta_frame_get_flags): If a frame has the WM_STATE_ABOVE X - attribute, set META_FRAME_ABOVE in its flags. - - * frames.c (meta_frames_apply_shapes): Allow variable amounts of - rounding. (#113162) - - * frames.c (show_tip_now, meta_frames_paint_to_drawable, control_rect, - get_control): extend handling of existing buttons to the - 3*2 new kinds of button. (#96229) - - * frames.c (meta_frames_button_press_event): translate clicks on the 3*2 - new kinds of button to the new grab ops. (#96229) - - * frames.c (meta_frames_button_release_event): implement the various - actions for the 3*2 new kinds of button. (#96229) - - * frames.c (meta_frames_update_prelit_control, - meta_frames_motion_notify_event): extend existing motion - notifications for buttons to the 3*2 new kinds of button. (#96229) - - * frames.c (meta_frames_set_window_background): handle specified - background colours and alpha transparency. (#151261) - - * frames.h (MetaFrameControl): New control types for the 3*2 new kinds - of button. (#96229) - - * iconcache.[ch] (meta_read_icons): use theme's fallback icons if a - window has no icon; use metacity's fallback icons only if the theme - does not provide any. (#11363) - - * iconcache.[ch] (meta_invalidate_default_icons (new function)): clear - icon cache on windows using default icons, and update them. (#11363) - - * main.c (main): added \n to error message. - - * prefs.c (button_function_from_string): extend for 3 new button - types. (#96229) - - * prefs.c (button_opposite_function (new function)): return a button - function's inverse (shade -> unshade, etc) (#96229) - - * prefs.c (update_button_layout): allocate space for a button's - inverse, if it has one. (#96229) - - * theme-parser.c (ParseState): add state for fallback icons (#11363) - - * theme-parser.c (ParseInfo): add format_version; remove - menu_icon_* (#114305) - - * theme-parser.c (parse_positive_integer): add lookup for integer - constants (#331356) - - * theme-parser.c (parse_rounding (new function)): parse window - rounding amount (#113162) - - * theme-parser.c (parse_alpha): don't set error if the number can't - be parsed since it'll already be set; change tolerance in comparison - from 1e6 to 1e-6 - - * theme-parser.c (parse_color (new function)): parse colour, including - possible constant lookup. - - * theme-parser.c (parse_toplevel_element): allow defining of various - new kinds of constant; allow - hide_buttons (#121639) and more detailed rounding attributes on - (#113162); allow background and alpha attributes on - ; (#151261) remove support for except as - stub; (#114305) add support for loading stock images (#113465); add - support for . (#11363)) - - * theme-parser.c (parse_draw_op_element): add from and to attribute - for arcs. (#121603) - - * theme-parser.c (parse_style_element): add check for theme version - supporting a button function. (#96229) - - * theme-parser.c (parse_style_set_element): add ability for shaded - windows to be resizable (#114304) - - * theme-parser.c (meta_theme_load): add theme versioning routine. - - * theme.c ( meta_frame_layout_get_borders): return rectangles for - the new 3*2 kinds of button, except where they're - inapplicable. (#96229) - - * theme.c (meta_frame_layout_calc_geometry): don't format buttons on - windows with no buttons (#121639); strip the 3*2 new kinds of button - correctly (#96229); allow variable amounts of rounding (#113162). - - * theme.c (meta_frame_style_new): set alpha to 255 by - default. (#151261) - - * theme.c (meta_frame_style_unref): free colour spec if - allocated. (#151261) - - * theme.c (meta_frame_style_validate): it's only an error not to - include a button if that button is valid in the current - theme. (#96229) - - * theme.c (button_rect): return rectangles for the new 3*2 kinds - of button. (#96229) - - * theme.c (meta_frame_style_set_unref): free differently resizable - shaded styles. (#114304) - - * theme.c (get_style): look up differently resizable styles - for shaded windows. (#114304) - - * theme.c (free_menu_ops (removed function), get_menu_icon - (removed function), meta_theme_draw_menu_icon (removed function), - meta_menu_icon_type_from_string (removed function), - meta_menu_icon_type_to_string (removed function), - meta_theme_free, meta_theme_validate): removed menu icon code. (#114305) - - * theme.c (meta_theme_load_image): add size_of_theme_icons - parameter. (#113465) - - * theme.c (meta_theme_define_color_constant (new function), - meta_theme_lookup_color_constant (new function)): allow - definition of colour constants. (#129747) - - * theme.c (meta_button_type_from_string, meta_button_type_to_string): - add the 3*2 new kinds of button. (#96229) - - * theme.c (meta_theme_earliest_version_with_button (new function)): - return the theme version each button was introduced in. (#96229) - - * theme.h ( MetaFrameLayout): add "hide_buttons" flag (#121639) and - corner radiuses. (#113162) - - * theme.h (MetaFrameGeometry): add rectangles for the 3*2 new - buttons. (#96229) - - * theme.h (MetaButtonType): the 3*2 new buttons. (#96229) - - * theme.h (MetaFrameStyle): add window_background_color and - window_background_alpha so that we can specify background on a - . (#151261) - - * theme.h (MetaFrameStyleSet): shaded_styles gets resize - dimension. (#114304) - - * theme.h (MetaTheme): added format_version, color_constants - hash, (#129747) fallback_icon and fallback_mini_icon, (#11363) - and removed menu_icons. (#114305) - - * theme.h (META_THEME_ALLOWS (new macro)): return whether a theme - supports a given feature. Also, several macros representing - new features in v2. - - * ui.c (meta_ui_set_current_theme)): also invalidate default - icons. (#11363) - - * window.[ch] (meta_window_update_icon_now)): became - non-static. (#11363) - -2006-10-06 Elijah Newren - - * src/metacity-dialog.c (kill_window_question): Be nice to - translators; remove unnecessary markup from strings marked for - translation (oops, I missed this in my review before previous - commit) - -2006-10-06 Elijah Newren - - * src/metacity-dialog.c (kill_window_question): Patch from Bruno - Boaventura to improve the "Force Quit" dialog. #121936 - -2006-10-02 Elijah Newren - - Ignore edge resistance for size-increment windows when resizing - with the keyboard. #346782. - - * src/edge-resistance.c (apply_edge_resistance_to_each_side): - ignore edge resistance for size-increment windows when resizing - with the keyboard, (apply_edge_resistance_to_each_side, - meta_window_edge_resistance_for_move, - meta_window_edge_resistance_for_resize): pass a is_resize - parameter as well - -2006-10-01 Elijah Newren - - * src/display.c (meta_display_set_input_focus_window): - * src/window.c (meta_window_focus): - Don't require a push/pop trap around - meta_display_set_input_focus_window(), but rather move the - push/pop into that function surrounding the XSetInputFocus() call - directly. Follow up to #358514. - -2006-10-01 Elijah Newren - - * src/*.[ch]: Stick an emacs comment directive at the beginning of - all the code files so that people using emacs will be more likely - to get coding style correct in their patches. We still need a - similar vi directive. #358866 - -2006-10-01 Elijah Newren - - Patch from Carlo Wood to ensure that maximized and minimized - properties are maintained across restarts. #358042. - - * src/constraints.c (place_window_if_needed): fix up partial - maximization handling and add minimize_after_placement handling. - - * src/display.[ch] (struct MetaDisplay, meta_display_open): add a - new display->display_opening flag to allow handling startup - differently where needed. - - * src/window-props.c (reload_net_wm_state): handle - _net_wm_state_hidden as well, setting - window->minimize_after_placement appropriately - - * src/window.[ch] (struct MetaWindow, meta_window_new_with_attrs): - add a window->minimize_after_placement field - - * src/window.c (meta_window_new_with_attrs): only unminimize the - window and its transients if the display isn't being opened, - (unmaximize_window_before_freeing): don't reset the state unless - the window is becoming withdrawn, if the screen is being closed be - sure to save the unmaximized state of the window so the next - window manager can restore it - -2006-10-01 Elijah Newren - - * src/window-props.c (set_title_text): surround the - XDeleteProperty() call with a - meta_error_trap_push/meta_error_trap_pop pair to prevent a crash - when closing a remote instance of gedit (and perhaps other apps). - #358514. - -2006-10-01 Elijah Newren - - Fix longstanding focus bug with mouse (not sloppy) focus mode with - popup override-redirect windows, particularly mozilla and - firefox's location bar autocompletion. #357695. - - * src/display.c (event_callback -- EnterNotify & LeaveNotify events): - for mouse focus, defocus the focused window when the mouse enters - the desktop window rather than when the mouse leaves the focused - window. - - * doc/how-to-get-focus-right.txt: - update for the slightly nuanced definition of mouse focus (people - without a DESKTOP window like nautilus get sloppy focus behavior - now) - -2006-09-27 Elijah Newren - - * src/menu.c (var menuitems): Patch from Bruno Boaventura to add - notes to remind translators to keep translations in sync with - libwnck. #355620. - -2006-09-18 Elijah Newren - - * src/window.c (meta_window_show): Patch from Jens Granseuer to - fix c89 cleanness, again. #356631. - -2006-09-18 Elijah Newren - - * src/constraints.c (constrain_maximization): Ignore maximum size - hints when maximizing. Should fix #327543 (see comment 4 and comment - 5). - -2006-09-18 Elijah Newren - - * src/ui.c (filter_func): avoid a compilation warning by making - sure to return something. #348067 - -2006-09-18 Thomas Thurman - - Branched for Gnome 2.17. - - * configure.in: bump version to 2.17.0. - -2006-09-18 Thomas Thurman - - * configure.in: post-release bump to 2.16.3 - -2006-09-18 Thomas Thurman - - * NEWS: 2.16.2 release - -2006-09-18 Elijah Newren - - Partial audit to fix timestamp usage. One step towards fixing - #355180; see important comments in that bug. - - * src/core.[ch] (meta_core_unshade, meta_core_shade): - * src/delete.c (meta_window_present_delete_dialog, - delete_ping_timeout_func): - * src/display.[ch] (meta_display_open, meta_display_close, - event_callback, meta_display_begin_grab_op, - process_selection_clear, meta_display_unmanage_screen, - meta_display_unmanage_windows_for_screen): - * src/frames.c (meta_frames_button_press_event): - * src/keybindings.c (handle_toggle_shade): - * src/main.c (main): - * src/screen.[ch] (update_num_workspaces, meta_screen_new, - meta_screen_free, prefs_changed_callback): - * src/window.[ch] (meta_window_free, finish_minimize, - implement_showing, meta_window_show, meta_window_maximize, - meta_window_make_fullscreen_internal, - meta_window_unmake_fullscreen, meta_window_shade, - meta_window_unshade, window_activate, send_sync_request, - meta_window_client_message, menu_callback, - meta_window_update_keyboard_resize): - Remove usage of CurrentTime, meta_display_get_current_time() and - meta_display_get_current_time_roundtrip() where possible, or - document why it isn't possible, or at very least add a FIXME with - some explanation of my laziness and what needs to be done. - -2006-09-18 Elijah Newren - - * src/spring-model.c (on_end_move, model_is_calm): Patch from Maik - Beckmann to remove compilation warnings. Fixes #355876. - -2006-09-18 Elijah Newren - - * configure.in: Make detection of stable vs. unstable automatic - and based upon the version number. Partially based on patch from - Christian Hamar in #356122. Fixes #356122. - -2006-09-13 Elijah Newren - - * HACKING: update -- we depend on gtk+ >= 2.10 since Vincent's - July patches for #348633. - -2006-09-13 Elijah Newren - - * src/window.c (meta_window_show): Patch from Thomas Andersen to - make windows be stacked correctly before showing them, to prevent - flicker with focus stealing prevention. #332385. - -2006-09-13 Elijah Newren - - * src/common.h (MetaWindowMenuFunc): - * src/core.[ch] (meta_core_user_lower_and_unfocus, - meta_core_user_focus, meta_core_show_window_menu, - meta_core_begin_grab_op, meta_core_end_grab_op): - * src/delete.c (delete_ping_reply_func, delete_ping_timeout_func, - meta_window_delete): - * src/display.[ch] (struct MetaDisplay, struct MetaPingData, - sanity_check_timestamps, meta_display_open, event_callback, - meta_spew_event, meta_display_set_grab_op_cursor, - meta_display_begin_grab_op, meta_display_end_grab_op, - meta_display_ping_timeout, meta_display_ping_window, - process_pong_message, timestamp_too_old, - meta_display_set_input_focus_window): - * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard, - meta_screen_grab_all_keys, meta_window_grab_all_keys, - meta_window_ungrab_all_keys, error_on_generic_command, - error_on_command, error_on_terminal_command): - * src/metacity-dialog.c (on_realize, warn_about_no_sm_support, - error_about_command, main): - * src/screen.[ch] (struct _MetaScreen, meta_screen_new, - meta_screen_show_desktop, meta_screen_apply_startup_properties): - * src/session.c (warn_about_lame_clients_and_finish_interact): - * src/window.[ch] (struct _MetaWindow, - intervening_user_event_occurred, window_activate, - meta_window_delete, meta_window_focus, - meta_window_send_icccm_message, meta_window_client_message, - menu_callback, meta_window_show_menu, struct EventScannerData, - check_use_this_motion_notify, meta_window_begin_grab_op, - meta_window_set_user_time): - * src/workspace.[ch] (focus_ancestor_or_mru_window, - meta_workspace_activate_with_focus, meta_workspace_activate, - meta_workspace_focus_default_window, - focus_ancestor_or_mru_window): - Fix issues on 64-bit machines with timestamps by using guint32 - (like gtk+ does) instead of Time. #348305 - -2006-09-12 Elijah Newren - - * src/theme.c (meta_gtk_arrow_from_string, - meta_gtk_arrow_to_string): patch from Bruno Boaventura de Oliveira - to fix a compiler warning about not handling GTK_ARRROW_NONE. - #355490. - -2006-09-12 Elijah Newren - - * src/compositor.c: Patch from Bruno Boaventura de Oliveira - Lacerda to fix warnings about unused function and global var. - #355489. - -2006-09-11 Thomas Thurman - - * configure.in: post-release bump to 2.16.2 - -2006-09-11 Thomas Thurman - - * NEWS: 2.16.1 release - -22006-09-09 Elijah Newren - - * src/display.c (meta_display_open): Fix build when XKB not found. - #354211 - -2006-09-09 Elijah Newren - - Avoid a stuck grab, preventing focus from being transferred - between windows. Thanks to Fryderyk Dziarmagowski for steps to - reproduce. Fixes at least part of #354422. - - * src/display.c (meta_display_begin_grab_op, - meta_display_end_grab_op): pass timestamp to - meta_screen_ungrab_all_keys, meta_screen_ungrab_all_keys, and - meta_window_ungrab_all_keys - - * src/keybindings.[ch] (grab_keyboard, ungrab_keyboard): add a - timestamp parameter and remove call to - meta_display_get_current_time(), (meta_screen_grab_all_keys, - meta_screen_ungrab_all_keys, meta_window_ungrab_all_keys): add a - timestamp parameter and pass it on to grab_keyboard and - ungrab_keyboard - -2006-09-07 Elijah Newren - - * src/constraints.c (update_onscreen_requirements): make sure - windows returning from fullscreen mode are constrained to be - "onscreen"; fixes #353699. - -2006-08-30 Colin Watson - - * src/window-props.c (reload_transient_for): Clear - window->xtransient_for after emitting the invalid window warning. - #353540 - -2006-09-07 Elijah Newren - - * src/metacity-dialog.c: Patch from Bruno Boaventura de Oliveira - Lacerda to replace copy_of_gdk_x11_window_set_user_time() with - gdk_x11_window_set_user_time(). We've long since adopted gtk+ >= - 2.6 as a dependency. #352293 - -2006-09-04 Thomas Thurman - - * configure.in: post-release version bump to 2.16.1 - -2006-09-04 Thomas Thurman - - * NEWS: 2.16.0 release - -2006-08-22 Elijah Newren - - * src/metacity-dialog.c (main): Patch from Jens Granseuer to fix - the build with c89/gcc 2.95. - -2006-08-21 Elijah Newren - - * NEWS: Oops, forgot to mention the translators in the 2.15.34 - release; add them retroactively - -2006-08-21 Elijah Newren - - * configure.in: post-release version bump to 2.15.55 - -2006-08-21 Elijah Newren - - * NEWS: 2.15.34 release - -2006-08-21 Elijah Newren - - Patch from Thomas Andersen to fix metacity-dialog handling of - arguments. #340690 - - * src/metacity-dialog.c (main): replace hackish argument parsing - with GOption parsing. Much nicer. :) - -2006-08-21 Elijah Newren - - Patch from Ed Catmur to fix keybindings with hex-values (coming - from special extended keyboard keys). #140448. - - * src/keybindings.c (struct _MetaKeyBinding): change keycode from - KeyCode to unsigned int (comment from Elijah: why???), - (reload_keycodes): only grab keysyms for keybindings that have - them, (count_bindings, rebuild_binding_table): bindings can be - valid either due to a valid keysym or a valid keycode, - (display_get_keybinding_action, meta_change_keygrab, - process_tab_grab, process_workspace_switch_grab): handle keycode - as well as keysym - - * src/prefs.[ch] (struct MetaKeyCombo, update_binding, - update_list_binding): handle keycode as well as keysym - - * src/ui.[ch] (meta_ui_accelerator_parse): new function special - cases strings of the form "0x[0-9a-fA-F]+" and otherwise calling - gtk_accelerator_parse(), (meta_ui_parse_accelerator, - meta_ui_parse_modifier): call meta_ui_accelerator_parse instead of - gtk_accelerator_parse. - -2006-08-21 Elijah Newren - - Allow drags & resizes to be reverted by hitting escape. Based on - patch from Thomas Andersen. #126497. - - * src/display.c (grab_op_is_mouse_only): new function, - (meta_display_begin_grab_op): grab the keyboard when moving or - resizing too so that we can get escape keypresses - - * src/display.h (struct _MetaDisplay): add a comment to remind - that grab_was_cancelled is only used in wireframe mode - - * src/keybindings.[ch] (process_mouse_move_resize_grab): add new - function for handling keypresses during mouse-only moving and - resizing, (meta_window_grab_all_keys): add a timestamp parameter - and pass it to meta_window_focus(), - (meta_display_process_key_event): make sure - process_mouse_move_resize_grab() gets called when needed, - (process_keyboard_move_grab, process_keyboard_resize_grab): - rearrange some code slightly and improve the comments to make it - more readable - -2006-08-21 Elijah Newren - - Fix several bugs with handling of fullscreen windows, causing them - to not actually be fullscreen. #343115 (and also #346927, - #350547, #351643, the recent additional WINE-related issue - mentioned on the mailing list, and probably others...) - - * src/constraints.c (setup_constraint_info): if a window tries to - resize to fullscreen-size and it has a fullscreen function but - isn't actually marked as fullscreen then assist it by marking it - as such, (constrain_fully_onscreen, constrain_titlebar_visible): - ignore this constraint for fullscreen windows since such windows - have a separate specialized constraint - - * src/stack.c (window_is_fullscreen_size, get_standalone_layer): - remove the old window_is_fullscreen_size() hack for detecting - windows to treat as fullscreen since it doesn't work well with the - new constraints framework (i.e. we needed a slightly different - hack) - - * src/window.[ch] (meta_window_new_with_addrs): shuffle the order - of adding the window to the stack and moveresizing the window - since moveresizing can cause stack changes if the window's initial - size is fullscreen size, (meta_window_make_fullscreen, - meta_window_make_fullscreen_internal): split - meta_window_make_fullscreen() similar to meta_window_maximize() so - that constraints can make use of it - -2006-08-19 Baptiste Mille-Mathias - - * src/stock_delete.png: Update the pixmap to a new one which - fit better with the other pixmaps of the menu. First patch in - metacity, woot! #345498 - -2006-08-18 Elijah Newren - - * src/tabpopup.c (meta_ui_tab_popup_new): Patch from Willie Walker - to restore the part of the patch that I should not have reverted - in #123372, in order to fix accessibility. #350624 - -2006-08-09 Elijah Newren - - * src/window.c (intervening_user_event_occurred): Vytautus Liuolia - totally rocks; he tested and debugged and tracked down where we - were using the focus window's net_wm_user_time even when it was - uninitialized. This may fix bug 311868 and others I've heard - about (with Valknut, IIRC). It definitely fixes the issues Vytas - was seeing with his single instance library. :-) - -2006-08-07 Elijah Newren - - * src/constraints.c (setup_constraint_info): patch from Stéphane - Rosi to allow moving maximized windows between xineramas again. - #323820 - -2006-08-07 Elijah Newren - - * configure.in: post-release version bump to 2.15.34 - -2006-08-07 Elijah Newren - - * NEWS: 2.15.21 release - -2006-08-07 Elijah Newren - - Add a constrain_titlebar_visible constraint; should fix both bug - 333328 and bug 345522. Not perfect (minor annoying snap pulling - windows back onscreen, plus an ugly hack almost as bad as the old - one), but tarballs are due in less than half an hour. ;-) - - * src/boxes.[ch] (meta_rectangle_overlaps_with_region): - new function - - * src/constraints.c (constrain_titlebar_visible): new function, - (enum ConstraintPriority, array all_constraints, - update_onscreen_requirements): various small changes to - accomodate the new function - - * src/edge-resistance.c: remove the infinite edge resistance, - which was a big hack of a way to workaround the lack of a - titlebar_visible constraint - - * src/window.[ch] (MetaWindow): new require_titlebar_visible - bitfield, (meta_window_new_with_attrs): initialized here - -2006-08-07 Elijah Newren - - * src/frames.c (meta_frames_button_press_event): Patch from Chris - Ball to not minimize in response to double clicks on the titlebar - when minimiziation should not be allowed. #347377 - -2006-08-07 Elijah Newren - - Patch from Björn Lindqvist to fix button lighting with dragged - clicks. #321474. - - * src/frames.c (meta_frames_button_press_event): update the - prelit_control, (meta_frames_button_release_event): some code - refactoring to simplify things a bit, and make sure to update the - prelit_control - -2006-08-07 Elijah Newren - - * src/keybindings.c (process_keyboard_move_grab): Patch from - Thomas Andersen to return the window to maximized state if the - window was "shaken loose" from maximized state during a resize but - the resize is later aborted. #346719. - -2006-08-07 Elijah Newren - - Patch from Vytautas Liuolia to react to _NET_STARTUP_ID changes, - as proposed for the new startup-notification/EWMH spec. #347515 - - * src/window-props.c (reload_net_startup_id): be sure to act on - the new id instead of just recording it - - * src/window.[ch] (window_activate, meta_window_activate, - meta_window_activate_with_workspace, meta_window_client_message): - change window_activate() to take a workspace parameter instead of - hardcoding to the current workspace, add - meta_window_activate_with_workspace() function needed by - reload_net_startup_id(). - -2006-08-07 Thomas Thurman - - * src/frames.h: add new MetaButtonSpace struct; use it for - close_rect, max_rect, min_rect and menu_rect. (#97703) - - * src/frames.c (control_rect, get_control): modify to support - the new fields in MetaButtonSpace. - - * src/theme.c (meta_frame_layout_get_borders, rect_for_function, - meta_frame_layout_calc_geometry, button_rect): add support for - the new fields in MetaButtonSpace. - -2006-08-07 Elijah Newren - - * src/screen.c (meta_screen_resize_func): patch from Dmitry - Timoshkov to make sure window features get recalculated when the - screen is resized via XRandR. Part of #346927. - -2006-08-04 Elijah Newren - - Patch from Dmitry Timoshkov to fix the heuristic for determining - if windows can be made fullscreen (needed for WINE and possible - also some legacy applications). Part of #346927. - - * src/window.c (recalc_window_features): ignore window decoration - when checking size for determing whether an unresizable window - should be allowed ot be considered for fullscreening - -2006-07-31 Björn Lindqvist - - * src/window.c: Make it so maximized windows do not have rounded - corners. #336850. - -2006-07-30 Jens Granseuer - - * src/tabpopup.c: Fix another C89 vs. C99 issue. #347621. - -2006-07-26 Vincent Untz - - * src/update-from-egg.sh: also kill this - -2006-07-25 Vincent Untz - - * src/Makefile.am, ui.c: Kill usage of libegg. #348633. - -2006-07-24 Thomas Thurman - - * configure.in: post-release version bump to 2.15.21 - -2006-07-24 Thomas Thurman - - * NEWS: 2.15.13 release - -2006-07-24 Björn Lindqvist - - * src/display.c (meta_display_grab_window_buttons): Grab - Alt+Shift+Button1 as well to partially fix operation ordering - issues when trying to snap-move windows. Part of #112478. - -2006-07-21 Thomas Thurman - - * ui.[ch] (filter_func): Avoid a case where a struct's - fields might be updated after it was freed. #348067. - -2006-07-10 Elijah Newren - - * configure.in: post-release version bump to 2.15.13 - -2006-07-10 Elijah Newren - - * NEWS: 2.15.8 release - -2006-06-12 Elijah Newren - - * configure.in: post-release version bump to 2.15.8 - -2006-06-12 Elijah Newren - - * NEWS: 2.15.5 release - -2006-06-10 Elijah Newren - - Patch from Aidan Delaney to tidy tabpopup.c by factoring out - tab_entry_new(). #166890. - - * src/tabpopup.c (tab_entry_new): new function, - (meta_ui_tab_popup_new): use tab_entry_new() to remove a big chunk - of code, plus a few other small cleanups. - -Tue Jun 6 12:46:42 2006 Søren Sandmann - - * configure.in (GETTEXT_PACKAGE): Bunp intltool requirement to - 0.35.0. - -2006-05-29 Elijah Newren - - * HACKING: Slightly more detailed instructions on setting up a - build environment to mention relevant development tools in - addition to the needed development libraries. - -Fri May 26 16:48:29 2006 Søren Sandmann - - * src/effects.c (meta_effect_run_unminimize): Run an unminimize effect - - * src/window.c (meta_window_unminimize): Store a "was_minimized" - boolean in the window. - - * src/window.c (meta_window_show): If the window was minimized, - run an unminimize animation. - - * src/c-window.c (meta_comp_window_run_unminimize): Add an - unminimize animation, running the minimize one in reverse. - -Fri May 26 14:55:07 2006 Søren Sandmann - - * src/c-window.c (meta_comp_window_run_focus): Rename from - _bounce() to _focus(). - -2006-05-26 Elijah Newren - - * src/display.c (meta_display_close): Fix a crash on exit/logout - from assuming a compositor would always exist - -2006-05-25 Elijah Newren - - * src/place.h: - * src/common.h: - Remove MetaWindowEdgePosition enum that isn't used anymore - -Thu May 25 15:56:43 2006 Søren Sandmann - - * src/effects.h (struct MetaEffect): Move duplicated window field - outside the union - - * src/compositor.c: delete duplicated code to get at the window. - -Thu May 25 15:17:29 2006 Søren Sandmann - - * src/c-window.c: Fix compilation in non-compositor case, by - moving the stack functions into the HAVE_COMPOSITOR defines. - -Thu May 25 15:11:58 2006 Søren Sandmann - - * src/c-window.h: Add a destroy notifier to the window. - - * src/c-screen.c (on_window_destroy): New function. - - * src/c-screen.c (meta_comp_screen_add_window): Use the destroy - notifier here. - - * src/c-window.c (generate_phases): New function. Simplify the - minimize animation a lot by generating all the rectangle - information into an array, then processing that. - -2006-05-25 Adam Jackson - - * src/c-window.c: - * src/c-window.h: - * src/compositor.c: - * src/compositor.h: - * src/effects.c: - * src/effects.h: - * src/spring-model.c: - * src/window.c: - Bounce on window focus. - -Wed May 24 22:15:01 2006 Søren Sandmann - - * src/compositor.c (do_effect): Make sure windows are kept on top - of the panel during minimize. - -Wed May 24 21:17:59 2006 Søren Sandmann - - * src/compositor.c (do_effect): Shrink the window instead of - explode it. - - * src/compositor.c (do_effect): don't read the frame if it is - NULL. - - * src/c-window.c (meta_comp_window_run_minimize): Resurrect the - shrinking minimize animation. - - * src/c-window.c (meta_comp_window_fade_in): Make dialogs 90% - translucent. - - * src/c-window.c (update_fade): End at end_fade, not 1.0. - -Wed May 24 19:15:45 2006 Søren Sandmann - - * src/c-window.c (cancel_fade): Add a fade-in animation when - windows are mapped. - -Wed May 24 16:37:11 2006 Søren Sandmann - - * src/c-window.c (private_metacity_window): New function - - * src/c-window.c (meta_comp_window_refresh_attrs): Map metacity's - own windows directly. - -Wed May 24 16:35:54 2006 Søren Sandmann - - * src/c-window.c (private_metacity_window): - -Wed May 24 14:36:42 2006 Søren Sandmann - - * src/c-window.c (meta_comp_window_{freeze,thaw}_stack: Add a - stack-freeze feature to CWindow. - - * src/c-screen.c (meta_comp_screen_restack): Don't restack if the - window is frozen. - -Wed May 24 13:09:49 2006 Søren Sandmann - - * src/c-window.c: Fix compilation in the non-composited case. - -Wed May 24 12:57:32 2006 Søren Sandmann - - * src/c-window.c (meta_comp_window_free): return TRUE when the - window is actually freed. - - * src/compositor.c (do_effect): Disable updating before exploding - the window. - - * src/c-window.c: Make MetaCompWindow refcounted. - - * src/c-window.[ch]: New functions meta_comp_window_{show,hide} - - * src/c-screen.c (meta_comp_screen_unmap): Call - meta_comp_window_hide() instead of directly setting the viewable - status of the node. - - * src/c-screen.c (meta_comp_screen_remove_window): Only remove the - window when it is actually freed. - -Wed May 24 12:45:21 2006 Søren Sandmann - - * src/c-screen.c: Delete unused meta_comp_screen_hide_window(). - -2006-05-23 Adam Jackson - - * src/c-window.c: - * src/c-window.h: - * src/compositor.c: - * src/effects.c: - * src/effects.h: - * src/window.c: - Move shrink effect code from compositor.c to c-window.c. Stubs for - restore effect. Notes in various places for where to hook in - other effects. - -Tue May 23 16:36:04 2006 Søren Sandmann - - * src/compositor.c (do_effect): Also use explode when windows close. - - * src/c-window.c (meta_comp_window_explode): Add refcounting to - comp window, and use it in the explosion effect - - * src/effects.h (struct MetaEffect): Add new MetaCloseEffect. - - * src/display.c (event_callback): Run it from the UnmapNotify - event handler. - -Tue May 23 15:23:58 2006 Søren Sandmann - - * src/c-window.c (send_sync_request): New function to send a sync - request to newly mapped windows. - (on_request_alarm): Show the window here. - -2006-05-23 Adam Jackson - - * src/effects.h: - Add more effect tokens. - -Mon May 22 17:35:52 2006 Søren Sandmann - - * src/effects.[ch]: Beginning of new layer that abstracts - transition effects. - - New functions: - (meta_push_effect_handler): Install an effect handler - (meta_pop_effect_handler): Remove last effect handler - (meta_effect_run_minimize): Create a minimize effect and pass it - to the handler. - (meta_effect_end): Called by handler when the effect is finished. - - * src/compositor.c: Move explosion code form there to src/c-window.c. - - * src/c-screen.c: Delete explosion related code. - -2006-05-22 Björn Lindqvist - - * common.h (enum MetaCursor): - * display.c (meta_display_create_x_cursor): Make mouse cursor when - moving windows become a hand. Fixes #337376. - -2006-05-19 Björn Lindqvist - - * frames.c: Fix a logic bug so that the whole titlebar becomes - sensitive to mouse clicks. Fixes #336320. - -2006-05-18 Björn Lindqvist - - * resizepopup.c: Remove the unused attributes resize_gravity, - width_inc, height_inc, min_width, min_height, frame_left, - frame_right, frame_top, frame_bottom, tick_origin_x, tick_origin_y - from the MetaResizePopup struct. Delete all code that references - those attributes. - -2006-05-15 Elijah Newren - - * configure.in: post-release version bump to 2.15.5 - -2006-05-15 Elijah Newren - - * NEWS: 2.15.3 release - -2006-05-15 Elijah Newren - - Revert the accessibility module loading workaround from Gnome - 2.6, since gtk+ has long since fixed this for us. #123372. - - * src/Makefile.am: remove METACITY_LIBDIR define - - * src/main.c (find_accessibility_module, - accessibility_invoke_module, accessibility_invoke, main): remove - the first three of these functions and all calls to them - - * src/tabpopup.c (meta_ui_tab_popup_new): not sure if this part of - 120025 needed to be reverted but doing the reversion, if wrong, is - the best way to get someone from the accessibility team to scream, - er, I mean comment. ;-) - -2006-05-15 Elijah Newren - - * src/screen.c (reload_xinerama_infos): Patch from - jylefort@FreeBSD.org to prevent a crash when changing resolution. - Fixes #340847. - -2006-05-15 Björn Lindqvist - - * places.[ch] (intcmp, window_get_edges, - get_windows_showing_on_same_screen, get_vertical_edges, - get_horizontal_edges, meta_window_find_next_vertical_edge, - meta_window_find_next_horizontal_edge, - meta_window_find_nearest_vertical_edge, - meta_window_find_nearest_horizontal_edge): Remove the preceeding - functions as they are all obsoleted by the new edge-resistance - stuff. Fixes #341561. - -2006-05-15 Paolo Borelli - - * src/prefs.c (update_binding): plug a small leak. - -2006-05-12 Elijah Newren - - * configure.in: I don't think we want a config file for the - no-gconf case; embedded people would prefer hard-coding things - into the binary - (http://mail.gnome.org/archives/metacity-devel-list/2006-May/msg00010.html) - -2006-04-25 Elijah Newren - - * HACKING: Clarify that gnome-common is needed now that autogen.sh - has been rewritten to use gnome-autogen.sh - -Fri May 5 12:50:58 2006 Søren Sandmann - - * src/c-window.c (has_counter): Some experimental code to handle - sync counter notifications on a window. - - * src/c-screen.c (meta_comp_screen_add_window): Pass a MetaDisplay - -2006-04-25 Elijah Newren - - Clear _NET_WM_VISIBLE_NAME (and the ICON_ equivalent) when no - longer being used. Fixes #330671. - - * src/window.[ch] (struct MetaWindow): new - using_net_wm_visible_name and using_net_wm_visible_icon_name bits, - (meta_window_new_with_attrs): initialize these new bits to false - - * src/window-props.c (set_title_text, set_window_title, set_icon_title): - if the _NET_WM_VISIBLE_(ICON_)NAME property was previously set but - doesn't need to be this time, make sure to clear it - -2006-04-25 Elijah Newren - - * rationales.txt: add three new tracker bugs - -Thu May 4 13:30:04 2006 Søren Sandmann - - * src/ui.h: Delete unused META_PRIORITY_COMPOSITE - - * src/ui.c: Delete argument from meta_ui_get_display(). - - * src/c-window.c: Remove the xid->window hashtable and associated - code. - - * src/c-screen.[ch]: Rename MetaScreenInfo to MetaCompScreen. Put the - xid->windows table here instaed of as a static variable. Also make - sure that CompWindows are freed when the screen is unredirected. - - * src/display.c: Delete non USE_GDK_DISPLAY case, as it didn't - work and hasn't been compiled for a long time. - - * src/display.[ch] (meta_display_open): Remove argument as it was - always NULL (and couldn't possibly be anything else in the - USE_GDK_DISPLAY case). - -Tue May 2 17:12:54 2006 Søren Sandmann - - * src/c-window.[ch]: New files - - * src/c-screen.c: Move WindowInfo struct to new c-window.[ch] - files. Delete various bits of obsolete, commented-out code. - -Fri Apr 28 12:53:23 2006 Søren Sandmann - - * src/core.c (get_window): New function. - * src/core.c: Use get_window() instead of cutted-and-pasted code - all over the place. - -2006-04-25 Elijah Newren - - * configure.in: post-release version bump to 2.15.3 - -2006-04-25 Elijah Newren - - * NEWS: 2.15.2 release - -2006-04-25 Elijah Newren - - * autogen.sh: Nuke the old version, copy one from gcalctool that - uses gnome-autogen.sh. Seems to fix the - translations-aren't-included-in-the-tarball problem. Fix from - Rodney in IRC. - -2006-04-25 Elijah Newren - - * configure.in: post-release version bump to 2.15.2 - -2006-04-25 Elijah Newren - - * NEWS: 2.15.1 release - * configure.in: belated post-release version bump to 2.15.1 - * src/Makefile.am: Include boxes.h so that control-center won't - fail to build #339708. - -2006-04-24 Elijah Newren - - * NEWS: 2.15.0 release - -2006-04-20 Brian Pepple - - #337951. - - * po/LINGUAS: New file listing all supported languages. - - * configure.in: Use po/LINGUAS instead of including all languages - directly in this file. See the wiki for more information: - http://live.gnome.org/GnomeGoals/PoLinguas. - -2006-04-19 Thomas Andersen - - * src/window-props.c (reload_transient_for): warn and ignore if - transient_for is set to a non-top-level window. Fixes #335524. - -2006-04-19 Björn Lindqvist - - * src/frames.c (struct CachedPixels, meta_frames_destroy, - invalidate_cache, generate_pixmap, populate_cache, - cached_pixels_draw, meta_frames_expose_event, - meta_frames_paint_to_drawable): - - Replace while loops iterating over sequences with for loops. Also, - replace the attributes in the CachedPixels struct with a list of - four CachedFramePiece:s, this allows iteration over the four - pixmaps instead of treating each one separately. Fixes #338359. - -2006-04-18 Björn Lindqvist - - * makefile.am: Add boxes.{c,h} to libmetacity_private - * src/theme-parser.c (check_expression): - * src/theme-viewer.c (run_position_expression_tests): - Use meta_rect (). - - * src/theme.c: Replace while loops iterating over sequences with - for loops. - - * src/theme.c, src/theme.h (struct _MetaPositionExprEnv, - meta_draw_op_draw, meta_draw_op_list_draw, - meta_theme_draw_menu_icon): Use MetaRectangles in function - prototypes instead of x, y, with, height ints where applicable. - -2006-04-18 Kjartan Maraas - - * configure.in: Remove obsolete entry for no_NO - * po/no.po: And the translation. - -2004-04-17 Thomas Thurman - - * keybindings.c (count_bindings, rebuild_binding_table): - * prefs.c (change_notify, screen_bindings, - window_bindings, init_bindings, update_binding, - find_and_update_list_binding, update_list_binding, - meta_prefs_get_window_binding): Allow any keybinding pref - to be specified either with , a string, or _list, - a list of strings, or both. Fixes #164831. - -2006-04-16 Elijah Newren - - Patch from Dan Sanders to fix #334899. - - * window.c (meta_window_new_with_attrs): Unminimize ancestors of - new windows when mapped; this prevents e.g. confirmation windows - from causing applications to appear locked when closing via the - window list. - -2006-04-15 Elijah Newren - - Patch from Dan Sanders to fix #335076. - - * src/core.c (meta_core_maximize, meta_core_toggle_maximize, - meta_core_unmaximize): - * src/window.c (meta_window_client_message): - Raise windows on maximize/unmaximize. - -2006-04-15 Elijah Newren - - * src/display.h: Patch from Andy Morum to fix the build with - --disable-xsync. #336605 - -2006-04-14 Elijah Newren - - * HACKING: Include instructions on setting up a minimal - building/testing environment - -2006-04-14 Thomas Thurman - - Add a tabbing function, bound to alt-f6 by default, to cycle - through the windows of the current application. Fixes #94682. - - * src/common.h: two new MetaGrabOpts values for group switching - * src/display.c (ping_data_free, meta_display_in_grab_op, - IN_TAB_CHAIN): adapt to new MetaGrabOpts - * src/display.h: new enum value for MetaTabList for group switching - * src/keybindings.c (meta_display_process_key_event): - adapt to new MetaGrabOpts - (process_tab_grab): adapt to new MetaGrabOpts, and use switch - statement for cancelling instead of if statement - * src/metacity.schemas.in: new keybindings - * src/prefs.c, src/prefs.h: handle new keybindings - * src/window.h: define META_WINDOW_IN_GROUP_TAB_CHAIN macro - -2006-04-14 Elijah Newren - - * HACKING: Include reasons why gdk/gtk.h and core includes like - display.h/window.h must be kept separate. Taken from a private - email from Havoc. - -2006-04-13 Alejandro Andres - - * README: Fixed broken links. #333303 - -Thu Apr 13 12:23:28 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_add_window): Check for both - POPUP and DROPDOWN. - -2006-04-13 Björn Lindqvist - - * src/async-getprop.c, src/async-getprop.h - (async_get_property_handler, ag_task_get_reply_and_free): - * src/testasyncgetprop.c (try_get_reply, run_speed_comparison): - Change unsigned chars to chars. - - * src/display.h (struct MetaDisplay): - * src/keybindings.c (reload_modmap): - Change unsigned ints to ints. - - * src/screen.c (set_workspace_names) - * src/stack.c (meta_stack_sync_to_server): - * src/xprops.c (utf8_string_from_results, utf8_list_from_results, - class_hint_from_results, meta_prop_get_values): - Introduce casts. - - Add a number of casts and change signedness on a number of - variables so that Metacity compiles with many fewer - warnings. Fixes #336032. - -2006-04-12 Elijah Newren - - Patch from Ron Yorston to add a focus_new_windows option. Default - is 'smart' (focus by default but normal focus-stealing-prevention - can kick in); 'strict' is current other choice (like 'smart' - except that programs launched by the terminal will not be - focused). Fixes remainder of #326159. Should also close #152004 - and a bunch of others. - - * src/common.h: - Add a MetaFocusNewWindows enum giving the current types allowed - - * src/display.h: - Update docs on allow_terminal_deactivation to note that it is only - relevant when focus_new_windows is 'strict' - - * src/metacity.schemas.in: add the new gconf key and explanation - - * src/prefs.[ch] (#define KEY_FOCUS_NEW_WINDOWS, static gboolean - focus_new_windows, update_focus_new_windows, meta_prefs_init, - change_notify, meta_prefs_get_focus_new_windows, - meta_preference_to_string): - Add all the normal preference handling stuff for this new - focus-new-windows option. - - * src/window.c (window_state_on_map, meta_window_set_user_time): - Don't focus windows launched from a terminal - -Mon Apr 10 16:44:51 2006 Søren Sandmann - - * src/c-screen.c (is_menu): Check if the window is a menu and make - it 90% opaque in that case. - - * src/c-screen.c (claim_selection): Handle CM_Sn selection - properly. - - * src/c-screen.c: Remove debug spew - - * src/screen.c (meta_screen_composite_all_windows): Remove debug spew - -2006-04-10 Björn Lindqvist - - * display.c (meta_display_open, event_callback): - * ui.c (meta_ui_get_double_click_timeout): - - Delete dead code that used to handle double click on the - titlebar. Remove the attributes last_button_time, - last_button_xwindow, last_button_num and is_double_click from - MetaDisplay and the functions meta_ui_get_double_click_timeout() - and meta_display_is_double_click() from their respective - files. Fixes #337507. - -2006-03-27 Gora Mohanty - - * src/metacity.schemas.in: - * src/theme.c: - Changes strings to make them more readable, and more translatable. - Fixes #335720. - -2006-04-02 Elijah Newren - - Fix constraints bug causing negative width windows and crashes. - #336651 - - * src/constraints.c (constrain_partially_onscreen): Don't - accidentally shove & resize the window by requiring more pixels to - be onscreen than the size of the window. - -Fri Mar 31 16:44:56 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_unredirect): Release the GL - window here. Disconect from the magnifier, not the stacker. - -Fri Mar 31 12:24:26 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_redirect): Only use magnifier - when USE_MAGNIFIER is set. - - * src/compositor.c (meta_compositor_free_window): Only wobble when - USE_WOBBLE is set. - -Fri Mar 31 12:13:21 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_redirect): Don't hardcode - screen size. - -Thu Mar 30 17:01:12 2006 Søren Sandmann - - * src/compositor.c (struct MetaCompositor): Fix the memory - corruption in a better way. - -Thu Mar 30 16:38:35 2006 Søren Sandmann - - * src/compositor.c (meta_compositor_begin_move): Fix an illegal write. - -Thu Mar 30 16:13:52 2006 Søren Sandmann - - * composite.c: Turn wobbling back on Add new explosion effect. - -2006-03-29 Elijah Newren - - Fix grouping in the presence of ancestors; caught by Björn. - #336184 - - * src/group.c (meta_window_compute_group): Use new - meta_window_find_root_ancestor() function to get ancestor; for the - computed group, use the ancestor's group instead of the ancestor - itself - - * src/window.[ch] (meta_window_find_root_ancestor, - meta_window_raise): split meta_window_find_root_ancestor() - functionality of meta_window_raise() and make it available - elsewhere - -2006-03-29 Elijah Newren - - * rationales.txt: Add bugs about pointer warping; update - raise-on-click ones. - -2006-03-29 Thomas Thurman - - Abstract out the functions for setting/unsetting demands attention - hint and avoid doing it when the window isn't obscured. Fixes the - remainder of #305882. - - * src/window.c, src/window.h (meta_window_set_demands_attention, - meta_window_unset_demands_attention): new functions to mark a - window as needing or not needing the user's attention - * src/window.c (meta_window_show, window_activate, - meta_window_focus, meta_window_configure_request, - meta_window_client_message): use the new set/unset - demands attention functions. - -2006-03-29 Björn Lindqvist - - * src/resizepopup.c: - * src/resizepopup.h: - * src/window.c (meta_window_refresh_resize_popup): - Aggregate the x, y, width and height attributes of MetaResizePopup - to one MetaRectangle rect attribute and update code using the - MetaResizePopup struct. Fixes #335177. - -2006-03-28 Elijah Newren - - * MAINTAINERS: New file. #335026. ;-) - -Tue Mar 28 09:57:26 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_add_window): Also check for overlay_window. - - * src/c-screen.c (meta_screen_info_redirect): Trap errors out of - unredirect(). - -2006-03-25 Thomas Thurman - - * src/window.c, src/window.h (update_net_wm_state, - update_mwm_hints, update_wm_class, update_transient_for): - deleted and moved into window-props.c - (meta_window_new_with_attrs): added constructing field - and four new initial properties (as above) - (meta_window_recalc_features, - meta_window_recalc_window_type): new functions - - * src/window-props.c (init_net_wm_state, reload_net_wm_state - init_mwm_hints, reload_mwm_hints, init_wm_class, - reload_mwm_class, init_transient_for, reload_transient_for): - new functions, moved in from window.c - - (meta_display_init_window_prop_hooks): initialise new properties - - Closes #309567. - -2006-03-25 Paolo Borelli - - * src/prefs.c: use g_str_has_prefix instead of a local copy - of the function. - -2006-03-16 Ray Strode - - Add patch from Elijah Newren to fix type - for compositing_manager schema entry (bug 335901) - - * src/metacity.schemas.in: Change type from "boolean" to "bool" - and default value from "FALSE" to "false" - -Wed Mar 22 13:16:48 2006 Søren Sandmann - - * src/compositor.c (meta_compositor_remove_window): Actually - remove the window. - - * src/c-screen.c (meta_screen_info_remove_window): Only remove - node if non-NULL - -Wed Mar 22 10:33:21 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_redirect): Put a square below - the desktop stack. - -Mon Mar 20 11:50:44 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_redirect): Put the desktop into - a magnifier. - - * src/c-screen.c (struct MetaScreenInfo): Add a CmMagnifier - - * src/c-screen.c (meta_screen_info_redirect): Move some of the gl - window related stuff here. - -2006-03-16 Soren Sandmann (sandmann@daimi.au.dk) - - * src/c-screen.c (meta_screen_info_set_target_rect): Put inside - COMPOSIT_EXTENSIONS - -2006-03-03 Thomas Thurman - - Always set _NET_WM_STATE when a window is shown or - hidden, even if it wasn't mapped. Fixes #315142. - - * src/window.c (meta_window_hide, meta_window_show): - call set_net_wm_state unconditionally - -2006-03-16 Elijah Newren - - Add debugging information for edge resistance - - * src/edge-resistance.c (cache_edges): print out the edges that - are being cached if in verbose mode, - (meta_window_edge_resistance_for_move, - meta_window_edge_resistance_for_resize): if edge resistance kicked - in then print out a message about it - - * src/util.c: - * src/util.h: - Add META_DEBUG_EDGE_RESISTANCE to MetaDebugTopic enum list - -Thu Mar 16 14:55:18 2006 Søren Sandmann - - * src/c-screen.c (struct WindowInfo): Maintain the size of the - window. - -Wed Mar 15 16:30:09 2006 Søren Sandmann - - * src/compositor.c (set_geometry): Use set_target_rect() instead - of set_size(). - - * src/c-screen.c: Add set_target_rect() as a way of scaling windows. - - * src/window.c (meta_window_handle_mouse_grab_op_event): Turn - updates on after a button release. - - * src/window.c (meta_window_move_resize_internal): Fix - indentation. - -Wed Mar 15 11:34:54 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_add_window): Use unset_patch() - instead of unset_geometry(). - -Tue Mar 14 11:57:46 2006 Søren Sandmann - - * src/compositor.c: Comment out wobbling - - * src/compositor.c (blow_up): remove this function - - * src/compositor.c (process_configure_notify): Uncomment - set_size(). - - * src/c-screen.c (meta_screen_info_set_updates): When updates are - true, set all the properties such as size and shape. - - * src/c-screen.c (meta_screen_info_add_window): Create a special - WindowInfo structure for each window. - - * src/c-screen.c (meta_screen_info_set_size): Set size and output - shape of the drawable node. - -2006-03-13 Elijah Newren - - * README: - * configure.in: - Update to reflect that we're now targetting 2.15 development. - -2006-03-12 Thomas Thurman - - * src/window-props.c (set_title_text): Mark a particular - string for translation. #334332. - -2006-03-06 Ryan Lortie - - * src/window.c (meta_window_free): Only unmaximise window before - freeing if the window is actually maximised. #333563. - -Fri Mar 3 15:31:04 2006 Søren Sandmann - - * src/c-screen.c (meta_screen_info_new): Update for libcm API - change. - -Wed Mar 3 13:25:03 2006 Søren Sandmann - - * src/compositor.c, src/c-screen.[ch]: Split the ScreenInfo data - structure into separate, new files c-screen.[ch]. - - * src/errors.c (x_error_handler): Forward foreign errors to - foreign displays. - - * src/errors.c (meta_errors_register_foreign_display): Implement - this function - - * src/errors.h: Add new meta_errors_register_foreign_display() - -Tue Feb 28 14:49:23 2006 Søren Sandmann - - * src/compositor.c: Put the windows in a stacker rather than - do the traversing outselves. - -2006-02-27 Elijah Newren - - Patch from Thomas Thurman to prevent setting cycle_windows to - keybindings that won't work. #329676 - - * src/prefs.c (update_binding): - Make sure that bindings which require a modifier key are set to a - keybinding with one or else that the binding is reverted. - - * src/ui.[ch] (meta_ui_accelerator_name): - New function - -2006-02-27 Elijah Newren - - Patch from Thomas Thurman to work around buggy application - grouping with transient windows. #328211 - - * src/group.c (meta_window_compute_group): - Put transients in the same group with their parent, always. - - * src/window.c (update_transient_for): - Update group too - -2006-02-27 Elijah Newren - - * configure.in: - Patch from Sylvain Bertrand to fix build issues with library - search order. #330695. - -Sat Feb 25 14:50:17 2006 Søren Sandmann - - * src/window.c: Remove include of flash.h - -Sat Feb 25 11:46:14 2006 Søren Sandmann - - * src/display.c (meta_display_begin_grab_op): Call - meta_compositor_begin_move if there is a compositor - - * src/compositor.c (meta_compositor_begin/update/end_move): - Implement those functions. - - * src/spring-model.[ch]: New files - -Thu Feb 23 15:40:52 2006 Søren Sandmann - - * src/compositor.c (meta_compositor_manage_screen): Don't attempt - to manage the screen if it already is managed. - - * src/compositor.c (meta_compositor_unmanage_screen): Synchronize - the display. - -2006-02-19 Thomas Thurman - - Removed "move to another workspace" menu when there are - exactly two workspaces. Fixes #151183. - - * src/menu.c (meta_window_menu_new): clear - META_MENU_OP_WORKSPACES bit when n_workspaces==2 - -Fri Feb 17 11:56:35 2006 Søren Sandmann - - * src/screen.c (meta_screen_free): Only uncomposite the screen if - there is a compositor. - - * src/compositor.c (meta_compositor_new): Warn and fail if the - server doesn't have composite - -Thu Feb 16 18:57:48 2006 Søren Sandmann - - * src/compositor.c: Fix the build when --enable-compositor is - there. - -Thu Feb 16 15:54:48 2006 Søren Sandmann - - * src/compositor.c: Insert #ifdef's to make it build again - -Thu Feb 16 15:24:42 2006 Søren Sandmann - - * src/screen.c (meta_screen_composite_all_windows): New function. - - * src/prefs.[ch], src/metacity.schemas.in: Add new - compositing_manager key. - - * src/display.c (prefs_changed_callback): Handle - META_PREF_COMPOSITOR_MANAGER - - * src/display.c (event_callback): Only call - meta_compositor_process_event() if there is in fact a compositor. - - * src/display.c (enable/disable_compositor): Add code to - enable/disable compositor at runtime - -Wed Feb 15 18:42:03 2006 Søren Sandmann - - * src/compositor.[ch]: Add code to destroy compositor. Implement - unmanage_screen() functionality. - -Wed Feb 15 14:47:50 2006 Søren Sandmann - - * src/compositor.c (meta_compositor_unminimize): Add unused wobbly - unminimize animation by Kristian - - * src/compositor.c (meta_compositor_minimize): Add wobbly minimize - animation by Kristian. - - * src/compositor.c: Add support for turning updates on and off. - - * src/window.c (meta_window_move_resize_internal): Use - sync counter to make composited resizing tear free - -2006-02-14 Elijah Newren - - Patch from Jens Granseuer to fix more build issues with gcc 2.95. - #331166. - - * src/prefs.c (meta_prefs_init): - Remove C99 style variable initiailization - -2006-02-13 Elijah Newren - - * configure.in: post-release version bump to 2.13.144 - -2006-02-13 Elijah Newren - - * NEWS: 2.13.89 release - -2006-02-13 Elijah Newren - - * src/keybindings.c (process_tab_grab): - We had that prev_window code in multiple places and it was all - identical. Let's just stick it in one place to make the function - easier to read. - -2006-02-13 Thomas Thurman - - * src/keybindings.c (process_tab_grab): - Allow alt-escape to cancel alt-tabbing, and vice versa. Fixes - #141425. - -2006-02-11 Thomas Thurman - - Disable alt-f7 if a window can't be moved, and alt-f8 if it - can't be resized. Fixes #328920. - - * src/keybindings.c (handle_begin_move, handle_begin_resize): - check window->has_*_func before beginning operation - -2006-02-11 Elijah Newren - - Add a man page for metacity. Original version taken from Debian - (written by Thom May and Akira Tagoh) and updated by Luke Morton - and Philip O'Brien. Necessary auto-fu supplied by Philip O'Brien. - Fixes #321279. - -2006-02-11 Elijah Newren - - * src/stack.h (enum MetaStackLayer): - * src/stack.c (get_standalone_layer): - actually use META_LAYER_TOP but just manually make it equal to - META_LAYER_DOCK. Add a note point to the EWMH for why we do this. - #330717 - -2006-02-11 Elijah Newren - - * src/window.c (enum GnomeWinLayer): remove this legacy cruft that - we stopped using years ago - -2006-02-10 Thomas Thurman - - Avoid a memory leak when checking which workspace(s) a window is - on. Fixes #322059. - - * src/workspace.h (struct MetaWorkspace): - * src/workspace.c (meta_workspace_new, meta_workspace_free): - added list_containing_self member to MetaWorkspace - - * src/window.c (meta_window_get_workspaces): use - window->workspace->list_containing_self instead of allocating (and - leaking) such a list on the fly. - -2006-02-09 Thomas Thurman - - * src/testboxes.c (test_regions_okay, test_clamping_to_region): - add messages to explain that warnings are harmless - -Tue Feb 7 00:58:05 2006 Soeren Sandmann - - * src/compositor.c: Wrap fade code in #ifdef HAVE_COMPOSITE_EXTENSIONS - -Mon Feb 6 17:45:39 2006 Søren Sandmann - - * src/compositor.c: New fancy minimize animation. Fade windows in - and out. - -2006-02-03 Thomas Thurman - - * src/display.c (event_callback): produce warning when invalid - events with no timestamp are received, rather than failing an - assertion - -Thu Feb 2 17:58:22 2006 Søren Sandmann - - * compositor.c (process_map): update the pixmap. - (update) print out framerate. - (dump_stacking_order) new debug - function. - (meta_compositor_add_window) error trap fixes - (MiniInfo): Make the minimize animation fade out. - -2006-01-30 Elijah Newren - - * configure.in: post-release version bump to 2.13.89 - -2006-01-30 Elijah Newren - - * NEWS: 2.13.55 release - -2006-01-30 Elijah Newren - - * src/display.[ch] (struct MetaDisplay), meta_display_open, - meta_display_set_input_focus_window, - meta_display_focus_the_no_focus_window): Track the active_screen, - (event_callback): If the mouse enters a window on a different - screen, activate the default window on the new screen. May need - to be modified for click-to-focus; we'll wait for feedback. Fixes - #319348. - -2006-01-23 Elijah Newren - - * src/display.c (meta_display_check_threshold_reached): change the - order of the ||'ed items in the if to avoid using an uninitialized - value - - * src/prefs.c (meta_prefs_init): fix a couple uninitialized value - problems - -2006-01-21 Elijah Newren - - Patch from Christian Kirbach to prevent a critical warning crasher - when switching themes. #327847. - - * src/theme.c (meta_theme_free): since themes are only constructed - as needed and may be NULL, check for that before freeing theme - hash tables - -2006-01-21 Elijah Newren - - * src/common.h (enum MetaActionDoubleClickTitlebar): - * src/frames.c (meta_frames_button_press_event): - * src/prefs.c (action_double_click_titlebar_from_string): - * src/metacity.schemas.in: - Patch from Dick Marinus to add a minimize - double-click-titlebar-action; slightly modified to also include a - none action. #300210. - -2006-01-20 Elijah Newren - - * configure.in: post-release version bump to 2.13.55 - -2006-01-20 Elijah Newren - - * NEWS: 2.13.34 release - -2006-01-20 Elijah Newren - - * src/constraints.c (setup_constraint_info): fixed_directions is - only meant for explicit user interactions; disable it for - everything else. There are other bugs and improvements that could - be made with fixed_directions that I should be filing too, but at - least put a FIXME there for now--I'm so lame. Fixes #327822. - -2006-01-20 Elijah Newren - - Avoid flashing when closing a maximized window. Fixes #317254. - - * src/window.c (unmaximize_window_before_freeing): new function - that just fixes the net_wm_state and sends a configure_notify, - (meta_window_free): use unmaximize_window_before_freeing() instead - of meta_window_unmaximize() to avoid flicker - -2006-01-20 Elijah Newren - - Fix unitialized value problem when in raise-on-click mode. Søren, - #327572. - - * src/display.c (meta_display_check_threshold_reached): make - function be a no op if raise_on_click!=FALSE - - * src/display.h (struct MetaDisplay): point out that - grab_initial_[xy] and grab_threshold_movement_reached are only for - raise_on_click==FALSE mode. - -2006-01-20 Elijah Newren - - Patch from Søren to fix some reading-from-free'd-data errors. - #327575 - - * src/edge-resistance.c (meta_display_cleanup_edges): store the - edges in a hash table so that we can still read their values - within the loop from the other array they are stored in, then free - them all at the end. - -2006-01-20 Elijah Newren - - Fix various initialization and default issues, especially for - --disable-gconf. Make --disable-gconf actually work. #326661. - - * configure.in: Fix compilation with --disable-gconf - * src/metacity.schemas.in: Add a note that if any defaults are - changed in this file, src/prefs.c may need to be updated to - reflect the change - * src/prefs.c: set various static global vars to the right default - value, (meta_prefs_init): get the titlebar_font and current_theme - handled better when not using gconf, (struct MetaSimpleKeyMapping, - screen_string_bindings, window_string_bindings): helper vars to - allow some keybindings to work even without gconf, - (init_bindings): initialize bindings for the without-gconf case - too, (init_commands): make sure these are all NULL for the - non-gconf case so that we don't access random memory, - (init_workspace_names): just give these all a default name for the - non-gconf case, - (meta_prefs_change_workspace_name): actually change the name for - the non-gconf case too - -2006-01-20 Elijah Newren - - More careful error handling of values returned by GConf. Fixes - #326615. - - * src/prefs.c (get_bool): new helper function, (meta_prefs_init): - use get_bool to handle the case of a gconf key not existing, - (update_cursor_size): sanity check for sane values - -2006-01-20 Elijah Newren - - Prevent rapidly repeated visual bells from hanging metacity. - Fixes #322032. - - * src/display.h (struct MetaDisplay): add a last_bell_time field, - (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS macro, - XERVER_TIME_IS_BEFORE macro): add parentheses around usage of - macro parameter - - * src/display.c (meta_display_open): initialize last_bell_time, - (event_callback): don't allow more than one bell per second - -2006-01-20 Elijah Newren - - * src/async-getprop.c: - * src/common.h: - * src/display.c: - * src/eggaccelerators.c: - * src/frames.c: - * src/gradient.c: - * src/iconcache.c: - * src/keybindings.c: - * src/metaaccellabel.c: - * src/place.c: - * src/prefs.c: - * src/preview-widget.c: - * src/screen.c: - * src/session.c: - * src/stack.c: - * src/tabpopup.c: - * src/theme-viewer.c: - * src/theme.c: - * src/window-props.c: - * src/window.c: - * src/workspace.c: - * src/tools/metacity-window-demo.c: - * src/wm-tester/test-gravity.c: - * src/wm-tester/test-resizing.c: - * src/wm-tester/test-size-hints.c: - Patch from Kjartan Maraas to fix a lot of tiny issues (unused - variable removal, making unused variables used again, correction - of types passed/declared for printf arguments, removal of unneeded - breaks and returns, dead code removal, dead code revival, renaming - to prevent shadowed variables, declaring unexported functions as - static) spotted by the intel compiler. #321439 - -2006-01-20 Elijah Newren - - Patch from Björn Lindqvist to fix #98340. - - * src/screen.c (meta_screen_ensure_tab_popup): Make sure an - outline border is shown even if a window frame's width is 0. - Also, correctly handle window outlines in showing desktop mode. - -Fri Jan 20 16:42:25 2006 Søren Sandmann - - * src/compositor.c: Make minimize animation update again. - -Thu Jan 19 18:05:47 2006 Søren Sandmann - - * src/compositor.c (meta_compositor_manage_screen): - g_object_unref() rather than ws_region_unref(). - -Thu Jan 19 16:50:50 2006 Søren Sandmann - - * src/compositor.c: Port to changes in libcm - -Tue Jan 17 17:25:29 2006 Søren Sandmann - - * src/compositor.c: Port to changes in libcm. - -2006-01-16 Elijah Newren - - * src/window-props.c: manually define HOST_NAME_MAX if not already - defined to fix Solaris compilation issue. Caught by Damien - Carbery, patch from Havoc. #326745 - -2006-01-16 Elijah Newren - - * configure.in: post-release version bump to 2.13.34 - -2006-01-16 Elijah Newren - - * NEWS: 2.13.21 release - -Mon Jan 16 11:55:20 2006 Søren Sandmann - - * src/compositor.c (meta_compositor_manage_screen): Really turn - off draw-in-a-loop. - -2006-01-15 Kyle Ambroff - - * src/workspace.c (focus_ancestor_or_mru_window): - If no valid window is found in the MRU list, then set focus to the - desktop window. (#317405) - -2006-01-15 Elijah Newren - - Fix accidental overzealous focus holding by the terminal - introduced by the original patch in bug 326159. Windows launched - from panel icons, the panel menu, or global keybindings should get - focus now. #326159. - - * src/display.c (meta_display_open, event_callback): - * src/display.h (struct MetaDisplay): - * src/keybindings.c (process_event): - * src/window.c (meta_window_set_user_time): - Add a new allow_terminal_deactivation field to MetaDisplay and use - it to track whether the user's last action was interaction with - the terminal or some outside action (global keybinding, clicking - on a dock, etc.) likely to launch a new window. - - * src/window.c (window_state_on_map): - Allow the focus switch from a terminal to something else if - allow_terminal_deactiviation is true. - - * src/keybindings.c (handle_panel_keybinding): - Remove some unneeded code. - -2006-01-15 Elijah Newren - - Patch from Jens Granseuer to fix more build issues with gcc 2.95. - #327050. - - * src/boxes.c (meta_rectangle_edge_cmp_ignore_type): - * src/window.c (meta_window_show): - Remove C99 style variable initiailization - -2006-01-14 Elijah Newren - - * src/window.c (__window_is_terminal): Don't dereference a NULL - string. Fixes #327013. - -2006-01-14 Elijah Newren - - * src/compositor.[ch]: fix compilation when - HAVE_COMPOSITE_EXTENSIONS is undefined. #326912 - -Fri Jan 13 16:37:26 2006 Søren Sandmann - - * src/compositor.c (update): Only update on damage events. - -2006-01-13 Elijah Newren - - Patch from Damien Carbery. Fixes #326746. - - * src/util.c: explicitly #include Xlib.h to fix a compilation - issue on Solaris. - -Fri Jan 13 14:40:19 2006 Søren Sandmann - - * configure.in: Add a dependency on libcm when building with - compositor. - - * src/window.c (meta_window_hide): Make this function static. - - * src/window.c (implement_showing): Use meta_compositor_minimize() - to do a weird minimize effect. - - * src/compositor.[ch]: Beginning of new GL based compositor. - - * src/screen.h (struct _MetaScreen): Add void pointer to - compositor data. - - * src/screen.c (meta_screen_new): Remove obsolete compositor - stuff; initialize compositor_data. Don't composite manage screen - out of this function. - - * src/errors.c (x_error_handler): Check that display is non-NULL - before using it. Add comment about how that can happen. - - * src/display.c (meta_display_{begin,end}_grab_op): Remove - explicity damage of windows. - - * src/display.c (meta_display_open): Composite manage all the - screens. - -2006-01-11 Elijah Newren - - * src/textboxes.c (test_area, test_intersect, test_equal, - test_overlap_funcs, test_basic_fitting, test_merge_regions, - test_regions_okay, test_region_fitting, test_clamping_to_region, - test_clipping_to_region, test_shoving_into_region, - test_find_onscreen_edges, - test_find_nonintersected_xinerama_edges, test_gravity_resize, - test_find_closest_point_to_line): - Replace __PRETTY_FUNCTION__ with G_STRFUNC, because lesser - compilers don't support the former. Caught by Damien Carbery, fix - suggested by Ray Strode. #326281. - -2006-01-10 Elijah Newren - - * configure.in: post-release version bump to 2.13.21 - -2006-01-10 Elijah Newren - - * NEWS: 2.13.13 release - -2006-01-10 Elijah Newren - - * src/bell.c: - * src/boxes.c: - * src/boxes.h: - * src/constraints.c: - * src/core.c: - * src/display.c: - * src/display.h: - * src/edge-resistance.c: - * src/frames.c: - * src/keybindings.c: - * src/main.c: - * src/prefs.c: - * src/prefs.h: - * src/screen.c: - * src/screen.h: - * src/window.c: - * src/window.h: - Whoops, I forgot to keep my copyright info updated with my previous - commits as Havoc had asked me to do. Doing that now... - -2006-01-10 Elijah Newren - - Add a raise on click option, basically only because all the major - distros are patching it in anyway. See #326156. - - * src/metacity.schemas.in: add the new gconf key and explanation - - * src/prefs.[ch] (#define KEY_RAISE_ON_CLICK, static gboolean - raise_on_click, update_raise_on_click, meta_prefs_init, - change_notify, meta_prefs_get_raise_on_click, - meta_preference_to_string): - Add all the normal preference handling stuff for this new - raise-on-click option. - - * src/core.c (meta_core_show_window_menu): - * src/display.c (event_callback, meta_display_begin_grab_op): - * src/window.c (window_activate, meta_window_configure_request, ): - Only raise the window if in raise_on_click mode. - - * src/display.c (meta_display_begin_grab_op, - meta_display_end_grab_op, meta_display_check_threshold_reached): - * src/display.h (struct MetaDisplay): - * src/window.c (meta_window_handle_mouse_grab_op_event): - if not in raise-on-click mode only raise on button release if the - click didn't start a move or resize operation; needs a few extra - MetaDisplay fields to handle this - - * src/core.c (meta_core_user_lower_and_unfocus): - no need to do the MRU shuffling if not maintaining the stacking - order == MRU order invariant - - * src/frames.c (meta_frames_button_press_event): - * src/window.c (meta_window_begin_grab_op): - remove an unneeded window raising that is already handled elsewhere - -2006-01-10 Elijah Newren - - Don't "steal" focus from terminal windows for new window mappings - as the difference in usage between terminals and other apps seems - to suggest this difference in treatment. See #326159 for details, - feedback welcome. - - * src/window.[ch] (__window_is_terminal): New function, currently - an ugly hack and should be replaced by a new property set by - applications if the behavior works to our liking, - (window_state_on_map): don't transfer focus to new windows from - terminals unless the new window is a transient of the focused - terminal - - * src/keybindigns.c (handle_panel_keybinding): panel run dialog - keybinding should be counted as an explicit transfer of focus to - the new window, so override the - don't-transfer-focus-from-terminals in this case - -2006-01-09 Elijah Newren - - More thorough handling of source indication. Part of #326041. - - * src/window.c (window_activate): new function based off the old - meta_window_activate but which also takes source indication into - account, (meta_window_active): just call window_activate() with - the necessary source indication to get the behavior wanted, - (meta_window_client_message): check source indication too for - _net_active_window messages - - * src/window.h (enum MetaClientType): convenience enum for source - indication handling - -2006-01-09 Elijah Newren - - Make the taskbar less flash happy and fix up some related stacking - issues. #326035. - - * src/window.c (windows_overlap): new function, - (meta_window_show): if a window is denied focus but doesn't - overlap with the focus window there is no need to set the demands - attention hint nor stack that window below the focus window, - (meta_window_get_outer_rect): we're not modifying the window so - declare it to be const - -2006-01-09 Elijah Newren - - Fix window outline for minimized windows when using alt-esc. - #325092. - - * src/display.c (meta_display_begin_grab_op): Specify the showing - type of tabbing operation (Alt tab vs. alt-esc) in addition to the - listing type of tabbing operation (docks vs normal windows) to - meta_screen_ensure_tab_popup(). - - * src/display.h (enum MetaTabShowType): new convenience enum - - * src/screen.[ch] (meta_screen_ensure_tab_popup): require the - showing type be specified in addition to the tabbing type; put the - outline around the window instead of the icon when in alt-esc - mode. - -2006-01-09 Elijah Newren - - Fix reduced resources resize handling for windows with sizing or - resizing constraints. #325774. - - * src/display.c (meta_display_end_grab_op): Provide constraints.c - with the correct gravity information. - -2006-01-09 Elijah Newren - - Be more strict about what is considered a valid region with - partial struts. Fixes #322070. - - * src/boxes.[ch]: - (meta_rectangle_expand_region_conditionally): - new function behaving like meta_rectangle_expand_region() but - which only does so when the width and height of the rectangles - meet a certain threshold - - (replace_rect_with_list): - Remove a compiling warning - - * src/constraints.c: - (constrain_partially_onscreen): - provide minimum thresholds in each direction for the size of the - rectangles to avoid cases where only a single pixel thick layer of - a window might be showing - -2006-01-09 Elijah Newren - - * src/bell.c (meta_bell_notify_frame_destroy): Use the right - function to remove the timeout so that we don't crash if removed - at an inopportune time. Fixes #322031. - -2006-01-09 Elijah Newren - - * src/edge-resistance.c (apply_edge_resistance): Remove the - "pull-away" edge resistance. Fixes another of the zillions of - issues covered in #321905. - -2006-01-09 Elijah Newren - - * src/edge-resistance.c (apply_edge_resistance): Revert to the old - edge resistance behavior for keyboard movement/resizing based - resistance. Not only makes the code much simpler and shorter, but - also fixes another of the zillions of issues covered in #321905. - -2006-01-09 Elijah Newren - - * src/edge-resistance.c (apply_edge_resistance): Remove the - timeout resistance at screen/xinerama edges for the whiners. - Okay, it made sense. Fixes another of the zillions of issues - covered in #321905. - -2006-01-09 Elijah Newren - - * src/edge-resistance.c (apply_edge_resistance): Make extra - timeout edge resistance apply even if one edge already offscreen. - Fixes another of the zillions of issues covered in #321905. - -2006-01-09 Elijah Newren - - Allow edge resistance at both sides of a window and also when - edges don't overlap but are a single pixel away from doing so. - Fixes one of the zillions of issues covered in #321905. - - * src/boxes.[ch]: - (meta_rectangle_edges_align): - new function to handle the overlap or off by one determining - whether edge resistance should kick in for an edge. - - (meta_rectangle_edge_cmp_ignore_type): - new function to sort edges but ignore the type so that e.g. left & - right edges of windows can be used interchangeably. - - (meta_rectangle_edge_cmp): - now uses meta_rectangle_edge_cmp_ignore_type() to do most the work - and just adds an extra condition - - * src/edge-resistance.c: - (find_nearest_position): - use meta_rectangle_edges_align() now to determine whether the - edges align, - - (apply_edge_resistance, apply_edge_resistance_to_each_side): - have the edge resistance kick in if either the beginning or ending - positions would cause overlap in the given direction -- fixes an - uncommon but annoying corner case, - - (apply_edge_snapping, apply_edge_resistance_to_each_side, - meta_display_cleanup_edges, - stupid_sort_requiring_extra_pointer_dereference, cache_edges): - mix edges from both sides now - -2006-01-09 Elijah Newren - - Plug a few leaks. Fixes #309178. - - * src/main.c (main): remove an unneeded g_set_prgname() call, free - some strings allocated by the GOptions parsing - -2006-01-02 Elijah Newren - - Patch from Björn Lindqvist to fix a logic error. #322149. - - * src/window.c (update_resize): && should have been ||. - -2006-01-02 Elijah Newren - - Patch from Jens Granseuer to fix build with gcc 2.95. #322622. - - * src/boxes.c (meta_rectangle_region_to_string, - meta_rectangle_edge_list_to_string, fix_up_edges): - * src/constraints.c (meta_window_constrain, setup_constraint_info, - place_window_if_needed, constrain_maximization, - constrain_fullscreen, constrain_size_increments, - constrain_size_limits, constrain_aspect_ratio, - do_screen_and_xinerama_relative_constrai, - constrain_to_single_xinerama, constrain_fully_onscreen, - constrain_partially_onscreen): - * src/edge-resistance.c (find_nearest_position, - apply_edge_resistance, apply_edge_resistance_to_each_side): - * src/testboxes.c (test_clamping_to_region, - test_clipping_to_region, test_shoving_into_region): - * src/window.c (meta_window_new_with_attrs, - meta_window_apply_session_info, meta_window_resize, - meta_window_resize_with_gravity, meta_window_configure_request): - Remove C99 style variable initiailization - -2006-01-02 Elijah Newren - - * configure.in: post-release version bump to 2.13.13 - -2006-01-02 Elijah Newren - - * NEWS: 2.13.8 release - -2005-12-27 Elijah Newren - - Make the workspace switcher work with dual-head (non-xinerama) - setups. Fixes #319423. - - * src/display.c (meta_display_open, event_callback, - meta_display_focus_the_no_focus_window): - * src/display.h (struct MetaDisplay, - meta_display_focus_the_no_focus_window): - * src/keybindings.c (primary_modifier_still_pressed): - * src/screen.c (meta_screen_new): - * src/screen.h (struct MetaScreen): - * src/window.c (meta_window_new_with_attrs, meta_window_show): - * src/workspace.c (meta_workspace_focus_default_window): - Replace display->no_focus_window with a no_focus_window for each - screen. - - * src/display.[ch] (meta_display_xwindow_is_a_no_focus_window, - event_callback): - * src/window.c (meta_window_new_with_attrs): - New utility function, meta_display_xwindow_is_a_no_focus_window(), - for checking if the given xwindow is a no_focus_window for one of - the screens. - -2005-12-27 Elijah Newren - - * src/tabpopup.c (meta_ui_tab_popup_new): since the title is going - to be treated as markup, escape it. Fixes #324846. - -2005-12-13 Kang Jeong-Hee - - * src/compositor.c: replace old call to width and height - of MetaScreen struct with rect.width and rect.height. - Now compile ok. - * src/delete.c: make an int variable into unsigned int. - Now compile warning has gone. - -2005-12-12 Elijah Newren - - * configure.in: post-release version bump to 2.13.8 - -2005-12-12 Elijah Newren - - * NEWS: 2.13.5 release - -2005-12-12 Elijah Newren - - * src/window.c (update_net_frame_extents): make the debugging - message actually correspond to the code. Patch from Björn - Lindqvist. Fixes #322051. - -2005-11-29 Kjartan Maraas - - * src/screen.h: Make the wireframe a bit slimmer. - Closes bug #320051. - -2005-11-24 Davyd Madeley - - * src/window-props.c: display hostname in titlebar for remote X - clients. Closes bug #322202. - -2005-11-22 Elijah Newren - - * configure.in: post-release version bump to 2.13.5 - -2005-11-22 Elijah Newren - - * NEWS: 2.13.3 release - -2005-11-22 Elijah Newren - - Don't allow removing a window from maximized or fullscreened state - to place the titlebar under the top panel. Fixes #322075. - - * src/display.c (handle_net_moveresize_window): fix up previous - comments now that I know a little more, modify the code just - slightly to clarify that this is NOT a manual user move/resize - operation - - * src/window.c (meta_window_unmaximize, - meta_window_unmake_fullscreen, - meta_window_shove_titlebar_onscreen): - don't claim that these are manual user move/resize operations - -2005-11-21 Elijah Newren - - * src/constraints.c (constrain_partially_onscreen): Relax the - partially onscreen constraint to allow the titlebar to touch the - bottom panel in order to make the new constraints code function - the same as the old version. Fixes #322071. - -2005-11-21 Elijah Newren - - * src/constraints.c (place_window_if_needed): When updating the - xinerama due to placement, update which maximal/spanning rect set - to use as well. Fixes #322068. - -2005-11-21 Elijah Newren - - * doc/strut-and-related-updating.txt: It took me a little while to - figure out how struts & workareas are updated and to learn what - all the related functions were used for so I thought I'd clean up - my notes and make them available. This will probably be more - useful now since regions and edges are also computed and stored at - the same time as the workareas. - -2005-11-20 Elijah Newren - - * src/constraints.c (place_window_if_needed): compute the frame - geometry due to maximization only after actually maximizing. - Fixes #321902. - -2005-11-21 Davyd Madeley - - * src/edge-resistance.c (meta_display_compute_resistance_and_snap): - Use GPOINTER_TO_INT() macro instead of cast to allow compilation on - 64-bit architectures without warning. - -2005-11-19 Elijah Newren - - * src/edge-resistance.c (apply_edge_resistance): differentiate - between movement towards an edge and movement away from one. Pick - smaller constants for movement away from an edge. - -2005-11-19 Elijah Newren - - * configure.in: post-release version bump to 2.13.3 - -2005-11-19 Elijah Newren - - * NEWS: 2.13.2 release - -2005-11-18 Elijah Newren - - Merge of all the changes on the constraints_experiments branch. - This is just a summary, to get the full ChangeLog of those - changes (approx. 2000 lines): - cvs -q -z3 update -Pd -r constraints_experiments - cvs -q -z3 diff -pu -r CONSTRAINTS_EXPERIMENTS_BRANCHPOINT ChangeLog - - Bugs fixed: - unfiled - constraints.c is overly complicated[1] - unfiled - constraints.c is not robust when all constraints - cannot simultaneously be met (constraints need to be - prioritized) - unfiled - keep-titlebar-onscreen constraint is decoration - unaware (since get_outermost_onscreen_positions() - forgets to include decorations) - unfiled - keyboard snap-moving and snap-resizing snap to hidden - edges - 86644 - resize should have a shift option like move does - 109553 - gravity w/ simultaneous move & resize doesn't work - 113601 - maximize vertical and horizontal should toggle and be - constrained - 122196 - windows show up under vertical panels - 122670 - jerky/random resizing of window via keyboard[2] - 124582 - keyboard and mouse snap-resizing and snap-moving - erroneously moves the window multidimensionally - 136307 - don't allow apps to resize themselves off the screen - (*cough* filechooser *cough*) - 142016, 143784 - windows should not span multiple xineramas - unless placed there by the user - 143145 - clamp new windows to screensize and force them - onscreen, if they'll fit - 144126 - Handle pathological strut lists sanely[3] - 149867 - fixed aspect ratio windows are difficult to resize[4] - 152898 - make screen edges consistent; allow easy slamming of - windows into the left, right, and bottom edges of the - screen too. - 154706 - bouncing weirdness at screen edge with keyboard moving - or resizing - 156699 - avoid struts when placing windows, if possible (nasty - a11y blocker) - 302456 - dragging offscreen too restrictive - 304857 - wireframe moving off the top of the screen is misleading - 308521 - make uni-directional resizing easier with - alt-middle-drag and prevent the occasional super - annoying resize-the-wrong-side(s) behavior - 312007 - snap-resize moves windows with a minimum size - constraint - 312104 - resizing the top of a window can cause the bottom to - grow - 319351 - don't instantly snap on mouse-move-snapping, remove - braindeadedness of having order of releasing shift and - releasing button press matter so much - - [1] fixed in my opinion, anyway. - [2] Actually, it's not totally fixed--it's just annoying - instead of almost completely unusable. Matthias had a - suggestion that may fix the remainder of the problems (see - http://tinyurl.com/bwzuu). - [3] This bug was originally about not-quite-so-pathological - cases but was left open for the worse cases. The code from - the branch handles the remainder of the cases mentioned in - this bug. - [4] Actually, although it's far better there's still some minor - issues left: a slight drift that's only noticeable after - lots of resizing, and potential problems with partially - onscreen constraints due to not clearing any - fixed_directions flags (aspect ratio windows get resized in - both directions and thus aren't fixed in one of them) - - New feature: - 81704 - edge resistance for user move and resize operations; - in particular 3 different kinds of resistance are - implemented: - Pixel-Distance: window movement is resisted when it - aligns with an edge unless the movement is greater than - a threshold number of pixels - Timeout: window movement past an edge is prevented until - a certain amount of time has elapsed during the - operation since the first request to move it past that - edge - Keyboard-Buildup: when moving or resizing with the - keyboard, once a window is aligned with a certain edge - it cannot move past until the correct direction has - been pressed enough times (e.g. 2 or 3 times) - - Major changes: - - constraints.c has been rewritten; very few lines of code from - the old version remain. There is a comment near the top of - the function explaining the basics of how the new framework - works. A more detailed explanation can be found in - doc/how-constraints-works.txt - - edge-resistance.[ch] are new files implementing edge-resistance. - - boxes.[ch] are new files containing low-level error-prone - functions used heavily in constraints.c and edge-resistance.c, - among various places throughout the code. testboxes.c - contains a thorough testsuite for the boxes.[ch] functions - compiled into a program, testboxes. - - meta_window_move_resize_internal() *must* be told the gravity - of the associated operation (if it's just a move operation, - the gravity will be ignored, but for resize and move+resize - the correct value is needed) - - the craziness of different values that - meta_window_move_resize_internal() accepts has been documented - in a large comment at the beginning of the function. It may - be possible to clean this up some, but until then things will - remain as they were before--caller beware. - - screen and xinerama usable areas (i.e. places not covered by - e.g. panels) are cached in the workspace now, as are the - screen and xinerama edges. These get updated with the - workarea in src/workspace.c:ensure_work_areas_validated() - -2005-11-14 Elijah Newren - - * configure.in: post-release version bump to 2.13.2 - -2005-11-14 Elijah Newren - - * NEWS: 2.13.1 release - -2005-11-11 Aidan Delaney - - * src/tabpopup.h: (struct _MetaTabEntry): - * src/tabpopup.c: (meta_ui_tab_popup_new): - * src/screen.c: (meta_screen_ensure_tab_popup): - Changed the 'minimized' field of the MetaTabEntry struct to - 'hidden'. Fixes reopened bug #168455. - -2005-10-29 Kjartan Maraas - - * src/eventqueue.c: (meta_event_queue_new): Merge fix - for bug #320050 from stable. - -2005-10-27 Erdal Ronahi - - * configure.in: Added ku (Kurdish) to ALL_LINGUAS - -2005-10-25 Philip O'Brien - - * src/prefs.c (meta_preference_to_string): add handling for - META_PREF_CURSOR_THEME and META_PREF_CURSOR_SIZE for more complete - debug info - -2005-10-24 Elijah Newren - - * configure.in: post-release version bump to 2.13.1 - -2005-10-24 Elijah Newren - - * NEWS: 2.13.0 release - -2005-10-23 Elijah Newren - - Fix edge snapping for multi-screen (non-xinerama) setups. #319425 - - * src/place.c (get_windows_showing_on_same_screen, - get_vertical_edges, get_horizontal_edges): rename - get_windows_on_same_workspace() to - get_windows_showing_on_same_screen() - - * src/place.c (get_windows_showing_on_same_screen): exclude windows - in the list that are on a different screen - -2005-10-20 Elijah Newren - - * HACKING: Clarify why METACITY_VERBOSE=1 is bad without - META_USE_LOGFILE=1; point to bug 305091 for details. - -2005-10-13 Muktha - - * src/themes/Simple/metacity-theme-1.xml: Make the unfocussed - Simple window border visible with high contrast inverse theme. - Fixes #121361. - -2005-10-08 Elijah Newren - - Fix a crash that occurs when removing some virtual desktops and - windows happen to be on those desktops. #318306. - - * src/workspace.c (meta_workspace_relocate_windows): Since windows - cannot be on more than one workspace at a time, remove the window - from the old workspace before adding it to the new one. - -2005-10-08 Elijah Newren - - Add my copyright notice to a number of files on which it should - already exist. - -2005-10-03 Elijah Newren - - * src/metacity.schemas.in: clarify the meaning of the auto_raise - preference. Fixes one of the issues in #312421. - -2005-10-03 Elijah Newren - - Patch from Ross Cohen to make alt-esc consistent with alt-tab by - leaving stacking of unselected windows unchanged. Fixes #314285. - - * src/keybindings.c (process_tab_grab): before raising and showing - the next candidate, reset the stack positions to what they were - at the beginning of the grab - -2005-10-03 Elijah Newren - - Patch from Ross Cohen to make alt-esc (show windows instantly) - actually show minimized windows too. Fixes #107072. - - * src/keybindings.c (process_tab_grab): initialize tab_unminimized - to FALSE for the target window when starting the grab, when - advancing through the list check to find the previous window and - re-minimize it if it was tab-unminimized, unminimize the new - window we're alt-esc'ing to if it's minimized, (do_choose_window): - raise and unminimize the initial window as well in alt-esc'ing - - * src/window.h (struct _MetaWindow): add a tab_unminimized field - - * src/window.c (meta_window_new_with_attrs): initialize - tab_unminimized to false - -2005-10-03 Elijah Newren - - Branched for Gnome 2.13. :-) - - * configure.in: bump version to 2.13.0. Add UNSTABLE warning. - * README: add 2.13.x to the list of unstable branches - -2005-10-03 Elijah Newren - - A combination of a couple memory leaks fixes, from Kjartan, - Soeren, and I. Fixes #313030. - - * src/bell.c (meta_bell_flash_screen): call XFreeGC() - - * src/frames.c (invalidate_cache): free pixels - - * src/window.c (meta_window_show_menu): call - meta_screen_free_workspace_layout() - -2005-10-03 Elijah Newren - - Patch from Björn Lindqvist fix the workspace switcher tabpopup to - display the right windows and to fix the - pick-a-new-window-to-focus algorithm in order to not select - windows that aren't showing. Fixes #170475. - - * src/tabpopup.c (meta_convert_meta_to_wnck, - meta_select_workspace_expose_event): factor out conversion code - from meta_select_workspace_expose_event() into the new - meta_convert_meta_to_wnck() function - - * src/tabpopup.c (meta_select_workspace_expose_event): - * src/workspace.c (focus_ancestor_or_mru_window): - replace the buggy window->minimized logic with - !meta_window_showing_on_its_workspace (window) - -2005-10-03 Elijah Newren - - Patch from Björn Lindqvist to have ancestors come along with the - transient when moving the window from one workspace to another. - Fixes #314977. - - * src/window.c (meta_window_change_workspace): have all ancestors - change workspaces too - -2005-10-03 Elijah Newren - - * configure.in: post-release version bump to 2.12.2 - -2005-10-03 Elijah Newren - - * NEWS: 2.12.1 release - -2005-10-03 Elijah Newren - - Truncate ridiculously long titles to avoid crashing or letting the - pager crash. Based on patch from Ray, incorporating suggestions - from Havoc and some extensions of my own. Fixes #315070. - - * src/display.c (set_utf8_string_hint, meta_display_open): - * src/xprops.[ch] (meta_prop_set_utf8_string_hint): - Move set_utf8_string_hint() to props.[ch], namespace it - ("meta_prop_"), and make it public - - * src/tabpopup.c (utf8_strndup, meta_ui_tab_popup_new): - * src/util.[ch] (meta_g_utf8_strndup): - Move utf8_strndup() to util.[ch], namespace it ("meta_g_"), and - make it public - - * src/display.c (meta_display_open): - * src/display.h (struct _MetaDisplay): - add net_wm_visible_name and net_wm_visible_icon_name atoms to the - list of atoms we work with - - * src/window-props.c (set_window_title, set_icon_title): If title - length is greater than 512, truncate it and set - _NET_WM_VISIBLE_NAME or _NET_WM_VISIBLE_ICON_NAME accordingly - -2005-10-03 Elijah Newren - - Get the tabbing window outline to work with gtk+ 2.8.4 again. - Fixes #317528. - - * src/tabpopup.c (display_entry): gtk+ 2.8.4 needs to know the - mapped state of its windows (see bug 316180), and since we - manually map with gdk_window_show_unraised() we need to manually - set the mapped state too - -2005-09-05 Elijah Newren - - * configure.in: post-release version bump to 2.12.1 - -2005-09-05 Elijah Newren - - * configure.in: - * README: - * NEWS: - 2.12.0 release - -2005-09-04 Danilo Šegan - - * configure.in: Added Armenian (hy) to ALL_LINGUAS. - -2005-09-03 Elijah Newren - - * HACKING: Add tips on how to more easily get the ids of windows, - and how to shorten xprop output. - -2005-09-02 Brent Smith - - * src/place.c: (meta_window_place): Moved the call to - meta_screen_get_natural_xinerama_list to earlier in - function so that xineramas_list is allocated before - find_first_fit is called. Fixes #315000 - -2005-08-22 Elijah Newren - - * configure.in: post-release version bump to 2.11.5 - -2005-08-22 Elijah Newren - - * NEWS: 2.11.3 release - -2005-08-22 Elijah Newren - - * configure.in: Patch from Björn Lindqvist to check for the - appropriate versions of glib and gtk. Fixes #314116. - -2005-08-12 Elijah Newren - - * src/place.c (meta_window_place): Avoid obscuring - centered-on-desktop windows which are denied focus. Fixes - #313234. - -2005-08-08 Elijah Newren - - * configure.in: post-release version bump to 2.11.3 - -2005-08-08 Elijah Newren - - * NEWS: 2.11.2 release - -2005-08-08 Elijah Newren - - Patch from Brent Smith to fix a duplicate string. Fixes #309774. - - * src/theme-parser.c (parse_toplevel_element, parse_draw_op_element): - Change "No \"%s\" attribute on element <%s>" string to "No \"%s\" - attribute on <%s> element" - -2005-08-03 Ray Strode - - Improve the behavior of keyboard move/resize and edge - snapping. Still not perfect, bug 310888. - - * src/effects.c (draw_xor_rect): Make the outside of a - wireframe rectangle line up with the outside edge of its - window, instead of centering the wireframe edges on the - window edges. - - * src/keybindings.c (process_keyboard_move_grab): allow - edge snapping in wireframe mode. Adjust code to take - into account changed semantics of find_next_*_edge - functions. - (process_keyboard_resize_grab_op_change): new function - to take some orthogonal logic out of - process_keyboard_resize_grab_op. Only allow keyboard - resize cursor to go to flat edges, not corners. - (process_keyboard_resize_grab): allow edge snapping in - wireframe mode. Fix up snapping logic. - - * src/place.c (get_{vertical,horizontal}_edges): use - GArray instead of int *, since the number of output - edges isn't known until the middle of the function now. - Use xor rect extents instead of window extends if in - wireframe mode. - (meta_window_find_next_{vertical,horizontal}_edge: add - new source_edge_position parameter to specify which edge - on the active window to start from when looking for next - edge on the screen. Return the coordinate of the edge - found and not the coordinate of where the window should be - moved to snap to where the edge was found. - - * src/window.c (update_move): all the user to specify - an edge to resize with mouse in keyboard resize mode. - window - -2005-08-01 Elijah Newren - - * src/metacity.schemas.in: Change default theme from "Simple" to - "Clearlooks". - -2005-07-31 Elijah Newren - - * src/stack.c (is_focused_foreach, get_standalone_layer): use only - the expected_focus_window instead of both the focused_window and - the expected_focus_window. Removes an infinite flicker loop in - sloppy and mouse focus, and an ugly one time flicker in click to - focus. Fixes #311400. - -2005-07-30 Elijah Newren - - Patch from Jaap Haitsma to make sure that Metacity dialogs have - icons. Fixes #309876. - - * src/metacity-dialog.c (kill_window_question, - warn_about_no_sm_support, error_about_command): call - gtk_window_set_icon_name() to set the dialog icon - -2005-07-28 Elijah Newren - - * src/place.c (avoid_being_obscured_as_second_modal_dialog): - remove some unneeded debug spew that was causing crashes. Fixes - #311819. - -2005-07-24 Elijah Newren - - * configure.in: post-release version bump to 2.11.2 - -2005-07-24 Elijah Newren - - * NEWS: 2.11.1 release - -2005-07-24 Elijah Newren - - * src/place.c (find_most_freespace): try to place windows denied - focus near the focus window and fix a xinerama bug with the - placement, (avoid_being_obscured_as_a_second_modal_dialog): avoid - modal dialogs being obscured in somewhat pathologically strange - circumstances that Eclipse seems to be good at triggering, - (meta_window_place): have dialog windows make use of - avoid_being_obscured_as_a_second_modal_dialog(). Fixes one of the - issues found in #307875. - -2005-07-24 Elijah Newren - - * src/window.c (meta_window_raise): raise the window as well as - its ancestor; fixes a stacking bug with an ancestor that has more - than one child window. Fixes one of the issues in #307875. - -2005-07-24 Elijah Newren - - * src/window.c (meta_window_free): restore original window size if - the window was maximized, as the FIXME says. ;-) Fixes #137185. - Thanks to Christian Persch for the testcase that made this easier - to track down. - -2005-07-23 Elijah Newren - - * src/window.c (meta_window_activate): revert the patch from - #128380--change _NET_ACTIVE_WINDOW behavior to what it originally - was. - -2005-07-18 Matthias Clasen - - * configure.in: Add checks for Xcursor, to make the changes - done on 2005-07-11 effective. - -2005-07-14 Elijah Newren - - Patch from Ken Harris to provide a more lenient threshold for - drawing rounded corners. Fixes #122065. - - * src/theme.c (meta_frame_layout_calc_geometry): use height + - width > 5 instead of height > 3 && width > 3 as criterion - -2005-07-13 Elijah Newren - - Fix a slight bug (causing possible miscoloring of parts of the - titlebar) introduced by the patch from #169982. - - * src/gradient.c: - (meta_gradient_create_interwoven): - (meta_gradient_create_multi_vertical): - - bitshifting operators do not take precedence over typecasting, so - make sure to use parentheses to get the right operation order. - -2005-07-12 Elijah Newren - - * configure.in: post-release version bump to 2.11.1 - -2005-07-12 Elijah Newren - - * NEWS: 2.11.0 release - -2005-07-12 Elijah Newren - - Patch from Andrew Johnson to speed up vertical gradients. Fixes - #169982. - - * src/gradient.c: - (meta_gradient_create_interwoven): - (meta_gradient_create_vertical): - (meta_gradient_create_multi_vertical): - - use memcpy instead of really long loops to set values in memory to - a given pattern. - -2005-07-12 Elijah Newren - - Patch from Björn Lindqvist to split up main() into more manageable - chunks and make use of GOpt. Closes #305331. - - * src/main.c (usage): remove this function, - (meta_print_compilation_info): new function taken from main(), - (meta_print_self_identity): new function taken from main(), - (struct MetaArguments) new struct to replace some free variables, - (meta_parse_options): new funcion taken from main() but now using - GOpt, (meta_select_display): new function taken from main() - -2005-07-12 Aivars Kalvans - - * src/screen.c (meta_screen_free): free ->xinerama_infos - Closes #307884 - -2005-07-11 Elijah Newren - - Stuff I forgot to do when I branched an hour or so ago before - Matthias' commit... - - * configure.in: bump version to 2.11.0. Add UNSTABLE warning. - * README: add 2.11.x to the list of unstable branches - -2005-07-11 Matthias Clasen - - React to cursor theme changes: (#308106) - - * src/prefs.h: - * src/prefs.c: Expose the GConf keys for cursor theme - and size as preferences META_PREF_CURSOR_THEME and - META_PREF_CURSOR_SIZE with getters meta_prefs_get_cursor_theme() - and meta_prefs_get_cursor_size(). - - * src/display.c (meta_display_open): Initialize the cursor - theme and size. - - * src/display.h: - * src/display.c (meta_display_set_cursor_theme): New function - to change the cursor theme and update all cursors. - - * src/screen.h - * src/screen.c (meta_screen_update_cursor): New function to - refesh the root cursor of a screen. - - * src/main.c (prefs_changed_callback): Update the cursor - theme when the cursor preferences change. - -2005-06-27 Elijah Newren - - * configure.in: post-release version bump to 2.10.3 - -2005-06-27 Elijah Newren - - * NEWS: 2.10.2 release - -Sun Jun 26 11:19:18 2005 Soeren Sandmann - - * src/frames.c: Add a cache of pixmaps for recently exposed frame - areas. Makes metacity a bit faster when dragging windows around. - See bug 141813. - -2005-06-10 Ryan Lortie - - * src/frames.c: Prevent using the address of a local variable - as a hash key. (Bug #307209) - - * src/xprops.c (meta_prop_get_values): Fix a small leak in the - case of a SYNC_COUNTER property value and HAVE_XSYNC not - defined. (Bug #307214) - -2005-06-07 Ray Strode - - Cleanup font data when done with it (bug 306720). - - * src/effects.c (draw_xor_rect): free font info structure. - * src/screen.c (meta_screen_new): pass a 1 not a 0 to - XFreeFontInfo to free font info structure. - (meta_screen_free): call XUnloadFont on GC font before freeing - the GC. - -2005-06-02 Elijah Newren - - * src/window.c (meta_window_focus): if the window has a modal - transient which is being unmanaged, don't focus it. Fixes the - Metacity issue reported in #305362. - -2005-05-30 Ray Strode - - Bug 305564 again. - - When drawing XOR resize popup use "fixed" font instead of - -misc-fixed-*-16-* xlfd. Should work on more xservers. - - Also take steps to fail better if the xserver isn't - cooperating. - - * src/effects.c (draw_xor_rect): if we can't draw font box - for whatever reason, at least draw grid frames. - - * src/screen.c (meta_screen_new): use fixed alias instead - of a xfld. Don't pass GCFont to XCreateGC if font couldn't - be loaded. Print a warning if font couldn't be loaded. - -2005-05-26 Elijah Newren - - * HACKING: Add a clarification that METACITY_VERBOSE needs to be - accompanied by METACITY_USE_LOGFILE - -2005-05-26 Elijah Newren - - * src/window.c (meta_window_configure_request): Patch from Greg - Hudson to make sure window position is calculated correctly for - reconfigure requests when part of the XWindowChanges structure is - uninitialized. Fixes #305257. - -2005-05-26 Ray Strode - - Actually commit the stuff mentioned in the last - ChangeLog entry. - -2005-05-26 Ray Strode - - Add a resize popup when resizing constrained - windows, (bug 305564). - - * src/display.c: - (meta_display_begin_grab_op), - (meta_display_end_grab_op): - * src/keybindings.c (process_keyboard_move_grab), - (process_keyboard_resize_grab): Call - meta_window_{begin,update,end}_wireframe convenience - functions instead of the meta_effects counterparts. - - * src/display.h: keep track of old wireframe geometry to - clean up xor popup on resize - - * src/effects.[ch] (meta_effects_begin_wireframe), - (meta_effects_update_wireframe), - (meta_effects_end_wireframe), - (draw_xor_rect): take optional width and height arguments - to show to user in resize popup. Draw resize popup if - width and height >= 0 and wireframe isn't smaller than - the popup would be. - - * src/screen.c (meta_screen_new): load a largish font for - the resize popup - - * src/window.[ch] - (meta_window_move_resize_internal): update - wireframe resize popup when the window is resized. - (meta_window_get_wireframe_geometry): new function to - calculate the numbers to display in resize popup - (meta_window_begin_wireframe), - (meta_window_update_wireframe), - (meta_window_end_wireframe): new functions to reduce - repetitive wireframe code. Functions handle updating - wireframe and resize popup geometry. - (update_move), (update_resize), - (meta_window_refresh_resize_popup): remove fixme and - add debug message. - -2005-05-26 Elijah Newren - - * src/window.c (check_maximize_to_work_area): don't accidentally - treat maximize vertically as maximize in both directions. Fixes - #302204. - -2005-05-26 Elijah Newren - - * src/window.c (meta_window_new_with_attrs): put all transients - of the new window, if any exist, in the calc_showing queue. Fixes - #303284. Thanks to Billy Biggs for the testcase that made this - easy to track down. - -2005-04-11 Elijah Newren - - * configure.in: post-release version bump to 2.10.2 - -2005-04-11 Elijah Newren - - * NEWS: 2.10.1 release - -2005-04-05 Dan Winship - - * src/metacity-dialog.c (warn_about_no_sm_support): Make sure the - "Close" button has the focus, not the table. (#172703) - -2005-04-05 Pawan Chitrakar - - * configure.in: Added ne in ALL_LINGUAS - -2005-03-31 Steve Murphy - - * configure.in: Added "rw" to ALL_LINGUAS. - -2005-03-17 Lex Hider - - * doc/Makefile.am (EXTRA_DIST): add doc/code-overview.txt and - doc/how-to-get-focus-right.txt - -2005-03-10 Adi Attar - - * configure.in: Added "xh" to ALL_LINGUAS. - -2005-03-07 Elijah Newren - - * configure.in: post-release version bump to 2.10.1 - -2005-03-07 Elijah Newren - - * configure.in: - * README: - * NEWS: - 2.10.0 release - -2005-02-28 Elijah Newren - - * configure.in: post-release version bump to 2.9.55 - -2005-02-28 Elijah Newren - - * NEWS: Metacity 2.9.34 unstable release - -2005-02-28 Elijah Newren - - Patch from Aidan Delaney to make sure that icons in the alt-tab - popup are dimmed for all hidden windows, not just minimized ones. - Fixes #168455. - - * src/screen.c: (meta_screen_ensure_tab_popup): make use - meta_window_showing_on_its_workspace() instead of just checking if - the window is minimized. - -2005-02-25 Elijah Newren - - Prevent the visual bell from changing the focus window. Fixes - #123366. - - * src/bell.c: (meta_bell_flash_screen): if not in click-to-focus - mode and mouse_mode is also false, increment the focus sentinel so - that we can ignore spurious EnterNotify and LeaveNotify events. - - * src.display.c: (event_callback): make sure to also ignore - LeaveNotify events when the focus sentinel isn't clear - -2005-02-23 Elijah Newren - - * src/window.c: (meta_window_new_with_attrs): Fix crash that - occurs when stupid apps claim that a window is its own parent. - #168207 - -2005-02-21 Elijah Newren - - * configure.in: post-release version bump to 2.9.34 - -2005-02-21 Elijah Newren - - * NEWS: Metacity 2.9.21 unstable release - -2005-02-21 Elijah Newren - - Handle keynav vs. mousenav in mouse and sloppy focus modes. Fixes - #167545. - - * doc/how-to-get-focus-right.txt: Update due to this new method - for handling keynav vs. mousenav, plus various other updates that - I previously forgot. - - * src/display.h: (struct _MetaDisplay): add a mouse_mode boolean - - * src/display.c: (meta_display_open): initialize mouse_mode to - true, (event_callback): have EnterNotify and LeaveNotify events - set mouse_mode to true when focusing a window - - * src/keybindings.c: (process_tab_grab): set mouse_mode to false - when using alt-tab/alt-esc, (do_choose_window): likewise, - (do_handle_move_to_workspace): set mouse_mode to false on - move-window-to-workspace- keybindings - - * src/window.c (idle_calc_showing): if we're in keynav mode while - using sloppy or mouse focus, use metacity_sentinel to avoid - EnterNotify events being generated from events other than mouse - movement. - - * src/workspace.c (meta_workspace_activate_with_focus): add a - FIXME in a potentially duplicate section of code, - (meta_workspace_focus_default_window): use the same focus choice - as click-to-focus if in keynav mode. - -2005-02-20 Elijah Newren - - * src/display.c: (event_callback): Handle _NET_CURRENT_DESKTOP - messages that come with timestamps. Fixes the metacity portion of - #161361 other than the portion handled by #128380. - -2005-02-20 Elijah Newren - - * src/window.c: (meta_window_activate): when receiving a - _NET_ACTIVE_WINDOW message, switch to the desktop where the window - is located before activating instead of moving the window to the - current desktop. Thanks to Lubos Lunak for catching this issue. - Fixes #128380. - -2005-02-20 Elijah Newren - - * src/window.c (meta_window_show): Ignore all focus and - focus-stealing-prevention code in meta_window_show when not - showing the window for the first time. Fixes #167199. - -2005-02-20 Elijah Newren - - Fix an obscure xinerama placement bug with windows that are too - large to fit in the workarea in both dimensions. #166757 - - * src/place.c: (meta_window_place): use the current xinerama - instead of arbitrarily resetting to 0 - -2005-02-20 Elijah Newren - - Patch from Joe Marcus Clarke to fix a possible crash on logout. - #167935. Thanks for fixing my mistakes, Joe! - - * src/display.c: (meta_display_open): initialize - display->grab_old_window_stacking to NULL. - -2005-02-20 Elijah Newren - - Big patch to cover about 6 different issues in order to correct - rare problems with timestamps (make sure window selected in - tasklist actually gets focus, sanity check timestamps to avoid - rogue apps hosing the system, correct the updating of - net_wm_user_time, correctly handle timestamps of 0 when comparing - xserver timestamps for those who have had their systems up for - over 25 days or so, add some debugging information to verbose - logs, some code cleanups). Fixes all issues listed in #167358. - - * src/display.h: (struct _MetaDisplay): clarify comment on - last_focus_time, introduce a new variable--last_user_time, - (XSERVER_TIME_IS_BEFORE macro): put this functionality into a - separate macro and then introduce a new macro with this name that - uses the old one but adds additional special-case checks for - timestamps that are 0, (comment to - meta_display_set_input_focus_window): add information about how - last_user_time should be used in this function - - * src/display.c (santiy_check_timestamps): new function, - (meta_display_open): intialize display->last_user_time, - (meta_display_get_current_time_roundtrip): use the timestamp, - which is known to be good, in order to sanity_check_timestamps, - (event_callback): use the new meta_window_ste_user_time() function - in order to correct problems, use the timestamp of KeyPress and - ButtonPress events, which are known to be good, in order to - sanity_check_timestamps, (timestamp_too_old): new function for - common behavior of meta_display_focus_the_no_focus_window and - meta_display_set_input_focus_window, with added checking for - display->last_user_time in addition to display->last_focus_time, - (meta_display_set_input_focus_window): replace some of the code - with a call to timestamp_too_old(), - (meta_display_focus_the_no_focus_window): replace some of th ecode - with a call to timestamp_too_old() - - * src/window.h: (meta_window_set_user_time): new function to - abstract the many things that need to be done when updating the - net_wm_user_time of any window - - * src/window.c: (meta_window_activate): add debugging spew, make - sure the comparison is made with last_user_time NOT - last_focus_time, use meta_window_set_user_time() function in order - to correct problems, (meta_window_client_message): add a newline - to a debugging message to make them easier to read, - (meta_window_set_user_time): new function - - * src/window-props.c (reload_net_wm_user_time): use the new - meta_window_ste_user_time() function in order to correct problems - -2005-02-16 Elijah Newren - - * src/display.c: (event_callback): trivial fix to a log message: - change %d to %lu (see debugging log from bug 167358). - -2005-02-12 Elijah Newren - - Raise the ancestor of a window instead of the window itself. - Fixes #166894. - - * src/window.c: (find_root_ancestor): new function, - (meta_window_raise): get the ancestor of the given window and - raise it if possible instead of the window - -2005-02-12 Elijah Newren - - Don't unconditionally place splashscreens (and other - not-to-be-focused windows) below the focus window. Fixes #167042. - - * src/window.c: (intervening_user_event_occurred): new function - taken from the timestamp comparison portion of the old - window_takes_focus_on_map function, (window_state_on_map): new - function with remainder of old window_takes_focus_on_map function - that determines both whether the window will take focus and - whether it should be placed on top, (meta_window_show): use - place_on_top_on_map to determine window stacking instead of trying - to infer it from takes_focus_on_map - -2005-02-11 Elijah Newren - - Avoid new windows being obscured by the focus window (and thus - possibly lost). Fixes #166524. - - * src/place.c: new MetaWindowDirection enum, - (find_most_freespace): new function to find where there is the - most space available around the focused window, - (meta_window_place): if a window is denied focus and the window - overlaps the focused window, retry the first-fit algorithm only - paying attention to the focus window position and if that fails - just find the location on the screen with the most space - available. - - * src/window.h: (struct MetaWindow): new - denied_focus_and_not_transient bitfield - - * src/window.c: (meta_window_new_with_attrs): initialize - denied_focus_and_not_transient, (meta_window_show): set and unset - the denied_focus_and_not_transient field appropriately - -2005-02-08 Aidan Delaney - - Removed useless function call. #166730 - - * src/tabpopup.c: (outline_window_expose): Removed unused - references to variables and an unnecessary function call to - gdk_window_get_size(). - -2005-02-08 Elijah Newren - - Avoid using CurrentTime when focusing, handle it better in case we - miss any cases. Fixes #166732. - - * src/window.c: (meta_window_shade): use - meta_display_get_current_time_roundtrip() to ensure we have a - valid timestamp, (meta_window_unshade): same - - * src/display.c: (meta_display_set_input_focus_window): If - CurrentTime was passed, get one from the XServer in addition to - throwing a warning, (meta_display_focus_the_no_focus_window): same - -2005-02-08 Elijah Newren - - * src/window.c: (meta_window_activate): If we're not passed a - timestamp, make sure to manually get one. Fixes #166728. - -2005-02-07 Elijah Newren - - * configure.in: post-release version bump to 2.9.21 - -2005-02-07 Elijah Newren - - * NEWS: Metacity 2.9.13 unstable release - -2005-02-06 Elijah Newren - - Set a _METACITY_VERSION property (a utf8 string) on the WM check - window. #165350. - - * src/display.h: (struct MetaDisplay): add a atom_metacity_version - field - - * src/display.c: (meta_display_open): initialize the - _METACITY_VERSION property on the WM check window to the current - version of Metacity. - -2005-02-06 Elijah Newren - - Ignore xconfigurerequest events for stacking when it should be - safe to do so. Again, thanks to Crispin Flowerday for the test - case. Thanks to KWin for the inspiration (and to Google for - indexing their source code). Fixes the other half of #166395. - - * src/window.c: (meta_window_configure_request): if the - active_window is from a separate application than the one getting - the configure request and the net_wm_user_time of the active - window is later than that of the window getting the configure - request, then ignore the request. - -2005-02-06 Elijah Newren - - If activation requests are too old, set the demands_attention hint - instead of actually activating. Thanks to Crispin Flowerday for - the test case and for testing the patch. Fixes half of #166395. - - * src/window.c: (meta_window_activate): if the request came before - the last focus time, set the demands attention hint instead - -2005-02-04 Dave Ahlswede - - * src/metacity.schemas.in: Add period to the end of - reduced_resources' description. Fixes #165780. - -2005-02-04 Elijah Newren - - Make sure window->border_only is initialized so we don't get - random windows without decorations. Thanks to Sinisa Segvic and - Owen Taylor for providing test cases. Fixes #145131. - - * src/window.c: (update_mwm_hints): Be sure to call - recalc_window_features even if no MWM hints are set - -2005-02-02 Elijah Newren - - Focus parents of dismissed transient windows in preference to the - window that most recently had keyboard focus. Fixes #157360. - - * doc/how-to-get-focus-right.txt: Note the distinction between - "most recently used window" and "most recent to have keyboard - focus" that we are now making. - - * src/workspace.c: (focus_ancestor_or_mru_window): rename from - meta_workspace_focus_mru_window, and first check whether we need - to focus an ancestor window before looking for the mru window, - (record_ancestor): helper function for - focus_ancestor_or_mru_window, - (meta_workspace_focus_default_window): update due to the function - rename from meta_workspace_focus_mru_window to - focus_ancestor_or_mru_window - -2005-01-31 Elijah Newren - - Try 2 to correct misleading and inaccurate wording. Hopefully, - really fixes #165380. - - * src/menu.c: Change wording of menu from "Always on Current - Workspace" to "Always on Visible Workspace". "Always on Current - Workspace" could sound like a synonym of "Only on This Workspace" - when it was supposed to be the opposite. - -2005-01-31 Elijah Newren - - Correct the stacking when return from fullscreen mode. Fixes - #165718. - - * src/window.c: (meta_window_unmake_fullscreen): Update the layer - after resizing the window - -2005-01-31 Muktha - - src/themes/Atlanta/metacity-theme-1.xml: - src/themes/Simple/metacity-theme-1.xml: - src/themes/Bright/metacity-theme-1.xml: - Make the unfocussed title bar distinguishable. Fixes #125291. - -2005-01-28 Elijah Newren - - Patch from RHEL-3 (Havoc doesn't remember how it got there) that - Havoc posted in bug 156511 to fix the problem with fullscreen - windows on a different xinerama monitor not staying on top. I - updated to HEAD. Should fix #156511. - - * src/stack.c: (windows_on_different_xinerama): new function, - (get_standalone_layer): let windows on a different screen than the - one with the focus window stay in the fullscreen layer - -2005-01-28 Elijah Newren - - * src/metacity-dialog.c: (warn_about_no_sm_support): make this - dialog be sticky. Fixes #164745. - -2005-01-28 Elijah Newren - - Patch from Tim Herold to handle xcomposite pkgconfig version - regression. Fixes #149368. - - * configure.in: Change XCOMPOSITE_VERSION from 1.0 to 0.2 - -2005-01-28 Elijah Newren - - Correct misleading and inaccurate wording. Fixes #165380. - - * src/menu.c: Change wording of menu to "Always on Current - Workspace" from "Put on All Workspaces", remove a quick-key - conflict between "On _Top" and "Only on _This Workspace" by - switching the latter to "_Only on This Workspace" - - * src/window.c: Remove a comment that is no longer necessary - (since bug 87531 has been fixed) - -2005-01-28 Elijah Newren - - Take into account the appropriate list of windows when placing a - new one. Fixes #165381. - - * src/place.c: (meta_window_place): use - meta_window_showing_on_its_workspace(w) instead of !w->minimzed, - also take into account sticky windows - - * src/window.[ch]: rename window_showing_on_its_workspace to - meta_window_showing_on_its_workspace and export it - -2005-01-27 Elijah Newren - - Plug a pair of leaks. Fixes #165378 - - * src/place.c: (meta_window_place, get_windows_on_same_workspace): - free list returned by meta_display_list_windows. - -2005-01-27 Elijah Newren - - Treat splashscreens same as other windows for stacking. Fixes - #165243. - - * src/stack.h: (MetaStackLayer enum): remove META_LAYER_SPLASH - from the list - - * src/stack.c: (get_standalone_layer): remove the special casing - of META_WINDOW_SPLASHSCREEN - -2005-01-27 Elijah Newren - - * src/window.c: (set_net_wm_state): shaded windows should not show - up in pagers. Fixes #165377. - -2005-01-26 Elijah Newren - - Stick and unstick transients with their parent automatically. - Fixes #152283. - - * src/window.c: (window_stick_impl, window_unstick_impl): rename - from meta_window_stick and meta_window_unstick respectively, - (stick_foreach_func): a function to assist calling - window_(un)stick_impl on each transient, (meta_window_stick, - meta_window_unstick): new functions that call window_stick_impl or - window_unstick_impl for the window and each of its transients. - -2005-01-26 Elijah Newren - - Patch from John Paul Wallington to keep tooltip on screen - horizontally for xinerama. Fixes #165261. - - * src/fixedtip.c: (meta_fixed_tip_show): rename screen_width and - screen_height to screen_right_edge and screen_bottom_edge, set - them using xinerama info instead of just screen geometry, and use - them to determine where to place the tooltip window. - -2005-01-26 Arvind Samptur - - Don't wireframe when accessibility is on, it apparently - causes a desktop wide freeze. - - * src/prefs.[ch] (meta_prefs_init) (change_notify) - (update_gnome_accessibility) (meta_preference_to_string) - (meta_prefs_get_gnome_accessibility) : Add code to monitor - accessibility status. - - * src/display.c (meta_display_begin_grab_op): Check - accessibility status before going ahead with wireframe. - Fixes #159538 - -2005-01-25 Elijah Newren - - * src/tabpopup.c: (meta_select_workspace_expose_event): ignore - sticky windows for non-active workspaces. Fixes #165259. - -2005-01-25 Elijah Newren - - * src/window.c: (meta_window_new_with_attrs): set the window state - hints _after_ applying session information. Fixes #164677. - -2005-01-25 Elijah Newren - - Add man pages for metacity-window-demo and metacity-theme-viewer. - Man pages from Jose Moya, auto-fu from Dave Ahlswede. (#143513) - - * doc/man/metacity-theme-viewer.1: - * doc/man/metacity-window-demo.1: - - New man pages - - * doc/man/Makefile.am: - * doc/Makefile.am: - * configure.in: - - Make sure to install the man pages - - * doc/man/.cvsignore: - - Silence cvs - -2005-01-25 Benjamin Kahn - - New 48x48 default icon as specified in bug #160660 - -2005-01-25 Elijah Newren - - Patch from Stephane LOEUILLET in bug #151850. - - * src/metacity.desktop.in: specify encoding - -2005-01-25 Balamurali Viswanathan - - * src/prefs.c (meta_prefs_init): Get gconf to load the - terminal dir so that we get the notifications when - the command is changed. Fixes bug #160934 - -2005-01-25 Elijah Newren - - Refuse to focus a window with a modal transient, and focus the - transient instead. Fixes #164716. - - * src/window.c: (get_modal_transient): new function, - (meta_window_focus): if the window has a modal transient, make - sure it is on the current workspace and then focus it instead. - -2005-01-24 Elijah Newren - - * configure.in: post-release version bump to 2.9.13 - -2005-01-24 Elijah Newren - - * NEWS: Metacity 2.9.8 unstable release - -2005-01-24 Elijah Newren - - * src/display.c: (meta_display_begin_grab_op): don't forget to - initialize display->grab_old_window_stacking. Thanks to Sebastien - Bacher and the bleeding edge Ubuntu users for catching the - occasional crash this could cause so quickly, and for verifying - that the patch worked (I couldn't duplicate). Fixes #165093. - -2005-01-23 Elijah Newren - - * configure.in: post-release version bump to 2.9.8 - -2005-01-23 Elijah Newren - - * NEWS: Metacity 2.9.5 unstable release - * README: there are more stable releases beyond 2.8.6... - -2005-01-23 Elijah Newren - - Restore original stacking when aborting an alt-esc window switch - operation. Fixes #123576. - - * src/display.c: (GRAB_OP_IS_WINDOW_SWITCH): new macro, - (meta_display_close): clear grab_old_window_stacking if non-NULL, - (event_callback): restore stack positions if alt-esc op cancelled - with button press, (meta_display_begin_grab_op): store the old - stacking positions, (meta_display_end_grab_op): free the old stack - positions - - * src/display.h: (struct _MetaDisplay): add a - grab_old_window_stacking list - - * src/keybindings.c: (process_tab_grab): restore stack positions - if alt-esc op cancelled with an errant key press - - * src/stack.c: (compare_just_window_stack_position): new - GCompareFunc function, (meta_stack_get_positions): get current - stack positions, (compare_pointers): new GCompareFunc function, - (lists_contain_same_windows): simple utility func to see if two - lists contains the same windows, (meta_stack_set_positions): new - function to set the positions of all the windows in the stack - - * src/stack.h: (meta_stack_get_postions, - meta_stack_set_positions): new functions - -2005-01-23 Elijah Newren - - Patch from John Paul Wallington to fix #163420. - - * src/window.c: (check_maximize_to_work_area): fix vertical - maximization for second screen - -2005-01-21 Elijah Newren - - * rationales.txt: Add a tracker bug for modal dialog issues - -2005-01-20 Elijah Newren - - * src/tabpopup.c (dimm_icon): use pixbuf, not dimmed_pixbuf (which - isn't defined yet). Fixes crash from #136666. - -2005-01-20 Vincent Noel - - * src/screen.c: (meta_screen_ensure_tab_popup), - (meta_screen_ensure_workspace_popup): - * src/tabpopup.c: (meta_ui_tab_popup_new), (display_entry): - * src/tabpopup.h: Show labels in bold for windows that demand - attention. Fixes #164590. - -2005-01-18 Vincent Noel - - * src/screen.c: (meta_screen_ensure_tab_popup), - (meta_screen_ensure_workspace_popup): - * src/tabpopup.c: (dimm_icon), (meta_ui_tab_popup_new), - (free_entry): - * src/tabpopup.h: In the tab task switcher popup, dim the window - icon and put its name between brackets when the window is - minimized. Fixes #136666. - -2005-01-11 Elijah Newren - - Correct highlighting of windows in workspace switcher popup. - Fixes #163450. - - * src/tabpopup.c (meta_select_workspace_expose_event): Remove race - between FocusIn/FocusOut events and the expose event by replacing - window->has_focus with - window==window->display->expected_focus_window. - -2005-01-09 Elijah Newren - - * configure.in: post-release version bump to 2.9.5 - -2005-01-09 Elijah Newren - - * NEWS: Metacity 2.9.3 unstable release - -2005-01-09 Elijah Newren - - * src/display.c (meta_display_open): - * src/display.h (struct _MetaDisplay): - * src/window.c (meta_window_free, meta_window_client_message, - meta_window_notify_focus): - - Remove the hack from bug 128200; it isn't needed anymore with the - fix from bug #160470. - -2005-01-09 Elijah Newren - - Don't focus the panel on click. Fixes #160470 (and 100470 and - removes the need for the hack from 128200) - - * doc/how-to-get-focus-right.txt: Update section on focusing - non-decorated windows (specifically, DOCKS and DESKTOPS) - - * src/display.c (event_callback): don't focus dock windows on - click - -2005-01-06 Elijah Newren - - Make sure the save session dialog appears focused. Fixes #162983. - - * src/session.c (warn_about_lame_clients_and_finish_inter): Get a - timestamp by explicit request from Xserver, since none is - available otherwise. - -2005-01-06 Leena Gunda - - * src/window.c (meta_window_unmaximize): Restore the wireframe - rectangle co-ordinates to saved window co-ordinates. Fixes - bug #161236. - -2005-01-03 Thomas Fitzsimmons - - * src/Makefile.am (install-data-local): Install schema data from - builddir not srcdir. - -2005-01-02 Elijah Newren - - Provide more documentation to make it easier for people to - contribute to Metacity. (#162646) - - * HACKING: Add lots of information to extend this document: more - on relevant standards and X properties, lots of information on - debugging and testing, and add a list of some other important - things to read; also move some information to - src/code-overview.txt and organize this file into sections. - - * doc/code-overview.txt: New file including some small parts from - the old HACKING file and lots of new stuff. This file gives a - brief overview of some of the bigger structures and files, with - guides for a variety of task categories providing places to start - looking in the code and things to look for. - -2004-12-28 Elijah Newren - - Allow users to move the window around immediately after - double-clicking to shade (#90290) - - * src/display.c (event_callback): only end the grab op if either - there is no frame or else the frame is not mapped - -2004-12-27 Elijah Newren - - Focus windows that manually position themselves too (fixes - #107347). - - * src/window.h (struct _MetaWindow): add a new - showing_for_first_time flag - - * src/window.c (meta_window_new_with_attrs): initialize - showing_for_first_time flag to !mapped, (meta_window_show): - replace did_placement with showing_for_first_time in the section - to decided whether to focus since did_placement isn't quite what - we want - -2004-12-27 Elijah Newren - - * src/display.c (meta_display_set_input_focus_window, - meta_display_focus_the_no_focus_window): Spew warning if - CurrentTime is passed to the function, but don't exit prematurely. - (fixes #162353) - -2004-12-24 Elijah Newren - - * src/window.c (meta_window_show_menu): Don't show menu if all - options are invalid (fixes #148915) - -2004-12-24 Elijah Newren - - * src/window.c (window_takes_focus_on_map): Fix error in - distinguishing < vs. <= introduced by the patch in #154598, - restructure code so that verbose log matches code better in order - ensure such mistakes are harder to make in the future (fixes - #162172) - -2004-12-24 Elijah Newren - - Thanks to mild7@users.sourceforge.net for this fix. - - * src/window.h: (META_WINDOW_IN_NORMAL_TAB_CHAIN): Excludes - windows with skip_taskbar hint set from the alt-tab list; they'll - appear in the ctrl-alt-tab list instead. (fixes #106249) - -2004-12-22 Elijah Newren - - Wrap XSetInputFocus, making display->expected_focus_window a - little more reliable (see #154598) - - * src/display.h: (struct _MetaDisplay): add a large comment about - the expected_focus_window, add a last_focus_time field, - (XSERVER_TIME_IS_BEFORE): new macro moved from window.c but fixed - for 64-bit systems, (meta_display_set_input_focus_window): new - function - - * src/display.c (meta_display_open): initialize last_focus_time, - add a comment about brokenness of trying to set intial focus - window, (meta_display_set_input_focus_window): new function that - wraps XSetInputFocus, - (meta_display_focus_the_no_focus_window): make this function - closer to a wrapping of XSetInputFocus for the no_focus_window. - - * src/window.c (XSERVER_TIME_IS_LATER): remove this macro in favor - of the improved one added to display.h - - * src/display.c (meta_display_open): - * src/window.c (meta_window_focus): - use meta_display_focus_the_no_focus_window and - meta_display_set_input_focus instead of XSetInputFocus - -2004-12-22 Elijah Newren - - * src/core.c (meta_core_user_lower_and_unfocus): - * src/display.c (meta_display_get_current_tab): - * src/stack.c (get_default_focus_window, meta_stack_list_windows): - * src/window.c (set_net_wm_state, meta_window_should_be_showing, - implement_showing, meta_window_activate, - meta_window_notify_focus): - * src/window.h: - * src/workspace.c (meta_workspace_list_windows): - - Rename meta_window_visible_on_workspace to - meta_window_located_on_workspace (whether or not the window was - showing wasn't taken into account, which made "visible" - confusing). Fixes #136314. - -2004-12-22 Elijah Newren - - Partially resolve the conflicting requirements of windows on - multiple workspaces and hidden being a global quantity for windows - (fixes bug 156182; the remainder of the work is bug 87531 and is a - libwnck issue) - - * src/display.c (event_callback): - * src/window.c (meta_window_visible_on_workspace, meta_window_unstick): - * src/workspace.c (meta_workspace_add_window, - meta_workspace_contains_window, - meta_workspace_queue_calc_showing): - * src/workspace.h: - - Remove meta_workspace_contains_window, replace with simple - comparison utilizing window->workspace - - * src/place.c (meta_window_place): - * src/window.c (meta_window_shares_some_workspace): - * src/window.h: - - Remove meta_window_shares_some_workspace, replace with a simple - comparison utilizing window->workspace - - * src/session.c (save_state), - * src/window.c (meta_window_new_with_attrs, - meta_window_apply_session_info, meta_window_free, - window_showing_on_its_workspace, - meta_window_change_workspace_without_transients, - meta_window_unstick, meta_window_set_current_workspace_hint, - meta_window_get_workspaces): - * src/window.h: - * src/workspace.c (meta_workspace_free, meta_workspace_add_window, - meta_workspace_remove_window): - - Only one workspace now - -2004-12-20 Elijah Newren - - * configure.in: post-release version bump to 2.9.3 - -2004-12-20 Elijah Newren - - * NEWS: Metacity 2.9.2 unstable release - -2004-12-20 Elijah Newren - - * configure.in: re-add the note about Fibonacci sequence micro - version numbers that was lost with 2.8.5 - -2004-12-19 Elijah Newren - - Thanks to Baptiste Mille-Mathias for this fix. - - * src/metacity.schemas.in: Add a missing period at the end of a - sentence. - -2004-12-19 Elijah Newren - - When snap-moving, don't snap to transients of minimized windows - since they are hidden. Fixes #157180 - - * src/place.c (get_windows_on_same_workspace): make the logic to - determine hidden windows more thorough by calling - meta_window_should_be_showing() - - * src/window.c (meta_window_should_be_showing): rename this - function from window_should_be_showing and also export it, - (implement_showing): - s/window_should_be_showing/meta_window_should_be_showing/, - (idle_calc_showing): - s/window_should_be_showing/meta_window_should_be_showing/ - - * src/window.h (meta_window_should_be_showing): Add this function - to the list so that it can be used in src/place.c - -2004-12-19 Elijah Newren - - Focus the desktop when showing it. Fixes #159257. - - * src/display.c (event_callback): obtain a timestamp to pass to - meta_screen_show_desktop - - * src/keybindings.c (handle_toggle_desktop): obtain a timestamp to - pass to meta_screen_show_desktop - - * src/screen.c (meta_screen_show_desktop): add a timestamp - parameter, get the most recently used window of type DESKTOP (if - there is one) and focus it - - * src/screen.h (meta_screen_show_desktop): add a timestamp - parameter - -2004-12-19 Elijah Newren - - Thanks to ash@contact.bg for this fix. - - * po/POTFILES.in: Remove reference to metacity-properties.* files - since Alex removed them in his 2004-12-07 commit. - -2004-12-13 Elijah Newren - - * configure.in: post-release version bump to 2.9.2 that I forgot - to do last week (oops) - -2004-12-07 Alex Duggan - - * configure.in: - * src/tools/Makefile.am: - - Remove deprecated capplet from GNOME 2.0 - - * src/tools/metacity-properties.c: - * src/tools/metacity-properties.desktop.in: - * src/tools/metacity-properties.glade: - * src/tools/metacity-properties.png: - - Removed from cvs - -2004-12-06 Elijah Newren - - * NEWS: Metacity 2.9.1 unstable release - -2004-12-06 Benjamin Kahn - - * src/default_icon.png: Use a better default application - icon. Fixes bug #160373 - -2004-11-16 Marco Pesenti Gritti - - * src/Makefile.am: - - Fix build out of src directory. Bug #158325 - -2004-11-10 James Henstridge - - * Makefile.am (DISTCLEANFILES): remove intltool stuff on distclean. - - * src/themes/Makefile.am (uninstall-local): add uninstall rule. - - * src/Makefile.am (libmetacity_private_la_CFLAGS): set this - variable so that the files shared with metacity get compiled with - different names. - - * configure.in: use more modern macros in some places, and make - sure that $ACLOCAL_AMFLAGS is set so that rebuilds work better. - - * autogen.sh (conf_flags): use newer automake. - -2004-11-06 Vincent Untz - - * src/metacity.schemas.in: gnome-panel-screenshot was renamed to - gnome-screenshot - -2004-11-01 Elijah Newren - - * configure.in: bump version to 2.9.1 - -2004-11-01 Elijah Newren - - * NEWS, README: Metacity 2.9.0 (unstable release) - -2004-10-25 Elijah Newren - - Don't lower newly mapped windows when they're denied focus, if - they are transients of the focused window. Instead, defocus the - currently focused window. (fixes #151996). - - (Also, reenable focus stealing prevention and do a small spacing - cleanup) - - * src/window-props.c (init_net_startup_id): fix spacing - - * src/window.c (window_takes_focus_on_map): re-enable focus - stealing prevention, (meta_window_show): if the new window is - denied focus and is a transient of the currently focused window, - defocus the currently focused window but keep the transient on - top; remove some old code about transients and focus; make sure - that EnterNotify events won't accidentally focus the new window. - -2004-10-25 Elijah Newren - - Fix the alt-tab order--if the most recently used window is not - focused, start alt tabbing with that window instead of the one - after it (fixes #156251) - - * src/display.c (find_tab_forward): add a skip_first parameter, - (find_tab_backward): add a skip_last parameter, - (meta_display_get_tab_next): if a beginning window wasn't given - and the focused window isn't the tab chain, don't skip the MRU - window - -2004-10-22 Elijah Newren - - Update _NET_WM_STATE_HIDDEN so the pager on the panel will know - whether to display windows as visible or hidden (#105665) - - * src/screen.c (queue_windows_showing): Revert the - queue_windows_showing portion of the patch committed on 2004-10-16 - for #142198--it was an ill-advised optimization. - - * src/window.c (window_showing_on_its_workspace, - window_should_be_showing): split the old window_should_be_showing - into these two functions, (set_net_wm_state): hidden state is more - complex; use window_showing_on_its_workspace to determine the - correct value - -2004-10-20 Elijah Newren - - Patch from Soeren to fix the modifier key breakage introduced by - an Xorg change. (fixes #151554) - - * src/keybindings.c: include X11/XKBlib.h if available, - (handle_spew_mark): remove this unused function declaration, - (end_keyboard_grab): new function, uses XKB if available, - (process_tab_grab): use end_keyboard_grab to determine whether to - end the grab, (error_on_command): make key a const char *, - (process_workspace_switch_grab): use end_keyboard_grab to - determine whether to end the grab - -2004-10-19 Anders Carlsson - - * src/frame.c: (meta_window_ensure_frame): - Don't try to use an ARGB visual at all if the depth isn't - 32-bit. This caused major slowdowns with Composite enabled. - -2004-10-16 Elijah Newren - - Make the "showing desktop" mode be per-workspace instead of - per-screen. (fixes #142198) - - * src/keybindings.c (handle_toggle_desktop): access - showing_desktop through the active workspace - - * src/screen.c (meta_screen_new): remove initialization of - screen->showing_desktop, - (meta_screen_update_showing_desktop_hint): rename and make not - static and access showing_desktop through the active workspace, - (queue_windows_showing): replace meta_display_list_windows() with - screen->active_workspace->windows, - (meta_screen_minimize_all_on_active_workspace_except): renamed - from meta_screen_minimize_all_except since it now only works on - the active workspace, (meta_screen_show_desktop, - meta_screen_unshow_desktop): access showing_desktop through the - active workspace - - * src/screen.h (struct _MetaScreen): remove showing_desktop field, - (meta_screen_minimize_all_on_active_workspace_except): rename from - meta_screen_minimize_all_except, - (meta_screen_update)_showing_desktop_hint): export this function too - - * src/window.c (maybe_leave_show_desktop_mode): access - showing_desktop through the active workspace and use new name for - meta_screen_minimize_all_on_active_workspace_except, - (window_should_be_showing): access showing_desktop through the - active workspace - - * src/workspace.c (meta_workspace_new): initialize - workspace->showing_desktop, (meta_workspace_activate_with_focus): - add note that old can be NULL, update showing_desktop_hint if - different on this workspace than the previous one - - * src/workspace.h (struct _MetaWorkspace): add showing_desktop - field - -2004-10-16 Elijah Newren - - * rationales.txt: Add new tracker bugs - -2004-10-15 Elijah Newren - - * src/keybindings.c (reload_keymap): Fix from Rob to correct - requested number of keycodes (#155247) - -2004-10-13 Elijah Newren - - Code cleanup - - * src/window.c (is_in_dock_group, docks_at_end_cmp, - shuffle_docks_to_end): removed functions, - (meta_window_notify_focus): no need to call is_in_dock_group or - shuffle_docks_to_end because of the patch from #120100 that was - committed. - -2004-10-13 Vincent Untz - - Add a keybinding to launch a terminal - - * src/keybindings.c: (handle_run_terminal): new function, - (error_on_generic_command): new function, (error_on_command): wrapper - around error_on_generic_command(), (error_on_terminal_command): new - function - - * src/metacity.schemas.in: add run_command_terminal key - - * src/prefs.[ch]: (meta_prefs_init): cache the terminal command and - register a gconf callback to update it, (change_notify): handle the - notification of terminal command changes, (meta_preference_to_string): - add the terminal command case, (update_terminal_command): new function, - (meta_prefs_get_terminal_command): new function, - (meta_prefs_get_gconf_key_for_terminal_command): new function - -2004-10-11 Rob Adams - - * configure.in: bump version to 2.9.0. Add UNSTABLE warning. - -2004-10-11 Rob Adams - - * NEWS, README: Metacity 2.8.6 (stable release) - -2004-10-08 Elijah Newren - - Fix middle-frame-click-to-lower focus inconsistency (#154601) - - * src/core.c (meta_core_user_lower_and_unfocus): focus the default - window in all focus modes, not just click-to-focus (EnterNotify - events will not handle this case for sloppy and mouse focus) - - * src/display.c (event_callback): replace window->has_focus with - window == display->expected_focus_window to avoid a race issue - -2004-10-08 Elijah Newren - - Alter the meaning of expected_focus_window; doesn't affect - current operation but assists in fixing some other bugs - (#154598) - - * src/display.c (meta_display_focus_the_no_focus_window): set the - expected_focus_window to NULL. - - * src/window.c (meta_window_notify_focus): don't NULL the - expected_focus_window when that window receives a FocusIn event - -2004-10-04 Elijah Newren - - * src/display.c (event_callback): if the root window gets focused, - set the focus to the default window; this fixes the - "focus-follows-mouse" behavior seen for click-to-focus mode after - cancelling log out (fixes #153220) - -2004-10-04 Elijah Newren - - Fix a variety of issues with autoraise (#134206) - - * src/display.h: (struct _MetaDisplay): add an autoraise_window - parameter - - * src/display.[hc] (meta_display_focus_the_no_focus_window): new - function, (meta_display_queue_autoraise_callback): new function, - (meta_display_remove_autoraise_callback): new function - - * src/display.c (meta_display_open): intialize - display->autoraise_window too, (meta_display_close): remove any - pending autoraise callback, (window_raise_with_delay_callback): - clear out auto_raise->display->autoraise_window too, - (event_callback): call meta_display_queue_autoraise_callback - instead of having the code inline, call - meta_display_focus_the_no_focus_window to handle focusing that - window - - * src/window.c (meta_window_focus): If there's a window with an - autoraise timeout that isn't the window being focused, remove the - autoraise timeout - - * src/workspace.c (meta_workspace_focus_default_window): If no - autoraise timeout is queued for the given window then queue one - now, call meta_display_focus_the_no_focus_window to handle - focusing that window, (meta_workspace_focus_mru_window): call - meta_display_focus_the_no_focus_window to handle focusing that - window - -2004-10-04 Elijah Newren - - * src/display.c (event_callback): When no window becomes focused, - focus the default window instead of punting to the - no_focus_window. Also, change the warning to a verbose - message--this will happen frequently due to brain-damage in the X - protocol. (see #125492) - -2004-10-04 Elijah Newren - - Fix a variety of focus race conditions in all focus modes, or at - least make them harder to trigger (fixes #152000) - - * src/core.[ch] (meta_core_user_lower_and_unfocus): add a - timestamp parameter; pass it along to - meta_workspace_focus_default_window - - * src/display.[ch] (meta_display_get_current_time_roundtrip): new - function - - * src/display.c (event_callback): pass a timestamp to the - meta_workspace_activate and meta_workspace_focus_default_window - function calls - - * src/frames.c (meta_frames_button_press_event): pass a timestamp - to meta_core_user_lower_and_unfocus - - * src/keybindings.c (handle_activate_workspace): pass a timestamp - to meta_workspace_activate, (process_workspace_switch_grab): pass - a timestamp to meta_workspace_focus_default_window and - meta_workspace_activate, (handle_toggle_desktop): pass a timestamp - to meta_workspace_focus_default_window, - (do_handle_move_to_workspace): pass a timestamp to - meta_workspace_activate_with_focus, (handle_workspace_switch): - meta_workspace_activate - - * src/screen.c (meta_screen_new): pass a timestamp to - meta_workspace_activate - - * src/window.c (meta_window_free): pass a timestamp to - meta_workspace_focus_default_window, (idle_calc_showing): don't - increment the focus sentinel here, (meta_window_minimize): pass a - timestamp to meta_workspace_focus_default_window, - (meta_window_client_message), pass a timestamp to - meta_workspace_focus_default_window - - * src/workspace.h (meta_workspace_activate): add timestamp - parameter, (meta_workspace_activate_with_focus): add timestamp - parameter, (meta_workspace_focus_default_window): add timestamp - parameter - - * src/workspace.c (meta_workspace_focus_mru_window): make this - function take a timestamp and use it for meta_window_focus or - XSetInputFocus, (meta_workspace_activate_with_focus): make this - function take a timestamp and pass it along to meta_window_focus - and meta_workspace_focus_default_window, - (meta_workspace_activate): make this function take a timestamp and - pass it to meta_workspace_activate_with_focus), - (meta_workspace_focus_default_window): make this function take a - timestamp, warn if its 0 but try to handle that case sanely, and - pass the timestamp on to meta_window_focus or - meta_workspace_focus_mru_window or XSetInputFocus - -2004-09-22 Elijah Newren - - * src/keybindings.c (process_workspace_switch_grab): Focus the - default window after the user dismisses the workspace switcher - popup (fixes #123803; note that an alternate fix was made - independently by David Baron for sloppy and mouse focus users) - -2004-09-22 Elijah Newren - - Fix some uninitialized variable errors reported by valgrind (see - #153338) - - * src/display.c (meta_display_open): initialize - display->grab_resize_timeout_id, and display->grab_have_keyboard - - * src/ui.c (meta_ui_create_frame_window): initialize attrs.width - and attrs.height - -2004-09-17 Elijah Newren - - * src/workspace.c (meta_workspace_focus_mru_window): Don't focus a - window that is minimized (fixes #147947) - -2004-09-17 Kjartan Maraas - - * src/bell.c: (meta_bell_flash_screen): - * src/compositor.c: - * src/effects.c: (meta_effects_draw_box_animation): - * src/fixedtip.c: (meta_fixed_tip_show): - * src/frame.c: (find_argb_visual): - * src/frames.c: (unsigned_long_hash), (meta_frames_manage_window), - (meta_frames_apply_shapes): - * src/iconcache.c: (find_largest_sizes), (find_best_size): - * src/keybindings.c: (meta_spawn_command_line_async_on_screen): - * src/main.c: (main): - * src/menu.c: (meta_window_menu_new): - * src/prefs.c: (meta_prefs_get_visual_bell), - (meta_prefs_bell_is_audible), (meta_prefs_get_visual_bell_type), - (meta_prefs_get_action_double_click_titlebar), - (meta_prefs_get_auto_raise), (meta_prefs_get_auto_raise_delay), - (meta_prefs_get_reduced_resources): - * src/screen.c: (meta_create_offscreen_window): - * src/tabpopup.c: (meta_ui_tab_popup_get_selected): - * src/theme-parser.c: (meta_theme_load): - * src/theme.c: (meta_gtk_widget_get_font_desc): - * src/tools/metacity-mag.c: (mouse_press), (begin_area_grab): - * src/util.c: (meta_unsigned_long_hash): A load of fixes of issues - reported by sparse. Closes bug #152849 - -2004-09-15 Elijah Newren - - * src/display.c (event_callback): Remove some redundant code - regarding focusing the default window (#152117) - -2004-09-15 Elijah Newren - - Patch from Ken Harris in #135786 to focus a new default window - when lowering via middle-click on the frame. - - * src/core.[hc], src/frames.c: rename meta_core_user_lower to - meta_core_user_lower_and_unfocus - - * src/core.c (meta_core_user_lower_and_unfocus): if in - click-to-focus mode then also move the window to the back of the - mru list and focus the new default window for the active workspace - -2004-09-15 Elijah Newren - - Focus the no_focus_window if no suitable window is in the mru list - (should fix the almost contrived extra issue found in #147475) - - * doc/how-to-get-focus-right.txt: We no longer need to lie about - only focusing panels upon explicit request. - - * src/workspace.c: (meta_workspace_focus_top_window): removed this - function--it was more code than needed and was unreliable anyway, - (meta_workspace_focus_mru_window): if a suitable window isn't in - the mru list, focus the no_focus_window instead of calling - focus_top_window. - -2004-09-15 Elijah Newren - - Prevent focus inconsistencies by only providing one focus method - (fixes #151990) - - * src/screen.c (meta_screen_show_desktop): remove call to - meta_workspace_focus_top_window (it was merely focusing a window - that was going to be hidden anyway, and likely the one that - already had focus) - - * src/workspace.[hc]: remove meta_workspace_focus_mru_window and - meta_workspace_focus_top_window from workspace.h, make them static - functions in workspace.c - -2004-09-15 Elijah Newren - - Remove race condition for focus window choice on window close - followed by rapid mouse movement in sloppy and mouse focus modes - (partially fixes #152000) - - * src/window.c (meta_window_free): Don't increment the focus - sentinel for windows being freed, (idle_calc_showing): don't - increment the focus sentinel for windows being minimized - -2004-09-15 Elijah Newren - - Fix unwanted loss of focus to the mouse window when using keynav - (fixes #101190) - - * src/display.c (event_callback): Ignore EnterNotify events with - xcrossing.mode of either NotifyGrab or NotifyUngrab - -2004-09-15 Elijah Newren - - Focus correct window after minimizing via the tasklist (fixes - #128200; see also #107681) - - * src/display.h (struct _MetaDisplay): track the - previously_focused_window - - * src/display.c (meta_display_open): initialize - previously_focused_window - - * src/window.c (meta_window_free): clear the - previously_focused_window if it's being freed, - (meta_window_client_message): if we get a request to minimize the - previously_focused_window and the focus_window is a dock or the - desktop, focus the default window, (meta_window_notify_focus): - update the previously_focused_window - -2004-09-13 Rob Adams - - * configure.in: post-release increment - -2004-09-13 Rob Adams - - * configure.in: bump version number - - * NEWS: 2.8.5 release - - * README: 2.8.5 release - -2004-09-14 Gora Mohanty - - * configure.in: Added 'or' to ALL_LINGUAS. - -2004-09-07 Elijah Newren - - Add a new write-up on making window focus consistent (see #152004) - - * doc/how-to-get-focus-right.txt: New document - - * rationales.txt: Remove references to focus bugs, instead point - to doc/how-to-get-focus-right.txt - -2004-09-06 Elijah Newren - - * rationales.txt: Add bugs regarding window focus - -2004-08-29 Elijah Newren - - * NEWS: 2.8.4 release - -2004-08-29 Elijah Newren - - * src/window.c (window_takes_focus_on_map): Disable - focus-stealing-prevention for now; there are still some issues and - hard code freeze is tomorrow...so this will have to wait until - Gnome 2.10. - -2004-08-27 Havoc Pennington - - * src/compositor.c (meta_compositor_new): disable NameWindowPixmap - stuff always for now, it seemed kind of busted - (paint_screen): don't grab the server during repaint, adds to the - speed, though only slightly. - - * src/frames.c (meta_frames_set_window_background): factor out all - the set_background stuff to one function; disable setting - background to transparent, because it breaks existing themes. We - need to add a flag in the theme XML file to say "start me with a - transparent background" - -2004-08-27 Elijah Newren - - Prevent an assertion failure that can occur after increasing the - number of workspaces; also fix a warning and stacking order when a - window is denied focus (fixes #150615) - - * src/window.c (meta_window_stack_just_below): the position of the - window should be set equal to that of the one we want to be below, - not 1 lower than that number - - * src/workspace.c (maybe_add_to_list): new function to add - on_all_workspace windows to an mru_list, (meta_workspace_new): - call maybe_add_to_list for all windows on the screen in order to - initialize the mru_list - -2004-08-26 Havoc Pennington - - * src/frame.c: delete extra copy of find_argb_visual so things - compile - - * src/compositor.c (HAS_NAME_WINDOW_PIXMAP): copy the - XCompositeNameWindowPixmap() stuff from xcompmgr, though I can't - say I really know what it's supposed to help with (painting the - window border?) - -2004-08-26 Havoc Pennington - - * src/frame.c, src/theme.c: couple of cosmetic tweaks from - resolving my local patch with the bugzilla patch from the 8-19 - entry below - -2004-08-26 Havoc Pennington - - * configure.in: move the have_xrender variable initialization up - in the file since it can be set as part of composite check - -2004-08-19 Havoc Pennington - - Fixes from Rich Wareham - - * src/display.h (struct _MetaDisplay): add render extension check - to the display - - * src/display.c: check for render - - * configure.in: don't build compositing manager by default, don't - want any nasty surprises; check for render separately from - compositing manager - - * src/frame.c: use an ARGB visual when available for the window - frame, so we can be all cool-ass - -2004-08-25 Elijah Newren - - Make dialogs that Metacity shows follow focus-stealing-prevention - conventions. (fixes one issue in #149028; see comments 47-54) - - * src/delete.c (delete_ping_reply_func, - delete_ping_timeout_func): Make callback functions take a - timestamp arg, (delete_ping_timeout_func): pass the timestamp to - metacity-dialog - - * src/display.c (meta_display_ping_timeout): add a timestamp to - the call to the ping_timeout_func, (meta_display_ping_window, - process_pong_message): add a timestamp to the call to the - ping_reply_func - - * src/display.h (MetaWindowPingFunc typedef): add a timestamp to - this function typedef - - * src/keybindings.c (error_on_command): require a timestamp and - pass the timestamp on to metacity-dialog, (handle_run_command): - pass a timestamp to error_on_command - - * src/metacity-dialog.c (copy_of_gdk_x11_window_set_user_time): - new function (temporary; only for use while using gtk+-2.4), - (kill_window_question, warn_about_no_sm_support, - error_about_command): make these functions take a timestamp and - call copy_of_gdk_x11_window_set_user_time, (main): require the - first two args to the program to be "--timestamp " - - * src/session.c (warn_about_lame_clients_and_finish_inter): pass a - timestamp of 0 to metacity-dialog to prevent focus (it's a popup - not generated by and kind of user request). - -Fri Aug 20 12:54:12 2004 Soeren Sandmann - - * src/display.c (meta_display_end_grab_op): Move wireframe code - before grab is released to prevent endless loops with fullscreen - windows. - -2004-08-18 Havoc Pennington - - * src/display.h (struct _MetaDisplay): track the last_xor_rect - separately from the current window size, and then use that to - paint the wireframe including the frame, and taking into - account shaded windows. - - * src/window.c (meta_window_get_xor_rect): new function to compute - the xor rect; it is not really 100% right, because it uses the - frame dimensions from the window at the start of the move/resize. - But probably won't break in practice. - -2004-08-17 Christian Rose - - * configure.in: Added "bs" to ALL_LINGUAS. - -2004-08-16 Kjartan Maraas - - * configure.in: Added nb to ALL_LINGUAS. - -2004-08-15 Rob Adams - - * configure.in: Bump version to 2.8.4 - -2004-08-15 Rob Adams - - * NEWS: 2.8.3 release - -2004-08-15 Rob Adams - - * src/windows.c (meta_window_update_struts): use height and - top/bottom struts to compute gap (copy/paste bug). - -2004-08-15 Rob Adams - - * src/window.c (meta_window_update_struts): Allow struts larger - than 1/2 the screen width/height, as long as there's a minimum - sized gap between them. Patch from Bill Haneman - for bug #144126. - -2004-08-13 Gurban M. Tewekgeli - * po/tk.po: Added Turkmen translation. - * configure.in: Added "tk" to ALL_LINGUAS. - -Mon Aug 9 05:38:33 2004 Soeren Sandmann - - * src/effects.c (graphics_sync): New function. - * src/effects.c (effects_draw_box_animation_timeout): Use it here - to synchronize with the hardware between each frame. - -2004-08-08 Rob Adams - - * src/window.c (meta_window_move_resize_internal): Add #ifdef - around XSYNC code; fixes compile problem if XSYNC is disabled. - Path for #149314 from Peter O'Shea and independently Mike Castle. - -Sun Aug 8 14:20:00 2004 Soeren Sandmann - - * src/frame.c (meta_frame_set_screen_cursor): Flush after setting - cursor. (Rest of #149413). - -2004-08-07 Elijah Newren - - * src/display.c (event_callback): activating the current workspace - should be a no-op. This prevents a race condition in focus window - choice when activating a window via the taskbar. Fix for #149589. - -2004-08-07 Elijah Newren - - * src/window.c, src/window.h: Revert Rob's 2004-07-31 patch that - ignored net_wm_user_time when unminimizing a window - - * src/window.c (meta_window_activate): If a nonzero timestamp is - passed, update the window's net_wm_user_time accordingly. (see - comments 102-108 of bug 118372) - -2004-08-07 Rob Adams - - Remove some extraneous items that could sometimes appear in the - window menu. Fix for #144493. - - * src/menu.c (menuitems): Change the second separator to key on - whether there are any workspaces. - (meta_window_menu_new): use NULL label instead of 0 op to identify - separator - - * src/window.c (meta_window_show_menu): Change the conditions on - the directions to take into account "holes" in the workspace - layout and also only set META_MENU_OP_WORKSPACES when there's more - than one workspace. - -2004-08-07 Havoc Pennington - - * src/screen.c (meta_screen_set_cursor): add XFlush() after - setting cursor, #149413 - -2004-08-06 Elijah Newren - - * src/display.c (event_callback): Focusing a window upon unshowing - the desktop in various ways (panel applet or keybinding) was - inconsistent for sloppy and click focus modes. Fix this by - calling meta_workspace_focus_default_window after unshowing the - desktop via a _NET_SHOWING_DESKTOP message. (resolves #149543) - -2004-08-06 Elijah Newren - - * src/workspace.c (meta_workspace_focus_default_window): prevent - keyboard from "getting locked" upon workspace switch, by making - sure that the no_focus_window has focus if no other window does. - (fixes #147475) - -2004-08-05 Elijah Newren - - Have newly mapped windows that are denied focus appear after the - focused window in the alt-tab list. This allows one to switch to - such a window with a single alt-tab press. (fixes #149366) - - * src/window.c (ensure_mru_position_after): new function, - (meta_window_show): If newly mapped window is denied focus, call - ensure_mru_position_after to make the window appear after the - focus window in the mru list. - -2004-08-05 Elijah Newren - - * src/window.c (meta_window_stick): prepend window to mru list - instead of appending, since making the window sticky should imply - that it is the most recently used, not the least recently. (fixes - #149369) - -2004-08-04 Elijah Newren - - * configure.in: post-release version bump (2.8.3) that I forgot to - do yesterday. - -2004-08-03 Elijah Newren - - Released 2.8.2 - - * NEWS, README: update - -2004-08-02 Elijah Newren - - Fix some bugs (reported in #120100) regarding the focus window - when using the workspace switcher. - - * src/display.c (event_callback): When switching workspaces due to - a _NET_CURRENT_DESKTOP message, make sure to focus the default - window as well. - - * src/workspace.c (meta_workspace_focus_default_window, - meta_workspace_focus_mru_window): Make DOCK or DESKTOP windows - have lower priority than others when choosing a window to focus. - (For the former function, this means don't focus them at all; for - the latter, this means only focus them (via the - meta_workspace_focus_top_window call) if no other mru window can - be found.) - -2004-07-31 Rob Adams - - Fix bug that caused windows to not be focused on unminimizing - because of user time support. - - * src/window.c (meta_window_new_with_attrs): initialize - focus_despite_user_time bit - (window_takes_focus_on_map): focus if focus_despite_user_time - despite user time, interestingly enough - (meta_window_show): reset focus_despite_user_time after showing - - * src/window.h (_MetaWindow): add focus_despite_user_time bit - -2004-07-31 Rob Adams - - Fix some support for EWMH hints, and fix USER_TIME support to - include the DEMANDS_ATTENTION hint. Also includes some code for - implementing _NET_RESTACK_WINDOW and _NET_MOVERESIZE_WINDOW, but - this is disabled pending feature thaw. - - * COMPLIANCE: update with new information - - * src/display.c (meta_display_open): add new hints to list - - * src/display.h (_MetaDisplay): Add new atoms to struct - - * src/screen.c (set_supported_hint): update the list of support - hints. - (set_desktop_viewport_hint): new function sets the viewport hint - to (0,0) as required by the spec for WMs with no viewport support. - (set_desktop_geometry_hint): new function to set the desktop size - hint to the size of the display, since we don't implement large - desktop support, as required by the spec. - (meta_screen_resize): update the geometry hint on screen resize - - * src/window.c (meta_window_new_with_attrs): Initialize - demands_attention state - (set_net_wm_state): Set demands_attention hint in the window state - (meta_window_show): If we don't pop up a window because of - USER_TIME, set DEMANDS_ATTENTION on the window. - (meta_window_focus): When a window receives focus, remove - DEMANDS_ATTENTION hint - (meta_window_client_message): Allow other apps to set - DEMANDS_ATTENTION on a window. Also, if the _NET_ACTIVE_WINDOW - hint includes a timestamp, use it. - (update_net_wm_state): Read DEMANDS_ATTENTION state also - - * src/window.h (_MetaWindow): add wm_state_demands_attention bit. - -2004-07-22 Rob Adams - - * src/metacity.schemas.in: Add trailing quotes to keybinding - explanation text. Patch from Emil Soleyman-Zomalan. - -Fri Jun 25 17:41:53 2004 Soeren Sandmann - - * configure.in: Require startup-notification 0.7 - -2004-06-25 Rob Adams - - * COMPLIANCE: indicate that _NET_WM_USER_TIME is now supported - -2004-06-24 Elijah Newren - - * src/keybindings.c: (handle_toggle_desktop): Choose correct - window to focus when "un-showing" the desktop. Fixes #144900. - -2004-06-24 Elijah Newren - - Make choice of focus window be consistent for each focus mode. - Fixes #135810. - - * src/delete.c: (meta_window_delete): In some #if 0'ed code, - replace meta_workspace_focus_mru_window with - meta_workspace_focus_default_window (just in case the code becomes - un-#if 0'ed out). - - * src/screen.c, src/screen.h: Change - meta_screen_focus_mouse_window to meta_screen_get_mouse_window, - and don't focus the window when found but rather return it. - - * src/window.c: (meta_window_free, meta_window_minimize): replace - meta_workspace_focus_mru_window with - meta_workspace_focus_default_window. - - * src/workspace.c: (meta_workspace_focus_default_window): Focus - appropriately for the given focus method: - click-to-focus: focus MRU window (== toplevel window) - sloppy focus: focus the window under the pointer if there is - such a window, otherwise focus the mru window - mouse focus: focus the window under the pointer if there is - such a window, otherwise don't focus anything - -2004-06-24 Elijah Newren - - * src/window.c: Avoid a race condition on the choice of window to - focus after the previously focused window gets closed or - minimized. Fixes #131582. - -2004-06-24 Elijah Newren - - * src/metacity.schemas.in: make naming for "move a window"/"move - the window"/"move window" more consistent. Patch from Michael - Terry for #142235. - -2004-06-24 Elijah Newren - - * src/session.c: Change meta_warning to meta_topic on failure to - connect to a session manager. Fixes #136218. - -2004-06-17 Elijah Newren - - Add support for _NET_WM_USER_TIME - - * src/display.c: - (meta_display_open): Add _NET_WM_USER_TIME to atom_names[], - (event_callback): Manually set _NET_WM_USER_TIME upon KeyPress - (doesn't work since keyboard isn't grabbed) and ButtonPress (does - work), this is just a fallback for applications that don't update - this themselves. - - * src/display.h: (struct _MetaDisplay): Add atom_net_wm_user_time field - - * src/screen.c: (meta_screen_apply_startup_properties): Check for - TIMESTAMP provided from startup sequence as well. - - * src/stack.c: - s/meta_window_set_stack_position/meta_window_set_stack_position_no_sync/, - (meta_window_set_stack_position): New function which calls the - meta_window_set_stack_position_no_sync function followed immediately - by calling meta_stack_sync_to_server. - - * src/window-props.c: - (init_net_wm_user_time), (reload_net_wm_user_time): new functions, - (reload_wm_hints): also load atom_net_wm_user_time - - * src/window.c: - new XSERVER_TIME_IS_LATER macro (accounts for timestamp wraparound), - (meta_window_new_with_attrs): add timestamp attributes, - (window_takes_focus_on_map): use TIMESTAMP from startup - notification and _NET_WM_USER_TIME to decide whether to focus new - windows, - (meta_window_show): if app doesn't take focus on map, place it - just below the focused window in the stack - (process_property_notify): check for changes to _NET_WM_USRE_TIME, - (meta_window_stack_just_below): new function - - * src/window.h: - (_MetaWindow struct): new fields for initial_timestamp, - initial_timestamp_set, net_wm_user_time_set, and net_wm_user_time, - (meta_window_stack_just_below): new function - -2004-06-21 Anders Carlsson - - * src/common.h: - * src/menu.c: (menu_closed), (activate_cb): - * src/window.c: (menu_callback): - Add a timestamp argument to menu functions and - use it in meta_window_delete. - -2004-06-21 Anders Carlsson - - * src/window.c: (meta_window_client_message): - Get the timestamp from the client message. - -Sat Jun 19 02:21:08 2004 Soeren Sandmann - - Fix bug 143333, support for update counter spec, and 109362, - schedule compensation events when events are ignored. - - * src/display.c (meta_display_open): Add _NET_WM_SYNC_REQUEST and - _NET_WM_SYNC_REQUEST_COUNTER atoms. Remove the old - METACITY_SYNC_COUNTER stuff. - (meta_display_begin_op): Setup the sync counter - - * src/xprops.c, src/xprops.h, src/window-props.c, src/display.h: - Add new atoms. - - * src/window.c (send_sync_request): new function. - (meta_window_move_resize_internal): send a sync request before - resizing. - (check_move_resize_frequence): Rework logic to also check the SYNC - case. If an event is ignored return the remaining time. - (update_resize_timeout): Timeout that gets called when a - compensation event is scheduled. - (uddate_resize): schedule compensation events when an event is - ignored. - (meta_window_handle_mouse_grap_op_event): When an alarm is - received and sync was turned off, turn it back on. - - * src/window.h (struct MetaWindow) Add some variables - -2004-06-16 Havoc Pennington - - * configure.in: bump version, add the UNSTABLE note - - * Branch off GNOME 2.6, we are now officially unstable - -2004-06-04 Jeff Waugh - - * src/metacity.schemas.in: Set titlebar_uses_system_font = false. The - previous default was almost violent in its lack of appreciation for - human beings. In fact, this entire setting should probably be removed, but - for now, let's just fix the default. Permission granted by Havoc. - -2004-05-04 Elijah Newren - - * configure.in: 2.8.1 - - * NEWS: update - -2004-05-02 Rob Adams - - * src/metacity-dialog.c (warn_about_no_sm_support): make the no sm - support warning dialog resizable, since the default GTK warning - dialog not has default not resizable. Fix for #141672 from - Olivier Crete. - -2004-04-29 Rob Adams - - * src/prefs.c (change_notify): Add a value type check for the - visual bell/audible bell gconf settings. Patch from Jarrod - Johnson for #141409. - -2004-04-19 Mark McLoughlin - - Syncing across this change from libwnck. - Patch from Neil Muller in bug #133979. - - * src/iconcache.c: (find_largest_sizes), (find_best_size): - Don't down-size nitems from a gulong to an int. Fixes a - crash with enlightenment, apparently. - -2004-04-16 Iñaki Larrañaga - - * configure.in: Added "eu" (Basque) to ALL_LINGUAS. - -2004-04-15 Elijah Newren - - * src/display.c: Prevent unwanted grab op from occurring. - Previously, for some people under certain conditions, clicking and - releasing the mouse button rapidly enough would result in Metacity - starting a move operation due to ignoring the button release. - This should fix that problem (it does for me). See bug 136587. - -2004-04-11 Rob Adams - - * configure.in: Make the --enable-xinerama switch work properly. - Fix for #138562 from foser@gentoo.org. - -2004-04-09 Guntupalli Karunakar - - * configure.in: Added "gu" (Gujarati) to ALL_LINGUAS. - -2004-03-27 Tõivo Leedjärv - - * configure.in: Added et to ALL_LINGUAS. - -2004-03-24 Guntupalli Karunakar - - * configure.in: Added "pa" (Punjabi) to ALL_LINGUAS. - -2004-03-21 Havoc Pennington - - * configure.in: 2.8.0 - - * NEWS: update - -2004-03-07 Elijah Newren - - * rationales.txt: Bring up to date (see bug 136252). - -2004-03-07 Havoc Pennington - - * configure.in: 2.7.1 - -2004-03-04 Paisa Seeluangsawat - - * configure.in: Added "th" (Thai) to ALL_LINGUAS. - -2004-03-01 Rob Adams - - * src/stack.c (compute_layer): don't promote due to transiency; we - handle that elsewhere now. - (ensure_above): perform layer promotion here as well as stack - position promotion. Note that this means that we need to do stack - constraints now on layer change now. - (get_maximum_layer_of_ancestor): remove function - (max_layer_func): remove function - (MaxLayerData): remove struct - -2004-02-28 Rob Adams - - Revert 2/27 patch for layer promotion. - -2004-02-27 Rob Adams - - * src/window.c (meta_window_notify_focus): only move on MRU list - if the window belongs on the workspace, since the FocusIn event - could be for a window whose workspace we've since switched away - from. Possible fix for #122016. - - * src/workspace.c (meta_workspace_contains_window): search for the - workspace in window->workspaces rather than the window in - workspace->windows. Since the number of workspaces is at most 36, - this is a O(1) lookup rather than a O(n) lookup. Sorry; couldn't - resist. - -2004-02-27 Rob Adams - - * src/metacity.schemas.in: Change - move_to_workspace_left/right/up/down keybindings to - arrow to avoid conflicting with new - keybindings in spacial nautilus. - -2004-02-27 Rob Adams - - Handle layer promotion of transient descendants of layer-promoted - windows to also be layer promoted, using a simple iterative - algorithm. - - * src/stack.c (compute_layer): change name to promote_layer, and - convert to simply perform any necessary layer promotion without - computing the standalone layer. - (max_layer_func): use window->layer instead of - get_standalone_layer - (get_maximum_layer_of_ancestor): use window->layer instead of - get_standalone_layer - (meta_stack_ensure_sorted): implement iterative algorithm, - explained in a long comment. - - * src/window.h: add a tmp_layer field used by stack.c for - determining if the stack is dirty or not, since maintaining this - information in meta_stack_ensure_sorted is no longer practical. - -2004-02-23 Rob Adams - - Add my copyright notice to a number of files on which it should - already exist. - - * src/window.c (meta_window_notify_focus): modify code to move to - front of MRU list so that we can have an assert that it was there - in the first place. This code may be causing some crashes. See - #131196. - -2004-02-22 Christian Rose - - * configure.in: Added "en_CA" to ALL_LINGUAS. - -2004-02-19 Rob Adams - - * src/prefs.h: remove trailing comma in MetaKeyBindingAction enum. - Fix for #134868 thanks to bugzilla-gnome@thewrittenword.com. - -2004-02-16 Rob Adams - - * src/window.c (update_move): reset drag state after shaking loose - or reattaching. Fix for #132625. - -2004-02-15 Anders Carlsson - - * src/menu.c (meta_window_menu_new): Actually translate a message, - don't just mark it for translation. - -2004-02-14 Elijah Newren - - * src/workspace.c: When moving a window to a different workspace, - prepend it to the mru list insted of appending it. Fixes #134368. - -2004-02-14 Rob Adams - - If we're moving a window and receive a _NET_CURRENT_DESKTOP - message indicating a workspace switch, bring along the drag window - to the new workspace, solving a potentially weird bug where the - window would be lost on the old workspace. This also makes it - possible to implement edge flipping in an external program with - just a few lines of code. Patch for #131630 from ed@catmur.co.uk. - - * src/keybindings.c (switch_to_workspace): remove function -- no - longer needed. - (handle_activate_workspace): call meta_workspace_activate instead - of switch_to_workspace - - * src/workspace.c (meta_workspace_activate_with_focus): if we're - in a move grab op, bring along the drag window. - -2004-02-14 Rob Adams - - * configure.in: Add configure option to not even try using - xinerama, to make metacity buildable on systems with no shared - library version of the xinerama libraries. Patch for #134203 from - Julio M. Merino Vidal. - -2004-02-01 Rob Adams - - * COMPLIANCE: Bring up to date with current draft EWHM. - -2004-01-27 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Use the 'utility' frame - for dialogs too. - -2004-01-24 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Updated this theme. - -2004-01-21 Elijah Newren - - * src/screen.c (set_supported_hint): Removed some duplicate - entries. - -2004-01-17 Rob Adams - - * src/metacity.schemas.in: Default binding removed for - toggle_shaded, since we don't have anything in the graphical UI - for it any more. - -2004-01-17 Rob Adams - - * src/window.c (meta_window_show_menu): Don't show - left/right/up/down if a window is sticky. Make "On Top" - insensitive for docks, splash screens, and desktops since it has - no effect anyway. - -2004-01-10 Rob Adams - - * src/metacity.schemas.in: update default - action_double_click_titlebar to be toggle_maximize instead of - toggle_shade. See #131126. - -2004-01-10 Rob Adams - - * src/constraints.c (meta_window_constrain): if we maximize after - placement, and the window is too big to fix in the work area, - define a sane saved_rect approximately with dimensions - three-quarters approximately three quarters the size of the work - area. This avoids the problem where large windows would - unmaximize and actually get bigger. See #93590. - -2004-01-09 Thomas Fitzsimmons - - Add _NET_FRAME_EXTENTS and _NET_REQUEST_FRAME_EXTENTS. - - * src/display.c: include xprops.h - (process_request_frame_extents): new function - (meta_display_open): add _NET_FRAME_EXTENTS and - _NET_REQUEST_FRAME_EXTENTS atoms - (event_callback): handle frame extents message - - * src/display.h (struct _MetaDisplay): add atom_net_frame_extents - and atom_net_request_frame_extents - - * src/theme.c (meta_pango_font_desc_get_text_height): make font_desc - parameter const - - * src/ui.c: include prefs.h - (meta_ui_theme_get_frame_borders): new function - - * src/window.c (update_net_frame_extents): new function - (meta_window_move_resize_internal): update frame extents - property when frame geometry changes - - * src/screen.c (set_supported_hint): add atom_net_frame_extents - and atom_net_request_frame_extents - -2004-01-09 Calum Benson - - * src/themes/Atlanta/metacity-theme-1.xml: - - Ensure Atlanta window buttons get larger when using large - print themes. Fixes #123469. - -2003-01-04 Rob Adams - - Maintain the button grab for sloppy and mouse focus all the time. - This fixes a number of problem introduced by trying to drop the - grab; we now do this only for click to focus mode. This has the - unfortunate effect that #102209 reappears for sloppy and mouse - focus, but this seems unavoidable, because of limitations in the X - protocol. See #115072. - - * src/display.c (meta_display_grab_focus_window_button): #if 0 the - section on not grabbing unless in click-to-focus mode. - - * src/window.c (meta_window_notify_focus): drop focus button grab - on FocusIn and acquire it on FocusOut only when in click-to-focus - mode. - -2004-01-03 Robert Sedak - - * configure.in: Added "hr" in ALL_LINGUAS. - -2003-01-02 Rob Adams - - * README: Update reference to EWMH. - - * HACKING: Add a reference to COMPLIANCE and to the ICCCM and - EWHM. - -2003-12-25 Havoc Pennington - - * src/compositor.c (process_reparent): handle ReparentNotify, and - add a lot of debug output. - -2003-12-25 Havoc Pennington - - * src/compositor.c (meta_compositor_process_event): change to - track all children of the root window, not only mapped children; - this keeps us from losing track of the stacking order - - * src/display.c (event_callback): don't do any of the compositor - event handling inline, do it all in compositor.c - -2003-12-21 Rob Adams - - Reorganize the window menu according to discussion on #110904. - The workspace name mnemonic chunk of the patch is thanks to - Jonathan Blandford. - - * src/common.h: add MENU_OP_ABOVE, MENU_OP_UNABOVE, MENU_UP_MOVE_TO_* - menu ops. - - * src/core.c (meta_core_get_menu_accelerator): add accelerator for - the new menu ops. - - * src/menu.c: add checked attribute in _MenuItem struct to display - a checkmark next to a menu item. Add the new menu items to - menuitems. - (get_workspace_name_with_accel): Add mnemonics even to renamed - workspaces. - (menu_item_new): provide support for the checked attribute - (meta_window_menu_new): construct new submenu for workspace - switching. - - * src/window.c (menu_callback): implement support for the new menu - ops. - (meta_window_show_menu): don't use the OP_*SHAPE operations, and - compute which of the OP_MOVE_TO_* ops should be used for the - current workspace and workspace layout. Add the OP_*ABOVE - operations. - -2003-12-20 Arafat Medini - - * configure.in: Added Arabic locale "ar" to ALL_LINGUAS - -2003-12-17 Rob Adams - - * src/display.c (meta_display_open): initialize - grab_wireframe_active to FALSE. Fix for #128090. - -2003-12-17 Rob Adams - - * src/tabpopup.c (meta_ui_tab_popup_new): Don't try to call - utf8_strndup on a null title for an entry. Fix for #128566. - - * src/workspace.c (meta_workspace_free): Call g_list_free on the - mru_list, since with sticky windows that MRU list could well not - be emtpy. See #122016. - -2003-12-13 Rob Adams - - * src/window.c (meta_window_new_with_attrs): set on_all_workspaces - in all cases _before_ adding to the workspaces, so that windows - initially on all workspaces are added correctly to the MRU lists. - Fix for #120907. - - * src/workspace.c (meta_workspace_add_window): handle sticky - windows so that we add to add mru lists if needed - (meta_workspace_remove_window): handle sticky windows so that they - are removed from all mru lists if needed. - -2003-12-12 Havoc Pennington - - * src/window.c (meta_window_free): unstick window to get it out of - mru_list it should not be in; assert that window has been removed - from all mru_list. Perhaps fixes #122016 crash. - -2003-11-29 Havoc Pennington - - * fix up compositing manager to somewhat work - -2003-11-26 Rob Adams - - * COMPLIANCE: fix a couple of minor typos. - -2003-11-24 Havoc Pennington - - * src/compositor.c (meta_compositor_new): fix the extension checks - -2003-11-24 Havoc Pennington - - * src/iconcache.c (meta_icon_cache_init): init prev_mask field - - * src/window.c (meta_window_new_with_attrs): init xgroup_leader - prior to use - -2003-11-24 Havoc Pennington - - * src/display.c (meta_display_begin_grab_op): add an event_serial - argument and use it when the pointer is already grabbed - automatically on the button press. May fix bug #126871 - -2003-11-24 Havoc Pennington - - * Apply patch from Gregory Merchan to avoid using CurrentTime when - setting input focus. Bug #108881 - -2003-11-23 Havoc Pennington - - * src/compositor.c: move xcompmgr code in here (minus drop - shadows), untested since Keith's server just crashes at the - moment. "It compiles" - -2003-11-20 Havoc Pennington - - * src/window.c (meta_window_new_with_attrs): new function - - * src/display.c, src/screen.c: create the compositor and feed - windows and events to it - -2003-11-20 Havoc Pennington - - * src/window.c (meta_window_notify_focus): revert the change here - -2003-11-17 Rob Adams - - Create COMPLIANCE document describing metacity specification - compliance. Right now gives detailed EWMH compliance; still need - to add ICCCM compliance information. Also some minor fixes to - bring metacity into compliance on some points. - - * COMPLIANCE: new file - - * src/display.h, src/display.c (meta_display_open), - src/screen.c (set_supported_hint): add - atom_net_wm_action_fullscreen and atom_net_wm_action_minimize - - * src/window.c (set_allowed_actions_hint): some fixes to which - hints to set and add fullscreen and minimize. - -2003-11-16 Rob Adams - - * src/window.c (meta_window_notify_focus): add paranoia check to - make sure a window is really on a workspace before inserting it at - the beginning of the MRU list. Maybe there's a race condition - with focusing and workspace switching. Hopefully a fix for - #122016. - -2003-11-15 Havoc Pennington - - * src/main.c (main): fix warning - - * src/compositor.c: add a new file to contain compositing manager - functionality; not yet implemented at all. - -2003-11-15 Rob Adams - - Inherit visual from frame window so that metacity will work with - the new compositing manager extension work by Keith on - freedesktop.org, so that ARGB windows can be full - alpha-transparent without a metacity frame getting drawn in the - background. In the long term, we need to actually set alpha - values when drawing the frame so that it will really work; this is - a stopgap solution. Patch from Keith Packard; see Bug 126875. - - * src/frame.c (meta_window_ensure_frame): pass client visual to - frame. - - * src/ui.[ch] (meta_ui_create_frame_window): add new xvisual - parameter and use it to create new window. - -2003-11-15 Rob Adams - - * src/window.c (update_net_wm_type): don't set window->type_atom - here so that the type-inference code will actually be called. Fix - for #126873 from Keith Packard. - -2003-11-08 Rob Adams - - * src/window.c (meta_window_move_resize_internal): configure frame - first if we grow more than we shrink combined in both dimensions. - Patch from Soren Sandmann for #108925. - -2003-11-07 Rob Adams - - * src/place.c (meta_window_place): use maximize_after_placement to - automaximize in meta_window_place; avoids a problem with not - recalculating the frame geometry after auto-maximizing. - -2003-11-07 Rob Adams - - * src/window.c (window_should_be_showing): show the window if it's - a transient of a dock or desktop, since otherwise such windows are - invisible in show desktop mode. Fix for #124648. - -2003-11-07 Rob Adams - - * src/main.c (main): Try harder to find a theme in the event that - the theme in the preference cannot be found. Patch from Marcin - Krzyzanowski. See #125815. - - * src/place.c (meta_window_place): use "visual" centering for - dialog placement and clip new dialogs to an xinerama workspace. - Fix for #118336. - -2003-10-30 Havoc Pennington - - * src/menu.c (meta_window_menu_new): patch to avoid creating - stick/unstick menu items when only one workspace, bug #116563 - from Michael Terry - -2003-10-25 Havoc Pennington - - * src/window.c (meta_window_notify_focus): if a window is focused - which is not either a dock or a transient in the same group as a - dock, shuffle all dock/desktop windows to the end of the MRU list - so they won't annoyingly get focus all the time. #123816 - -2003-10-15 Yukihiro Nakai - - Gettextize metacity-theme-viewer. #121747 - - * src/theme-viewer.c: gettextize. - * po/POTFILES.in: Add src/theme-viewer.c - -2003-10-13 Havoc Pennington - - In the "prefs cause code complexity" department, here's a "sloppy - focus die die die" kind of moment. - - * src/display.c (meta_display_grab_focus_window_button): don't - grab in sloppy focus mode, since we were dropping the grab on - window enter anyway this just removes races from the current - behavior. - - * src/display.c (prefs_changed_callback): ungrab/grab on focus - mode changes, since we treat sloppy and click differently. - -2003-10-12 Havoc Pennington - - Merge reduced_resources mode patch from the branch. Offers - wireframe and no-animations. - - * src/window.c (implement_showing): no animation if we are - in reduced resources mode - - * src/prefs.c: add REDUCED_RESOURCES pref - - * src/window.c (meta_window_update_keyboard_resize): fix to - modify grab_anchor_window_pos to grab_wireframe_rect if - appropriate instead of window->rect - - * src/display.h (struct _MetaDisplay): add grab_start_serial used - to avoid responding to events that occurred prior to the grab - initialization. - - Still broken in various ways, specifically EnterNotify that - occurred prior to XGrabPointer is processed as if it occurred - after. - - * src/window.c (meta_window_update_keyboard_move): add this - instead of meta_window_warp_pointer() crack - - * src/effects.c (meta_effects_update_wireframe): draw a kind of - grid for the wireframe, instead of just a rectangle, like twm - - * src/screen.c (meta_screen_new): line width of 3 for the XOR gc - - "Reduced resources" mode based on wireframe patch from - Erwann Chenede. Still pretty buggy. - - * src/keybindings.c (process_keyboard_move_grab) - (process_keyboard_resize_grab): add gruesome wireframe hacks - - * src/display.c (meta_display_end_grab_op): end wireframe - (meta_display_begin_grab_op): begin wireframe - - * src/effects.c (meta_effects_end_wireframe) - (meta_effects_update_wireframe, meta_effects_begin_wireframe): - routines to draw the wireframe stuff - - * src/window.c (window_should_be_showing): hide window when - doing wireframe, commented out as it breaks grab - * src/window.c (meta_window_refresh_resize_popup): handle wireframe - - * src/screen.c (meta_screen_new): create a screen->root_xor_gc - for use in drawing wireframes - - * src/frames.c (meta_frames_push_delay_exposes): repaint - everything before we delay - -2003-10-11 Havoc Pennington - - * src/display.c (meta_display_begin_grab_op): initialize - display->grab_have_pointer to FALSE, previously I think you could - get a case where we didn't have the grab and thought we did. - Bugs were reported with this happening. Of course we still have - the "why did the grab fail" problem, but it should be less - noticeable with this fixed. - -2003-10-06 Rob Adams - - * src/constraints.c (constraint_onscreen_*_func): disable onscreen - resize constraints for right, left, and bottom, since there is no - way to violate onscreen constraints by resizing in these - directions and the code to implement the constraints made some - incorrect assumptions. Fix for #120701, #120756, #123165, - #123631, #123838. - -2003-10-06 Žygimantas Beručka - - * configure.in: Added "lt" to ALL_LINGUAS - -2003-10-01 Havoc Pennington - - * NEWS: update - - * configure.in: 2.6.2 - -2003-09-30 Havoc Pennington - - * src/window.c (meta_window_queue_move_resize): add the moveresize - idle at META_PRIORITY_RESIZE so it runs before GTK does any - drawing, may fix bug #109211 (seems to for me) - - * src/ui.h (META_PRIORITY_RESIZE): add this between GTK - resize/redraw priorities - - * src/display.c (meta_display_queue_retheme_all_windows): remove - some debug spew from meta_warning - -2003-09-30 Havoc Pennington - - * src/testasyncgetprop.c: remove nonstandard header include, - #121870 - -2003-09-30 Havoc Pennington - - * src/tools/metacity-message.c (main): call - bind_textdomain_codeset(), fix from Yukihiro Nakai bug #121743 - -2003-07-28 Rached Ben Mustapha - - Fix bug #118428 - - * src/window.c (redraw_icon): Also redraw window icon if the window - is not mapped but its frame is. - (idle_update_icon): Unset the window->update_icon_queued flag. - -2003-09-29 Havoc Pennington - - * src/tabpopup.c (meta_ui_tab_popup_new): put a random cap on - number of characters in the title of each window, bug #109301 - -2003-09-29 Havoc Pennington - - * configure.in: put -lXext in Xrandr check, bug #115996 - -2003-09-29 Havoc Pennington - - * src/wm-tester/test-size-hints.c: a little program to test size - hints, for now just a 0x0 min size to verify bug #113320 - -2003-09-29 Havoc Pennington - - * src/async-getprop.c (async_get_property_handler): attempt to fix - this to return the data as an array of long even on 64-bit as with - XGetWindowProperty() breakage, bug #114035, credit to Gwenole - Beauchesne for tracking down. - -2003-09-29 Havoc Pennington - - * src/xprops.c (cvtINT16toInt): fix the 64-bit check not to use - macros from the X tree that don't get set - - * configure.in: check for sizes of various types - -2003-09-29 Havoc Pennington - - * src/delete.c (meta_window_delete): don't move the focus after - you click the close button on a window. bug #108706 - -2003-09-29 Havoc Pennington - - * src/main.c (find_accessibility_module): fix warnings (one was a - real bug) - - * src/ui.c (meta_gdk_pixbuf_get_from_pixmap): fix warning that - probably explains remaining crash on bug #116923. Jeez, need to - use -Werror here or something. - - Fix #103575, spawn child processes on proper screen. - - * src/keybindings.c (error_on_command): pass --screen to - metacity-dialog - (handle_run_command): launch user command with DISPLAY reflecting - the screen you launch it from - - * src/delete.c (delete_ping_timeout_func): pass --screen to - metacity-dialog - -2003-09-26 Havoc Pennington - - * src/display.c (event_callback): when focus on root window - becomes None, set it to something other than None so keybindings - keep working and print a warning about how some application sucks. - #84564 - (event_callback): Fix debug spew to print focus event details - properly - (meta_display_open): when setting initial focus, always use - RevertToPointerRoot and fix the focus if it's None or PointerRoot - -2003-09-26 Padraig O'Briain - - * src/Makefile.am: Add -DMETACITY_LIBDIR to support loading of modules - * src/main.c: Add functions find_accessibility_module, - accessibility_invoke_module and accessibility_invoke - (main); Check whether GConf accessibility key is true and if so - load accessibility modules. This code is based on the libgnome code. - - src/tabpopup.c (meta_ui_tab_popup_new): Set accessible role of - accessible for label containing window name to STATUSBAR so - AT can be aware of window name. - - This fixes bug #120025 - -2003-09-24 Havoc Pennington - - * src/session.c (io_from_warning_dialog): fix hang when we get - EOF, #121376 from Laurent Vivier - -2003-09-22 Taneem Ahmed - - * configure.in: Added "bn" to ALL_LINGUAS. - -2003-09-20 Åsmund Skjæveland - - * configure.in: Added Norwegian (nynorsk) translation code to - ALL_LINGUAS - -2003-09-20 Rob Adams - - Fix bug where multiple entries could appear in MRU lists, or no - entry when sticking/unsticking windows. Fix for #122016 - - * src/window.c (meta_window_stick): use window->screen->workspaces - instead of window->workspaces. - (meta_window_unstick): use window->screen->workspaces instead of - window->workspaces. - -2003-09-19 Rob Adams - - Fix a bug with partial-width panel struts caused by incorrect - computation of rectangle widths, and another when using different - screen resolutions on xineramas. See #122404. Also fix a crash - bug with the MRU list when sticking and unsticking windows. See - #120809. - - * src/constraints.c (get_outermost_onscreen_positions): Fix - off-by-one error with partial-width struts. - - * src/window.c (meta_window_update_struts): Fix off-by-one error - with partial-width struts. - (meta_window_stick): assign back to GList after g_list_append - (meta_window_unstick): assign back to GList after g_list_append - - * src/workspace.c (ensure_work_areas_validated): For right and - bottom struts, compute strut relative to root window and not to - xinerama edge in compliance with EWMH recommendations. - - -2003-09-17 Fatih Demir - - * configure.in: Added "ta" (Tamil) to the languages' list. - -Wed Sep 10 15:38:09 2003 Jonathan Blandford - - * configure.in: Rerelease 2.4.0.1 to fix glib-gettext problem. - -2003-09-08 Havoc Pennington - - * configure.in: remove "this is the unstable branch" warning - -2003-09-08 Havoc Pennington - - * configure.in: 2.6.0 - -2003-09-04 Havoc Pennington - - * configure.in: 2.5.5 - - * HACKING: add instructions on how to make a release - -2003-08-29 Rob Adams - - * src/ui.c (meta_gdk_pixbuf_get_from_pixmap): harden against null - return from gdk_pixmap_foreign_new. Fix for #116923. - -2003-08-26 Guntupalli Karunakar - - * configure.in: Added "hi" (Hindi) to ALL_LINGUAS. - -2003-08-20 Rob Adams - - Complete the transition to using the MRU window as the default - focus window instead of the topmost window; fixes a number of - problems with sloppy focus and utility windows. See #112031. - - * src/window.c (meta_window_free): call - meta_workspace_focus_mru_window - (meta_window_minimize): call meta_workspace_focus_mru_window - -2003-08-20 Rob Adams - - * src/constraints.c (meta_window_constrain): do northwest resize - when maximizing and fullscreening to avoid potential "off-by-one" - problems. - -2003-08-19 Rob Adams - - * src/stack.c (get_standalone_layer): put windows with - wm_state_below at the bottom. Make this higher priority than full - screen layer; see #120238. - -2003-08-18 Rob Adams - - * src/constraints.c (meta_window_constrain): recalculate frame - geometry if the window gets maximized after placement, since it's - likely to change. Fix for #120117. - -2003-08-17 Ray Strode - - * src/delete.c (meta_window_delete): Use MRU list to find focusing - window after a window is deleted instead of using top window. Fix - for #108643. - -2003-08-16 Havoc Pennington - - Patch from Soeren Sandmann #108926 to improve opaque resize - - * src/frame.c (meta_window_ensure_frame): new function - - * src/ui.c (meta_ui_create_frame_window): new function to create - a frame with GDK, so that GDK's invalidation etc. work properly - -2003-08-16 Havoc Pennington - - * src/display.c (xcursor_for_op): fix cursor for - META_GRAB_OP_MOVING, #111943 from John Paul Wallington - -2003-08-15 Rob Adams - - * src/constraints.c (meta_window_constrain): move to upper left - corner since we're resizing/moving instead of moving/resizing. - Fix for #119988. - -2003-08-15 Ray Strode - - Changed MRU list to be per workspace instead of per display, so - sticky windows don't hijack the window focus after workspace - switching (Bug #97635). - - * src/delete.c (meta_window_delete): Use - meta_workspace_focus_top_window instead of - meta_screen_focus_top_window. - - * src/display.c (meta_display_open): Stop using display->mru_list. - (find_tab_forward): - (find_tab_backward): - (meta_display_get_tab_list): Use workspace->mru_list instead of - display->mru_list and remove unneeded calls to - meta_window_visible_on_workspace - - * src/display.h: Remove mru_list from MetaDisplay - - * src/keybindings.c (handle_toggle_desktop): Use - meta_workspace_focus_top_window instead of - meta_screen_focus_top_window. - - * src/screen.c (meta_screen_focus_top_window): - (meta_screen_focus_default_window): Remove functions. - (meta_screen_show_desktop): Use meta_workspace_focus_top_window - instead of meta_screen_focus_top_window. - - * src/screen.h: Remove meta_screen_focus_top_window and - meta_screen_focus_default_window declarations. - - * src/window.c (meta_window_new): Stop using display->mru_list. - (meta_window_free): Use meta_workspace_focus_top_window - instead of meta_screen_focus_top_window and stop using - display->mru_list. - (meta_window_stick): Add sticky window to all workspace MRU lists. - (meta_window_unstick): Remove non-sticky window from the workspace - MRU lists it doesn't belong in. - (meta_window_notify_focus): Move newly focused window to the front - of active workspace's MRU list. - - * src/workspace.c (meta_workspace_new): Initialize - workspace->mru_list to NULL. - (meta_workspace_add_window): Add window to workspace's MRU list. - (meta_workspace_remove_window): Remove window from workspace's MRU - list. - (meta_workspace_activate_with_focus): Use - meta_workspace_focus_default_window instead of - meta_screen_focus_default_window. - (meta_workspace_focus_default_window): - (meta_workspace_focus_mru_window): - (meta_workspace_focus_top_window): Add functions. - - * src/workspace.h: Add mru_list to MetaWorkspace and add function - declarations for meta_workspace_focus_default_window, - meta_workspace_focus_mru_window, meta_workspace_focus_top_window. - -2003-08-14 Rob Adams - - Allow windows that are too tall for the workarea to break the - onscreen constraints just enough so that their bottom edges can be - made visible. Fix for #106740. Also, changes constraints to - constrain the resize and then the move to avoid complexities in - the code for the above fix. - - * src/constraints.c (get_outermost_onscreen_positions) - Compute the "effective" height of the work area and the minimum - size for the window to compute a value by which a window is - allowed to violate the top constraint. - (meta_window_constrain): convert to a resize then a move instead - of a move then resize. - -2003-08-13 Rob Adams - - * configure.in: remove metacity.spec from AC_OUTPUT - -2003-08-13 Havoc Pennington - - * metacity.spec.in: remove, nobody is maintaining it. - -2003-08-13 Laurent Dhima - - * configure.in: Added "sq" to ALL_LINGUAS. - -2003-08-10 Havoc Pennington - - * src/screen.c (meta_screen_new): don't select for button - press/release events, as that keeps other clients from doing so, - and it doesn't seem that metacity has any reason to do it. - Patch from Andreas Volz. - -2003-08-08 Bastien Nocera - - * src/metacity-dialog.c: (kill_window_question), - (warn_about_no_sm_support): fix markup being ignored when a window - title has a forbidden character in it (eg. "Send & Receive") - * src/tools/metacity-window-demo.c: fix warning - -2003-07-29 Arvind Samptur - - * src/xprops.c (utf8_list_from_results): Number of - strings we are processing is one more than required. - - Also get the string count right even without a null byte at the end. - Pointed out by Havoc. - -2003-07-27 Rob Adams - - * src/window.c (update_move): Update window shaking loose so that - the window is moved to the pointer and certain drag state is - properly restored once windows "reattach". Fix for #115000 based - on the patch by Jurg Billeter. - - * src/screen.c (meta_screen_resize): Invalidate work areas after - an xrandr screen size update. Fix for #117230. - - * src/stack.c (window_is_fullscreen_size): Check the bottom corner - of the window in addition to the top corner. Fix for #118194. - - * src/constraints.c (meta_window_constrain): Support aspect ratio - hints in the new constraints code. Fix for #113798. - - * src/tools/metacity-window-demo.c (toggle_aspect_ratio): toggle - the aspect ratio hints to force a 16:9 aspect ratio. - (do_appwindow): add a button to toggle aspect ratio. - -2003-07-27 Havoc Pennington - - * src/theme-viewer.c (run_theme_benchmark): also measure wall - clock time, and run over a number of window sizes. - -2003-07-15 Havoc Pennington - - * NEWS: update - - * configure.in: 2.5.3 - -2003-07-12 Pablo Saratxaga - - * configure.in: Added Walloon (wa) to ALL_LINGUAS - -2003-07-04 Havoc Pennington - - * Makefile.am (EXTRA_DIST): add rationales.txt - -2003-07-02 Jordi Mallach - - * src/metacity.desktop.in: Add X-GNOME-Bugzilla entries. - -2003-07-01 Padraig O'Briain - - * src/keybindings.c (process_tab_grab): Activate window before ending - grab. This fixes bug #114037. - -2003-06-20 Rob Adams - - * src/window.c (meta_window_unmaximize): Update grab state when we - unmaximize so double-clicking doesn't cause weird window-jumping - problems. See #116292. - -2003-06-29 Rob Adams - - * src/constraints.c (meta_window_constrain): Actually maximize - after placement. See #116285. - -2003-06-26 Havoc Pennington - - * src/workspace.c (meta_workspace_invalidate_work_area): nuke the - lists of struts here, to improve confidence that we never try to - use them after a window with rects in the list gets freed. - (it wasn't broken before I don't think, just making the - code more robust against future mods) - - * src/window.c (meta_window_update_struts): replace magic "75" - with a macro - - * src/constraints.c (constraint_hints_applies_func): don't apply - hints to maximized or fullscreen, rather than only fullscreen - (constrain_move): add paranoia max number of iterations to the - heuristic loop - -2003-06-26 Rob Adams - - Add keybinding to allow the user to toggle _NET_WM_STATE_ABOVE on - windows. Disabled by default. See #98387. - - * src/keybindings.c (handle_toggle_above): new function implements - the keybinding - - * src/metacity.schemas.in: add toggle_above keybinding - - * src/prefs.[ch]: add toggle_above keybinding - - * src/window.[ch] (meta_window_make_above): new function to put a - window into the above state - (meta_window_unmake_above): new function takes a window out of the - above state - -2003-06-26 Mohammad DAMT - - * po/id.po: Added Indonesian translation - * configure.in: Added "id" to ALL_LINGUAS - -2003-06-25 Rob Adams - - Update constraints code to support the new _NET_WM_STRUT_PARTIAL - EWMH draft specification. See #86682. Also, fix a bug involving - work area invalidation on metacity startup. Fix for #108497. - Finally, some minor fixes for full screen windows. - - * src/window.h: Add new MetaStruts structure to store strut rects - for a window. Remove has_struts and do_not_cover flag, and - support new MetaStruts instead of the four ints. - - * src/window.c (meta_window_new): change initialization to work - with new struts. Also, move meta_window_update_struts call to - after the workspaces are initialized to fix #108497. Remove - do_not_cover and related code. - (process_property_notify): add strut_partial - (update_struts): change function name to meta_window_update_struts - and expose in external MetaWindow API. Support partial width - struts and the new strut rects. - - * src/workspace.h: add new GSLists containing pointers to all - relevant struts for this workspace. - - * src/workspace.c (meta_workspace_new): initialize the list of - strut rects for this workspace. - (meta_workspace_free): free the strut rect lists - (ensure_work_areas_validated): support new struts and new strut - rect lists. Unleash the per-xinerama work areas. - - * src/constraints.c (get_outermost_onscreen_positions): Use the - current window position along with the new per-workspace strut - rects to compute the constraints that apply to a particular - window. - (constraint_hint_applies_func): don't do hints constraints on - fullscreen windows - (update_position_limits): for maximized windows use the work areas - to set the position limits; for other windows rely on the struts - constraints to be computed later in - get_outermost_onscreen_positions - (meta_window_constrain): don't apply aspect ratio hints to full - screen windows - - * src/display.c (meta_display_open): add _NET_WM_STRUT_PARTIAL atom - (meta_rectangle_equal): new helper function for MetaRectangles - (event_queue_callback): #ifndef out if USE_GDK_DISPLAY not set to - avoid compiler warning - - * src/display.h: add atom_net_wm_strut_partial, and add - meta_rectangle_equal. - - * src/screen.c (meta_screen_rect_intersects_xinerama): change - _window_intersects_ to _rect_intersects_ which is more useful now. - (meta_screen_resize_func): update struts on windows with struts - since struts are relative to the screen size, and this function is - called when the screen size updates. - - * src/screen.h (meta_screen_rect_intersects_xinerama): change - _window_intersects_ to _rect_intersects_ which is more useful now. - - * src/window-props.c (meta_display_init_window_prop_hooks): add - hook for strut_partial - - * src/tools/metacity-window-demo.c: Support partial-width struts - on the dock window tests for metacity testing purposes. - -2003-06-22 Samúel Jón Gunnarsson - - * configure.in: Added "is" to ALL_LINGUAS - -2003-06-12 Rob Adams - - * src/display.c (event_callback): Focus on mouse click in - sloppy/mouse to fix keynav. Fix for #115072. - -2003-06-12 Rob Adams - - * src/Makefile.am: honor --disable-schemas-install. Fix for - #106123 from Julio Merino - -2003-06-12 Rob Adams - - Remove legacy support for Gnome 1 hints, since we deem it unlikely - that anyone is running a current metacity with Gnome 1. The - removed hints are _WIN_WORKSPACE, _WIN_LAYER, _WIN_PROTOCOLS, - _WIN_SUPPORTING_WM_CHECK, and _WIN_HINTS. Thanks to Ben Jansens - for much of this patch. - - * display.c (meta_display_open): remove hints - - * display.h: remove atoms for hints - - * screen.c (set_wm_check_hint): don't set legacy hint - (set_supported_hint): don't set legacy hint - - * window-props.c (init_win_workspace): removed - (reload_win_workspace): removed - (meta_display_init_window_prop_hooks): remove hints - - * window.h: remove do_not_cover flag - - * window.c: remove GnomeWinHints enum - (recalc_do_not_cover_struts): removed - (meta_window_new): don't initialize removed flags or compute - legacy struts - (move_resize_cmp): removed - (idle_move_resize): Don't bother sorting the idle queue - (meta_window_client_message): don't set legacy hint - (process_property_notify): remove hints - (update_net_wm_type): don't fall back to WIN_LAYER hint - (update_struts): remove legacy struts - -2003-06-12 Havoc Pennington - - * src/display.c (event_callback): make raise-on-click explicitly - only happen in click to focus mode. - - * src/window.c (update_move): apply patch from Jurg Billeter to - allow you to "shake loose" maximized windows and move them between - Xinerama heads. #93586 - - * src/display.c: delete event_queue_callback - - * src/display.h (struct _MetaDisplay): get rid of - grab_current_window_pos and grab_current_root_[xy] as I could find - absolutely no code using them for anything. They were just sort of - randomly assigned to for no apparent reason. - - * src/display.c (event_callback): double-click timeout is per - screen, so get the screen and pass screen->ui to - meta_ui_get_double_click_timeout() - - * src/ui.c (meta_ui_get_double_click_timeout): take a MetaUI - argument so we get the right settings for each screen - (meta_ui_get_drag_threshold): new function - -2003-06-09 Rob Adams - - Revamp placement policy for windows that are maximized when they - are mapped, including windows that set a hint to be maximized or - windows that are auto-maximized using our heuristic. See #111902. - - * src/window.h: add new flag maximize_after_placement and new - function meta_window_maximize_internal. - - * src/window.c (meta_window_new): initialize - maximize_after_placement to FALSE and remove the automaximize - heuristic. - (meta_window_maximize_internal): new function accepts a saved_rect - argument to be used as the new saved_rect for the window, and does - not queue a move_resize. - (meta_window_maximize): re-implement using - meta_window_maximize_internal. - (update_net_wm_state): If a window has a maximize hint set on - startup set maximize_after_placement to TRUE - - * src/constraints.c (meta_window_constrain): Update the xinerama - information in the ConstraintInfo after placing the window, and - maximize the window after placement if - window->maximize_after_placement - - * src/place.c (find_first_fit): take a natural xinerama list as an - argument instead of generating it here - (constrain_placement): remove function, since it is no longer - needed - (meta_window_place): generate the natural xinerama list here and - pass it into find_first_fit. If find_first_fit fails, use the - list to find empty xineramas where we can place windows that may - be maximized later. This makes maximized windows follow the - correct placement policy. Move the automaximize heuristic here. - -2003-06-09 Rob Adams - - * src/metacity-dialog.c (warn_about_no_sm_support): install an - alarm to timeout the no-sm-dialog after 4 minutes of inactivity. - Patch from Ximian. See #114789. - -2003-06-07 Rob Adams - - * src/window.c (meta_window_new): call meta_group_compute_group - after setting window->desc to avoid SIGSEGV when verbose mode is - enabled. - -2003-06-07 Havoc Pennington - - * src/window.c (meta_window_notify_focus): drop the mouse button - grabs for the focused window; we'll see if this breaks anything. - It should fix #102209 - -Fri Jun 6 19:27:53 2003 Jonathan Blandford - - * src/metacity.schemas.in: fix the location of the schemas file. - -2003-06-04 Rob Adams - - * src/window.c (meta_window_new): don't be stupid and set - window->group = NULL after calling meta_window_compute_group. - - * src/group.c (meta_window_get_group): assert that window->group - != NULL in here instead of computing the group to ensure - robustness. - -2003-06-04 Rob Adams - - Precompute groups to guarantee that meta_group_list_windows always - returns the correct list of windows. See Bug #96973 - - * src/window.h: change cached_group variable to group - - * src/window.c (meta_window_new): change cached_group to group and - call meta_window_compute_group - - * src/groups.c (meta_window_get_group): simply return - window->group rather than computing it and returning - window->cached_group - (meta_window_compute_group): new function computes window->group. - Designed to be called once from meta_window_new - (remove_window_from_group): change cached_group to group - (meta_window_group_leader_changed): call meta_window_compute_group - instead of meta_window_get_group - -2003-05-29 Rob Adams - - Use a new property _METACITY_SENTINEL to eliminate a race - condition that causes focus to behave badly with sloppy/mouse - focus when lots of windows are mapped/unmapped, such as with a - workspace switch. The EnterNotify events on a display are ignored - until the PropertyNotify sent after all the window maps is - received. This is a fix for #110970. - - * src/display.[ch]: New _METACITY_SENTINEL atom. - (event_callback): ignore EnterNotify if the sentinel isn't clear, - and decrement the sentinel counter when the PropertyNotify is - received. - (meta_display_increment_focus_sentinel): new function. Increments - the sentinel counter and updates the property on a root window on - this display. - (meta_display_decrement_focus_sentinel): Decrement the sentinel - counter. - (meta_display_focus_sentinel_clear): returns whether the sentinel - counter is zero. - - * src/window.c (idle_calc_showing): after showing windows, call - meta_display_increment_focus_sentinel on each display for windows - to be shown. - - * src/workspace.[ch] (meta_workspace_activate_with_focus): new - function activates a workspace and focuses a particular window - after the workspace is activated. - (meta_workspace_activate): now just a wrapper for - meta_workspace_activate_with_focus - - * src/keybindings.c: use new meta_workspace_activate_with_focus - function to ensure that focus will follow the focused window - through the workspace switch. - -2003-05-29 Havoc Pennington - - * src/theme-parser.c (meta_theme_load): s/int/gsize/ for - g_file_get_contents() (found independently by - marcus@freebsd.org on SPARC and James Laska on s390x; - #113661 - - * src/main.c (main): fix theme location mentioned in error message - -2003-05-29 Ray Strode - - Get and use double-click speed from GtkSettings (Bug #103218). - - * src/ui.c, src/ui.h: - add function meta_ui_get_double_click_timeout for looking up - the global double-click speed. - - * src/display.c, src/display.h: remove double_click_time - field from MetaDisplay and use meta_ui_get_double_click_timeout - instead. - -2003-05-29 Rob Adams - - * src/main.c (main): chdir to the user's home directory on - startup. See #113755. - - * src/stack.c (get_standalone_layer): a window should be in the - fullscreen layer if it or any of its transient descendants are - focused or expecting the focus and it is either fullscreen or - fullscreen sized. Fix for #104369. - - * src/stack.c (is_focused_foreach): foreach used by - get_standalone_layer to find focused transient descendants. - -2003-05-20 Havoc Pennington - - * src/keybindings.c (meta_change_keygrab): the mask - display->ignored_modifier_mask wasn't being bound, - due to "<" instead of "<=" (most people didn't notice - as display->ignored_modifier_mask included Scroll_Lock). - Red Hat bugzilla #91301 reported by Youssef Makki - - * src/display.c (meta_change_button_grab): make corresponding - change for button grabs. - -2003-05-20 Havoc Pennington - - * NEWS: update - - * configure.in: 2.5.2 - -2003-05-20 Anders Carlsson - - * src/metacity-dialog.c: (kill_window_question): - Split up the strings to make life easier for translators. - -2003-05-20 Anders Carlsson - - * src/metacity-dialog.c: (kill_window_question): - Fix the wording and HIGify the dialog. - -2003-05-18 Havoc Pennington - - * src/window.c (unminimize_window_and_all_transient_parents): - revert broken change that assumed foreach_ancestor iterated - over the window itself. Andrew Sobala, Rob Adams, - #113232 - -2003-05-16 Rob Adams - - Flip the workspace when using up/down/left/right for move window - to, but not when specifying a workspace explicitly as in move to - workspace 4. Possible fix for #105492. - - * src/keybindings.c (do_handle_move_to_workspace): new function - moves a window to a workspace with the option to flip to that - workspace. - (handle_move_to_workspace): Use new do_handle_move_to_workspace - function without flipping (a keybinding) - (handle_move_to_workspace_flip): Use new - do_handle_move_to_workspace function with flipping (a keybinding) - -2003-05-16 Havoc Pennington - - * src/frames.c (meta_frames_paint_to_drawable): fix for - bug #104018 from David Santiago, change button state to - normal while it's being pressed if you move the mouse - outside it. Do this by tracking prelit_control for whether - to draw a button as active, not just for whether to draw - it as prelit. - (meta_frames_motion_notify_event): also update prelit_control - while clicking a button - -2003-05-16 Havoc Pennington - - * src/window.c (meta_window_new): fill in window->desc sooner - since we use it sooner now. - - * src/display.c (meta_display_open): init - display->grab_update_alarm - - * src/window.c (meta_window_new): initialize the always_sticky - field - (meta_window_new): initialize the update_icon_queued field - - Patch from Julien Olivier bug #92335 for converting "show desktop - mode" to "all windows are minimized" when you open a new window, - instead of just mapping all the windows again. - - * src/window.c (meta_window_activate): minimize all windows before - coming out of show desktop mode. - (meta_window_unminimize): don't toggle show desktop mode here - - * src/screen.c (meta_screen_minimize_all_except): new function - -2003-05-01 Havoc Pennington - - * src/theme-parser.c (meta_theme_load): fix memleak on error - -2003-05-16 Telsa Gwynne - - * configure.in: Added "cy" (Welsh) to ALL_LINGUAS. - -2003-05-06 Danilo Å egan - - * configure.in: Added "sr" and "sr@Latn" to ALL_LINGUAS. - -2003-05-03 Havoc Pennington - - * src/keybindings.c (handle_move_to_workspace): when moving - window to another workspace, don't switch to that workspace. - - * src/window.c (menu_callback): when moving window to another - workspace, don't switch to that workspace. - -2003-05-03 Havoc Pennington - - * configure.in: 2.5.1 - - * NEWS: update - -2003-05-01 Rob Adams - - * src/constraints.c (constraint_onscreen_applies_func): Don't - apply onscreen constraints to full screen windows. Fix for - #110048 - -2003-04-29 Havoc Pennington - - * src/bell.h: include Xlib.h before XKBlib.h which is required on - Solaris. #111877 from Peter O'Shea - -2003-04-23 Havoc Pennington - - * src/keybindings.c (process_keyboard_move_grab): support - diagonal keypad keybindings, from Dafydd Harries - -2003-04-21 Havoc Pennington - - * purge HAVE_GTK_MULTIHEAD from the source code, not just from - configure.in. Yes I am a loser. - -2003-04-19 Masahiro Sakai - - * configure.in: call AC_LIBTOOL_WIN32_DLL. - - * src/Makefile.am: add -no-undefined to libmetacity_private_la_LDFLAGS - and write dependency libraries in libmetacity_private_la_LIBADD. - -2003-04-06 Rob Adams - - * src/place.c (find_next_cascade): cascade on xinerama with - pointer instead of on first xinerama. - -2003-04-05 Rob Adams - - Update placement policy for screen with multiple xineramas. - Windows will be placed preferentially on the xinerama with the - pointer, and progressively further away as needed to find a place - where the window does not overlap other windows. - - * src/place.c (rect_fits_in_work_area): function - fit_rect_in_xinerama greatly simplified to work with new placement - policy. - (find_first_fit): implement new first fit placement scheme - - * src/screen.c (meta_screen_get_xinerama_neighbor): look for an - xinerama in the xinerama list that is adjacent to the specified - xinerama. - (meta_screen_get_natural_xinerama_list): return a list of - xineramas in the order to be preferred by the placement algorithm - as determined by the current location of the pointer. - - * src/screen.h: add function prototypes and an enum used by - meta_screen_get_xinerama_neighbor. - -2003-04-05 Rob Adams - - * src/place.c (center_tile_rect_in_area): Fix a minor off-by-one - error. See #110079. - -2003-03-30 Rob Adams - - * src/window.c (meta_window_move_resize_internal): When passing - frame geometry to meta_window_constrain, send null if no frame. - Possible fix for #109039. - -2003-03-29 Havoc Pennington - - * src/wm-tester/test-gravity.c (main): add --noframes option for - testing, showing how broken we currently are. - -Fri Mar 28 14:13:37 2003 Soeren Sandmann - - * src/window.c (update_resize): Only cap refresh rate when not - using SYNC. Remove bogus update-if-we-moved-more-than-a-delta. - - * src/window.c (update_move): Don't cap refresh rate during - moves. Remove bogus update-if-we-moved-more-than-a-delta. - -2003-03-26 Havoc Pennington - - * NEWS: update - - * configure.in: release 2.5.0 - -Sun Mar 23 23:04:06 2003 Soeren Sandmann - - * src/display.c (meta_spew_event): just return if we are not - verbose. - -2003-03-11 Havoc Pennington - - Should fix #108108, #106217, tracked down by Owen Taylor and - Frederic Crozat - - * src/window.c (meta_window_foreach_transient): change - MetaWindowForeachFunc to return a boolean for whether to continue - (meta_window_foreach_ancestor): new function - (window_should_be_showing): use meta_window_foreach_ancestor - (unminimize_window_and_all_transient_parents): ditto - (update_sm_hints): ditto - (meta_window_is_ancestor_of_transient): ditto - - * src/stack.c (get_maximum_layer_of_ancestor): use - meta_window_foreach_ancestor - -2003-03-16 Rob Adams - - * window.c (meta_window_show_menu): Free old window menu if it - already exists so we don't end up with more than one. Fix for - #108392. - -2003-03-14 Rob Adams - - * contraints.c (get_outermost_screen_positions): Don't try to - force a window onscreen by more than its width. Fix for #94815. - -2003-03-13 Rob Adams - - Make it so that the alt-tabbing won't try to go to a minimized - window by default. Fix for #107071. - - * display.c (meta_display_get_tab_list): use a GList instead of a - GSList - (meta_display_get_tab_next): use meta_display_get_tab_list to - decide what the next/previous tab window should be. - - * display.h (meta_display_get_tab_list): update function prototype - to return GList instead of GSList. - - * screen.c (meta_screen_ensure_tab_popup): update function to deal - with GList returned by meta_display_get_tab_list instead of GSList. - -2003-03-13 Christian Rose - - * configure.in: Added "ml" to ALL_LINGUAS. - -2003-03-11 Paul Duffy - - * configure.in: Added "ga" to ALL_LINGUAS - -2003-03-11 Rob Adams - - * src/constraints.c (meta_window_constrain): include left frame - geometry when maximizing or fullscreening windows. Fix for - #108127. - -2003-03-10 Roozbeh Pournader - - * configure.in: Added "fa" to ALL_LINGUAS. - -2003-02-27 Havoc Pennington - - Switch over to new constraints code, unquestionably introduces - some bugs, but should get us on the right path. - - * src/window.c (meta_window_get_work_area_all_xineramas): create - this function again as it turned out to be legitimate for window - position constraint - (adjust_for_gravity): use the width/height from the configure - request to compute the requested move - (meta_window_move_resize_internal): use meta_window_constrain - (update_size_hints): clamp max size to MAXSHORT to avoid worrying - about overflow stuff - - * src/constraints.c (meta_window_constrain): don't base placement - on uninitialized variables, general hacking - - * src/Makefile.am (metacity_SOURCES): add constraints.c, - constraints.h - - * src/constraints.c (meta_window_constrain): update the - cut-and-paste aspect ratio code to have latest bugfixes - -2003-03-08 Rob Adams - - * src/window-props.c (reload_normal_hints): Check that window min - and max size hints are at least 1. Fix for #107110. - -2003-02-27 Havoc Pennington - - Changes made on plane from FOSDEM, syncing from laptop. - - * src/main.c (main): add more debug spew about conditional - build stuff - (main): panic to "Simple" theme - - * src/window.c, src/window-props.c: move WM_NORMAL_HINTS and - WM_PROTOCOLS to new property system; don't queue move resize on - updating WM_PROTOCOLS; move WM_HINTS to new property system; - reload icon in an idle handler. - -2003-02-28 Mark McLoughlin - - Give me back my keys. - - * src/keybindings.c: (meta_window_grab_keys): don't - grab keys on DOCK windows. - - * src/window.c: (recalc_window_type): re-grab the - keys. - -2003-02-26 Dmitry G. Mastrukov - - * configure.in: Added Belarusian to ALL_LINGUAS. - -2003-02-26 Mark McLoughlin - - * src/keybindings.c: (handle_panel_keybinding): release - the keyboard grab before sending the action message to - the panel. - -2003-02-24 Mark McLoughlin - - Take control of the panel's global keybindings. The - screenshot utility is hooked up using a special case - run_command and the menu and run dialog bindings are - done using the _GNOME_PANEL_ACTION ClientMessage - protocol. - - * src/display.[ch]: (meta_display_open): add some atoms. - - * src/keybindings.c: - (handle_panel_keybinding): impl to handle a keybinding - by sending an action message to the panel. - - * src/metacity.schemas.in: add schemas for the panel and - screenshot keybindings and the screenshot commands. - - * src/prefs.[ch]: (update_command), - (meta_prefs_get_gconf_key_for_command): impl special case - handling for the screenshot commands. They are stored at - the the end of the commands array but have named keys. - -2003-02-23 Havoc Pennington - - Patch from Rob Adams addresses #95014 (placement issues), - makes first fit algorithm "center tile", adds most code - for per-xinerama workspaces (#86682) but disables it for now. - - * src/workspace.c (meta_workspace_get_work_area_for_xinerama) - (meta_workspace_get_work_area_all_xineramas): new xinerama - functions, maintain workspace->work_areas with a different - work area for each xinerama. However for now all the work - areas are the same, because haven't quite figured out how - _NET_WM_STRUT is supposed to work - - * src/window.c: adapt to new meta_window_* xinerama APIs - (meta_window_get_work_area_current_xinerama): new xinerama - API - (meta_window_get_work_area_for_xinerama): new xinerama API - (constrain_position): be a bit more clever about which xinerama's - work area we choose to use. - - * src/stack.c: adapt to new Xinerama API - - * src/screen.c (reload_xinerama_infos): invalidate all work areas - (meta_screen_get_xinerama_for_rect): new function - (meta_screen_window_intersects_xinerama): new function - - * src/place.c (find_first_fit): change to use - "center tiling" (center a screen full of tiled windows, - rather than aligning them top left). Adapt to new - xinerama functions. - -2003-02-22 Rob Adams - - * src/metacity.schemas.in: change toggle_maximized to - toggle_maximize and toggle_shaded to toggle_shade in - action_double_click_titlebar long description to match the values - used by metacity - - * po/*.po: change toggle_maximized to toggle_maximize and - toggle_shaded to toggle_shade in action_double_click_titlebar long - description to match the values used by metacity - -2003-02-22 Rob Adams - - * window.c (set_wm_state): modify comment to explain why the icon - window element is set to None. Fix for #97357 thanks to Gregory - Merchan. - -2003-02-22 Havoc Pennington - - * README: fix a typo, pointed out by Steve Kemp - -2003-02-22 Havoc Pennington - - * src/prefs.c (MAX_REASONABLE_WORKSPACES): change max workspaces - to 36 #81855 - -2003-02-22 Havoc Pennington - - * src/display.c (event_callback): fix to unfocus window only when - you leave the window frame, not when you leave the window itself, - unless window has no frame. #100248 fix from Orien Vandenbergh - -2003-02-22 Havoc Pennington - - * src/display.c (meta_display_get_tab_next): when tabbing - backward, we are still tabbing *from* the most recently used - window, not from the least recently used window. - - * src/keybindings.c (struct _MetaKeyBinding): make keycode - unsigned to match XEvent - - Patch for #84999 based on patch from Mark McLoughlin - - * src/prefs.c: add an add_shift field to MetaKeyPref to - add shift when grabbing the given keybinding. - - * src/keybindings.c (rebuild_screen_binding_table) - (rebuild_window_binding_table): refactor to share code, - and honor add_shift field in MetaKeyPref - -2003-02-20 Havoc Pennington - - * src/stack.c (create_constraints): don't create constraints - between windows on different screens, #106086 tracked down - by Arvind - -2003-02-14 Arvind Samptur - - * src/screen.c: (meta_screen_new) : Update the workspace - names from gconf and set the NET_DESKTOP_NAMES atom. - Renamed update_workspace_names() to set_workspace_names(). - Fixes #105498 - -2003-02-13 Havoc Pennington - - * configure.in: require GTK+ 2.2.0 - - * src/ui.c (meta_ui_init): remove hackaround for Pango X core - fonts backend - -2003-02-05 Abel Cheung - - * configure.in: Added "en_GB" and "nl" to ALL_LINGUAS. - -2003-02-05 Akira TAGOH - - * src/main.c (usage): fix a typo and missing option. (#105186) - -2003-02-04 Havoc Pennington - - * src/themes/Simple/ChangeLog: nuke subdir ChangeLog, - there can be only one true ChangeLog. - -2003-01-30 Havoc Pennington - - * src/keybindings.c (process_event): match handlers to key events - using key codes, not key syms - -Thu Jan 30 22:55:16 2003 Jonathan Blandford - - * src/themes/Makefile.am (THEMES): add Simple to the list of - themes. - - * src/metacity.schemas.in: change default theme to Simple. - -2003-01-29 Havoc Pennington - - * src/menu.c (meta_window_menu_new): don't create workspaces - menu items if only 1 workspace. Fix for #101952 from - Orien Vandenbergh - -2003-01-28 Bill Haneman - - * Re-instated visual-bell patch - (please see ChangeLog entry for 2002-12-16 for details). - - * src/prefs.c: - (visual_bell_type_from_string): - Accept a NULL string for 'visual-bell-type'. - -2003-01-25 Havoc Pennington - - * src/stack.c (window_is_fullscreen_size): When checking if a - window is fullscreen size, only require it to be at the origin - of the work area, not at the origin of the screen/xinerama. - Still require it to be full screen in width x height. - May fix xine in the case where the user has a top panel. - - * src/window.c (constrain_position): restore the ability for - undecorated windows to position themselves overlapping the top - panel, but don't let decorated windows do so. Oh the hacks... - -2003-01-08 Havoc Pennington - - * src/screen.c (meta_screen_apply_startup_properties): small code - snippet to fix startup sequences that set legacy class/name - -2003-01-22 Havoc Pennington - - * src/async-getprop.c (async_get_property_handler): do not read - sizeof(long) off the X connection. The X protocol does not vary - by architecture. Fixes longstanding hang on all 64-bit platforms. - -2003-01-22 Havoc Pennington - - * src/tools/Makefile.am: fix conditional so we get - metacity-properties.c in the distribution #103071 - -2003-01-22 Havoc Pennington - - * src/window.c (update_struts): be robust against the panel's - lame "set a negative number for struts" thing, even though - we'll also fix the panel. - -2003-01-21 Havoc Pennington - - Fix for the "mangles focus window when switching workspaces - and using mouse focus" bug - - * src/stack.c (meta_stack_get_default_focus_window_at_point): new - function - - * src/screen.c (meta_screen_focus_mouse_window): new function - (meta_screen_focus_default_window): new function - - * src/workspace.c (meta_workspace_activate): use the - new meta_screen_focus_default_window() - -2003-01-17 Havoc Pennington - - * src/window.c (meta_window_handle_mouse_grab_op_event): fix event - compression code to use GDK algorithm suggested by Owen, should be - more efficient. - -2003-01-22 Christian Rose - - * configure.in: Added "mn" to ALL_LINGUAS. - -2003-01-21 Havoc Pennington - - * src/display.c (event_callback): only hop window to the current - workspace if the window was previously minimized. Should keep - mozilla from popping windows over to your current workspace. - -2003-01-20 Havoc Pennington - - Attempt to fix #85916 - - * src/keybindings.c (primary_modifier_still_pressed): new function - (handle_workspace_switch): handle modifier release prior to - getting the grab - (do_choose_window): handle modifier release prior to getting the - grab - - * src/keybindings.c (grab_keyboard): properly return failure - if the GrabKeyboard doesn't work - -2003-01-19 Havoc Pennington - - * configure.in: add note about how this is the unstable branch, - set version to 2.5.0 - -2003-01-14 Havoc Pennington - - * src/window.c (meta_window_maximize, meta_window_unmaximize) - (meta_window_make_fullscreen, meta_window_unmake_fullscreen): - recalc_window_features() after making these changes, should fix - #103317 - -2003-01-14 Rob Adams - - * src/prefs.c: Increase the number of run_command bindings in - screen_bindings from 12 to 32. - - * src/prefs.h: Increase the number of META_KEYBINDING_COMMAND_N - macros from 12 to 32. - - * src/keybindings.c: Increase the number of run_command handlers - from 12 to 32. - -2003-01-11 Havoc Pennington - - * src/window.c (meta_window_handle_mouse_grab_op_event): implement - compression of motion events (drop all but the most recently - received), guessing at fixes for #103009 - -2003-01-11 Havoc Pennington - - * configure.in: add ability to --disable-shape - -2003-01-11 Akira TAGOH - - * configure.in: fix the behavior of --enable-*. - -2003-01-10 Havoc Pennington - - * src/Makefile.am (desktopfiles_in_files): revert that change, I - got the wrong .desktop file. doh. - -2003-01-10 Havoc Pennington - - * src/Makefile.am (desktopfiles_DATA): don't install .desktop file - for properties dialog if we aren't building/installing the - properties dialog. - -2003-01-10 Havoc Pennington - - * NEWS: update - - * configure.in: bump to 2.4.13, require 2.2.0 for multihead - -2003-01-09 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Use a line for the titlebar - text bg. - -2003-01-09 Havoc Pennington - - * src/window.c (recalc_window_features): argh, we were making all - dialogs skip taskbar; when did that get added. Fix to match - libwnck, only skip taskbar when the dialog is transient for some - other app window. - -2003-01-09 Havoc Pennington - - * src/metacity.schemas.in: change Windows+click back to Alt+click, - Windows+click just surprised everybody and didn't work half the - time. Maya users can configure it, and GTK DND can change its - default. - -2003-01-08 Havoc Pennington - - * src/metacity.schemas.in: assign Alt+F12 to shade window, - per #102658 - -2003-01-07 Havoc Pennington - - * src/screen.c (update_num_workspaces): fix off-by-one, patch from - readams@hmc.edu, #102806 - -2003-01-06 Arvind Samptur - - * src/window.c: (constrain_position) don't apply - offscreen height difference. This would get the - window under the panel on a resize or a move. - Fixes #102418 - -2003-01-05 Havoc Pennington - - * src/screen.c (meta_screen_calc_workspace_layout): invert - vertical_workspaces cases (we want to go down each column if - it's vertical, and across each row if horizontal). Patch - from readams@hmc.edu - -2003-01-05 Pablo Saratxaga - - * configure.in: Added Macedonian (mk) to ALL_LINGUAS - -2003-01-05 Havoc Pennington - - * src/frames.c (meta_frames_apply_shapes): put in the - HAVE_GTK_MULTIHEAD conditionals so we build with GTK 2.0 - -2003-01-05 Havoc Pennington - - * src/window.c (meta_window_show): focus new windows even in - mouse focus mode, #89981, patch from readams@hmc.edu - -2003-01-05 Havoc Pennington - - * src/workspace.c (meta_workspace_get_neighbor): redo using new - calc_workspace_layout to fix #98302 - - * src/util.c (topic_name): shorten default prefix - - * src/screen.c (meta_screen_calc_workspace_layout): enhance this - to handle all the funky layouts and calculate more information - than before - -2003-01-05 Pauli Virtanen - - * configure.in (ALL_LINGUAS): Added "fi" (Finnish). - -2003-01-05 Havoc Pennington - - * src/frames.c (meta_frames_apply_shapes): handle - the client having a shape mask, fixes #101806 - - * src/core.c (meta_core_get_client_xwindow): new function - - * src/frame.c, src/frame.h: keep a flag for whether we need to - update the frame shape - - * src/window.c (meta_window_new): select for ShapeNotify - - * src/display.h, src/display.c: actually query the shape - extension, instead of just using it all over the place. - - * src/prefs.c (update_application_based): don't let people turn on - application_based, as it just causes funky bugs. We can reenable - the pref when/if it ever does something useful. - -2003-01-03 Havoc Pennington - - * src/display.c: include the Xrandr header file - - * src/window.c (meta_window_fill_horizontal) - (meta_window_fill_vertical): maximize to work area, not entire - screen. doh. - -2002-12-19 Ross Burton - - * doc/metacity-theme.dtd: Fix a typo and loosen the requirements - for the resize element. - -2002-12-19 Havoc Pennington - - * Reverted visual bell patch, #99886 - -2002-12-19 Yanko Kaneti - - * configure.in: (ALL_LINGUAS) Added Bulgarian (bg). - -2002-12-18 Havoc Pennington - - * src/window.c (meta_window_new): select ColormapChangeMask - on toplevel windows, maybe a partial fix for #101478 - -Tue Dec 17 17:50:19 2002 HideToshi Tajima - - * src/themes/AgingGorilla/metacity-theme-1.xml: added support for - border only windows. #100984. - -2002-12-17 Havoc Pennington - - * src/display.c (meta_display_begin_grab_op): don't use "(null)" - for null pointers, use "none", so I can distinguish - glibc-generated (null) which is a bug. - (key_event_description): ditto - (meta_display_begin_grab_op): ditto - - * src/window.c (update_sm_hints): ditto - - * src/keybindings.c (reload_modmap): ditto - (meta_display_process_key_event): ditto - -2002-12-17 Havoc Pennington - - * src/metacity.schemas.in: s/focussed/focused/ - -2002-12-17 Havoc Pennington - - * src/xprops.c (validate_or_free_results): add a comma to message #101401 - -2002-12-16 Bill Haneman - - * configure.in: - Check for XKB extension. - - * src/Makefile.am: - Added bell.c and bell.h to metacity sources. - - * src/common.h: - (MetaFrameFlags): - Added META_FRAME_IS_FLASHING flag. - - * src/frame.h: - (MetaFrame): Added is_flashing field. - - * src/frame.c: - (meta_window_ensure_frame): - Initialize the is_flashing flag to FALSE. - (meta_frame_get_flags): - Handle the FRAME_IS_FLASHING flag. - (meta_window_destroy_frame): - Call meta_bell_notify_frame_destroy. - - * src/prefs.h: - (MetaPreference): - Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, - META_PREF_VISUAL_BELL_TYPE. - (MetaVisualBellType): New enum. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor declarations. - - * src/prefs.c: - (#includes): Include "display.h", since we now call - meta_displays_list() in our update func. - (#defines): - Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL, - and KEY_VISUAL_BELL_TYPE. - (provide_visual_bell, bell_is_audible, visual_bell_type): - New static state variables. - (update_visual_bell): New method to update visual-bell - boolean settings from keys "visual_bell" and "audible_bell". - (update_visual_bell_type): - New method to update visual-bell type setting. - (visual_bell_type_from_string) : - New method to convert from gconf string to visual-bell - type enum. Only currently recognized values are "fullscreen" - and "frame_flash". - (change_notify): - Handle changes to visual and audible bell properties. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor definitions. - (meta_prefs_init): Added a second call to notify_add, - listens to "/desktop/gnome/interface" as well as "apps/metacity". - Also call the update funcs for the new visual-bell gconf keys. - (meta_preference_to_string): - Handle the visual/audible bell cases. - - * src/bell.h: - (meta_bell_notify); - New method, calls a visual notifucation - method based on the visual-bell-type, or none if the type - is unrecognized or invalid. - (meta_bell_set_audible): - New public method for setting the audible bell setting, - used in updater for new gconf key "audible_bell". - (meta_bell_init): - Initialize the bell notification for a display. - (meta_bell_shutdown): - Shutdown the bell notification for a display. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification. - - * src/bell.c: - Include "bell.h", and conditionally include . - (meta_bell_set_audible): - If XKB is present, enable/disable the audible system - bell based on the gconf key /desktop/gnome/interface/audible_bell. - (meta_bell_init): - Query and initialize XKB if present, register for notification - on the bell, and set audible bell according to gconf settings. - (meta_bell_flash_screen): - Maps and unmaps a fullscreen X window (painted white, then - black), which causes a fullscreen 'flash' transient. - (meta_bell_flash_window_frame): - Flashes the titlebar of a specified window. - (meta_bell_flash_frame): - Calls meta_bell_flash_window_frame on the window which - was the source of the current bell event, or the currently - focussed window if the event source cannot be determined. - (meta_bell_unflash_frame): - Restore the frame's appearance to normal. - (meta_bell_flash_fullscreen): - Call meta_bell_flash_fullscreen for all screens. - (meta_bell_shutdown): - New method. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification, - testing for frame->is_flashing first. - - * src/display.h: - (MetaDisplay): Added xkb_base_event_type field. - - * src/display.c: - Check for XKB and include "X11/XKBlib.h" if present. - (meta_display_open): Call meta_bell_init. - (event_callback): Call meta_bell_notify - when event comes from XKB and is XkbBellNotify - (prefs_changed_callback): - Handle META_PREF_AUDIBLE_BELL notification. - - * src/screen.h: - (MetaScreen): Add flash_window field. - - * src/screen.c: - (meta_screen_new): - Initialize flash_window field. - - * src/theme.c: - (theme_get_style): - New heuristic for focus-style, to invert sense of focus - flag when META_FRAME_IS_FLASHING flag is set. - - * src/metacity.schemas.in: - Added scheme information for - /apps/metacity/general/visual_bell, - /apps/metacity/general/audible_bell, and - /apps/metacity/general/visual_bell_type. - -2002-12-16 Havoc Pennington - - * src/window-props.c (init_wm_name): argh, screwed that up. get - WM_NAME as VALUE_TEXT_PROPERTY #101383 - -2002-12-16 Bill Haneman - - * configure.in: - Check for XKB extension. - - * src/Makefile.am: - Added bell.c and bell.h to metacity sources. - - * src/common.h: - (MetaFrameFlags): - Added META_FRAME_IS_FLASHING flag. - - * src/frame.h: - (MetaFrame): Added is_flashing field. - - * src/frame.c: - (meta_window_ensure_frame): - Initialize the is_flashing flag to FALSE. - (meta_frame_get_flags): - Handle the FRAME_IS_FLASHING flag. - (meta_window_destroy_frame): - Call meta_bell_notify_frame_destroy. - - * src/prefs.h: - (MetaPreference): - Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL, - META_PREF_VISUAL_BELL_TYPE. - (MetaVisualBellType): New enum. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor declarations. - - * src/prefs.c: - (#includes): Include "display.h", since we now call - meta_displays_list() in our update func. - (#defines): - Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL, - and KEY_VISUAL_BELL_TYPE. - (provide_visual_bell, bell_is_audible, visual_bell_type): - New static state variables. - (update_visual_bell): New method to update visual-bell - boolean settings from keys "visual_bell" and "audible_bell". - (update_visual_bell_type): - New method to update visual-bell type setting. - (visual_bell_type_from_string) : - New method to convert from gconf string to visual-bell - type enum. Only currently recognized values are "fullscreen" - and "frame_flash". - (change_notify): - Handle changes to visual and audible bell properties. - (meta_prefs_get_visual_bell, meta_prefs_bell_is_audible): - (meta_prefs_get_visual_bell_type): - New accessor definitions. - (meta_prefs_init): Added a second call to notify_add, - listens to "/desktop/gnome/interface" as well as "apps/metacity". - Also call the update funcs for the new visual-bell gconf keys. - (meta_preference_to_string): - Handle the visual/audible bell cases. - - * src/bell.h: - (meta_bell_notify); - New method, calls a visual notifucation - method based on the visual-bell-type, or none if the type - is unrecognized or invalid. - (meta_bell_set_audible): - New public method for setting the audible bell setting, - used in updater for new gconf key "audible_bell". - (meta_bell_init): - Initialize the bell notification for a display. - (meta_bell_shutdown): - Shutdown the bell notification for a display. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification. - - * src/bell.c: - Include "bell.h", and conditionally include . - (meta_bell_set_audible): - If XKB is present, enable/disable the audible system - bell based on the gconf key /desktop/gnome/interface/audible_bell. - (meta_bell_init): - Query and initialize XKB if present, register for notification - on the bell, and set audible bell according to gconf settings. - (meta_bell_flash_screen): - Maps and unmaps a fullscreen X window (painted white, then - black), which causes a fullscreen 'flash' transient. - (meta_bell_flash_window_frame): - Flashes the titlebar of a specified window. - (meta_bell_flash_frame): - Calls meta_bell_flash_window_frame on the window which - was the source of the current bell event, or the currently - focussed window if the event source cannot be determined. - (meta_bell_unflash_frame): - Restore the frame's appearance to normal. - (meta_bell_flash_fullscreen): - Call meta_bell_flash_fullscreen for all screens. - (meta_bell_shutdown): - New method. - (meta_bell_notify_frame_destroy): - Remove pending idle handlers on notification, - testing for frame->is_flashing first. - - * src/display.h: - (MetaDisplay): Added xkb_base_event_type field. - - * src/display.c: - Check for XKB and include "X11/XKBlib.h" if present. - (meta_display_open): Call meta_bell_init. - (event_callback): Call meta_bell_notify - when event comes from XKB and is XkbBellNotify - (prefs_changed_callback): - Handle META_PREF_AUDIBLE_BELL notification. - - * src/screen.h: - (MetaScreen): Add flash_window field. - - * src/screen.c: - (meta_screen_new): - Initialize flash_window field. - - * src/theme.c: - (theme_get_style): - New heuristic for focus-style, to invert sense of focus - flag when META_FRAME_IS_FLASHING flag is set. - - * src/metacity.schemas.in: - Added scheme information for - /apps/metacity/general/visual_bell, - /apps/metacity/general/audible_bell, and - /apps/metacity/general/visual_bell_type. - -2002-12-16 Havoc Pennington - - * src/window-props.c: use META_PROP_VALUE_STRING_AS_UTF8 so - we convert old Latin-1 WM_NAME to UTF-8 - - * src/xprops.h (enum): add META_PROP_VALUE_STRING_AS_UTF8 to get a - latin1 string then convert. - -2002-12-15 Havoc Pennington - - * src/window.c (meta_window_new): get window name before anything - else. - - * src/xprops.c (validate_or_free_results): instead of suggesting - how to get window title etc. with xprop, just print out the - window title. much better. - -2002-12-15 Havoc Pennington - - * src/xprops.c (validate_or_free_results): make the warning about - strange property contents blame the application and explain how to - use xprop to diagnose which app is causing the problem. - -2002-12-15 Havoc Pennington - - * src/prefs.c (meta_prefs_change_workspace_name): don't pass NULL - string to gconf_client_set_string #101237 - -2002-12-13 Havoc Pennington - - * src/tools/Makefile.am (Desktop_in_files): only install .desktop - file for metacity-properties if we actually install - metacity-properties - - * src/display.c (event_callback): not focusing on button 2 click - was crack, revert that change. - -2002-12-09 Havoc Pennington - - * AUTHORS: add myself here, bug #100789 - - * src/display.c (meta_display_set_grab_op_cursor): drop - PointerMotionHintMask - - * src/window.c (meta_window_handle_mouse_grab_op_event): don't use - XQueryPointer, as we aren't using PointerMotionHint now - - * src/display.c (event_callback): rearrange a bit of code - for slight speedup and clarity - - * src/window.c (update_resize) - (meta_window_handle_mouse_grab_op_event): implement - usage of the _METACITY_UPDATE_COUNTER - (meta_window_handle_mouse_grab_op_event): fix code that - used event->xbutton with a motion event - - * src/display.c (meta_display_open): add new atoms, and - initialize Xsync if we have it - (grab_op_is_resizing): new function - (meta_display_begin_grab_op): create an alarm monitoring - window's _METACITY_UPDATE_COUNTER - (meta_spew_event): conditionalize this on WITH_VERBOSE_MODE - and print alarm events. - - * src/window.c (meta_window_new): fetch _METACITY_UPDATE_COUNTER - - * configure.in (HAVE_XSYNC): check for Xsync extension - -Mon Dec 9 22:09:56 2002 Soeren Sandmann - - * src/display.c, src/window.c: Handle crossing events during - resizing. (#93384). - -2002-12-09 Havoc Pennington - - * configure.in: 2.4.8 - -2002-12-08 Havoc Pennington - - * README: updates - - * src/window.c (MAX_RESIZES_PER_SECOND): change to 20 instead of - 30, just as an experiment. - (MOVE_THRESHOLD): change 15 to 20 - (RESIZE_THRESHOLD): change 15 to 20 - - * src/util.c (ensure_logfile): kill this function when verbose - mode is disabled. - -2002-12-08 Havoc Pennington - - * src/window.c (meta_window_fill_vertical) - (meta_window_fill_horizontal): new functions to resize to - fill screen - - * src/keybindings.c: add vert, horiz maximize - - * src/prefs.c: had vert, horiz maximize - - * src/metacity.schemas.in: shorten some overlong short - descriptions that make the keybindings capplet look ugly. - Add maximize_vertically, maximize_horizontally keys. - -2002-12-08 Havoc Pennington - - * src/prefs.c (meta_prefs_get_application_based): make this always - return FALSE for now, to avoid bug reports. - - * src/util.c (ensure_logfile): put "opened log file" message on - stderr so it will normally land in ~/.xsession-errors - - * configure.in: remove extra AC_ARG_PROGRAM - - * src/display.c (event_callback): handle the toggle-verbose message - - * src/tools/metacity-message.c: add a toggle-verbose message, been - meaning to do this for a while. - - * src/util.c (meta_set_verbose): if verbose mode is enabled and we - don't support it, then exit. - - * src/prefs.c: allow building without gconf (currently means some - prefs are no-ops) - - * src/util.c, src/util.h: support defining macros to - kill all verbose output entirely. (Removes the code and strings - associated with it) - - * configure.in: don't get METACITY_PROPS_LIBS if not building the - config dialog. - (HAVE_GCONF): allow building sans gconf, if you are size-sensitive - and not using gnome. - (WITH_VERBOSE_MODE): add ability to disable all the verbose debug - spew strings, to shrink the binary. - (--disable-sm): allow SM support to be forced on or off - (--disable-startup-notification): allow forcing this on or off - -2002-12-08 Havoc Pennington - - * src/prefs.c (update_workspace_name): also treat empty string as - "unset" in this function. - -Thu Dec 5 18:41:02 2002 HideToshi Tajima - - * src/window.h (META_WINDOW_IN_NORMAL_TAB_CHAIN, - META_WINDOW_IN_DOCK_TAB_CHAIN) : never use a window with input = - FALSE take_focus = FALSE in the normal and dock tab chains. #90409 - -Thu Dec 5 13:56:52 2002 HideToshi Tajima - - * src/display.c (event_callback): move a window to the current - space on the MapRequest when it's not on the space yet. #100390 - -2002-12-01 Havoc Pennington - - * src/frames.c (get_control): rearrange this function a bit, so - that we return CONTROL_TITLE for anything above the bottom of the - titlebar, in the fallback case where no other control was found. - Also, don't return RESIZE_N for title rect above the top resize - size, unless the window is resizable. - (meta_frames_button_press_event): only start a move when clicking - control TITLE, not control NONE. This way you don't start moving - a nonresizable window if you click its edges. - -2002-12-01 Havoc Pennington - - * src/tools/Makefile.am: conditionalize building the config dialog - - * configure.in (BUILD_CONFIG_DIALOG): add --enable-config-dialog - option to turn on the "window focus" dialog. This is part of - deprecating this dialog. - -2002-11-30 Havoc Pennington - - * src/screen.c (STARTUP_TIMEOUT): lengthen to 15 seconds - - * src/util.c (utf8_fputs): hmm, return a value - - * src/screen.c (meta_screen_apply_startup_properties): new - function to apply initial workspace based on startup sequence. - - * src/window.c (meta_window_new): load _NET_STARTUP_ID - (meta_window_get_startup_id): new function - - * src/window-props.c (meta_display_init_window_prop_hooks): add - hooks for _NET_STARTUP_ID - - * src/display.c (event_callback): send property events to - groups. - - * src/xprops.c (meta_prop_get_values): make a type of INVALID - mean to ignore that property (don't fetch its value). - - * src/group.c (meta_group_property_notify): new function - - * src/screen.c (set_supported_hint): support _NET_STARTUP_ID - - * src/display.c (meta_display_open): add _NET_STARTUP_ID to atoms - we initialize - - * src/group-private.h: private header shared between - group-props.c, group.c - - * src/group-props.h, src/group-props.c: new files to contain - functions for retrieving group properties - - * src/window.c (meta_window_same_application): change this a bit - to work with new definition of group - - * src/group.c (meta_window_get_group): always create a group for - every window, using the window's own ID as group leader if - required. - - * src/window.c (update_wm_hints): handle changes to group leader - - * src/group.c (meta_window_group_leader_changed): new function - - * src/display.h (struct _MetaDisplay): _NET_WM_WINDOW_TYPE_SPLASH, - not SPLASHSCREEN. Reported by Gregory Merchan and Matthias Clasen. - - * src/screen.c (startup_sequence_timeout): when timing out a - startup sequence, send a remove message, don't just time it out - locally. - -2002-11-26 Calum Benson - - * src/themes/Crux : - - Removed alpha layers from the pixmaps that don't need them. - Fixes #98389, results in 10-15% speedup on most machines. - -2002-11-26 Glynn Foster - - * configure.in: 2.4.5 - -2002-11-23 Dan Mills - - * Makefile.am: remove theme-format.txt, it's now in doc/. - -2002-11-22 Havoc Pennington - - * src/window.c (meta_window_change_workspace): patch from - Hidetoshi Tajima to move a window's transients when moving - the window between workspaces. #98900 - -2002-11-21 Havoc Pennington - - * src/display.c (meta_display_open): init ret_to to - RevertToPointerRoot out of sheer paranoia; don't want no - RevertToNone in my code! - -2002-11-21 Havoc Pennington - - * src/window.c (update_initial_workspace): delete - (meta_window_new): add getting initial workspace to the batch - property get call - - * src/window-props.c (meta_display_init_window_prop_hooks): add - net_wm_desktop and win_workspace support - -2002-11-20 Havoc Pennington - - * src/window-props.c (set_icon_title): remove unused variable - - * src/screen.c (meta_screen_new): read an existing - _NET_CURRENT_DESKTOP and restore it if set. Makes a restart even - less visible. - - * src/workspace.c (set_active_space_hint): don't set the hint - during the process of unmanaging a screen - -2002-11-20 Havoc Pennington - - * configure.in: add doc/Makefile - - * doc/metacity-theme.dtd: add DTD for themes from Ross Burton - - * doc/Makefile.am: doc subdir - - * doc/theme-format.txt: move to doc subdir - -2002-11-19 Havoc Pennington - - Should really fix #98303 - - * src/prefs.c (meta_prefs_change_workspace_name): add - bad hack to treat empty string the same as null - - * src/menu.c (get_workspace_name_with_accel): allocate one more - than the length of "name" so we have room for a nul byte (and - don't malloc(0) on empty strings). Also some formatting cleanups. - -2002-11-19 Havoc Pennington - - * src/window.c (meta_window_client_message): do a - recalc_window_features after setting new wm_state in order - to update skip_pager in addition to wm_state_skip_pager - (set_net_wm_state): base _NET_WM_STATE on skip_pager not - wm_state_skip_pager, ditto for skip_taskbar - -2002-11-19 Havoc Pennington - - Fix #98303 and assorted cleanup - - * src/prefs.c (meta_preference_to_string): handle - META_PREF_WORKSPACE_NAMES - - * src/menu.c (get_workspace_name_with_accel): assert that the - workspace has a name - - * src/screen.c (meta_screen_ensure_workspace_popup): assert that - we got a workspace name - (meta_screen_ensure_workspace_popup): assert that we got a - workspace name - - * src/prefs.c (update_workspace_name): fix screwiness (strcmp with - a freed string, assorted bad logic) - (init_workspace_names): assert that we filled in a default - workspace name - (meta_prefs_get_workspace_name): assert non-NULL workspace name - -2002-11-16 Bill Haneman - - * src/themes/Atlanta/metacity-theme-1.xml: - Changed outer bevel and focus line color to - work better with inverse themes (no effect on - Default or other existing gtk+ themes). - -2002-11-13 Havoc Pennington - - * src/ui.c (get_cmap): fix a multihead safety thing (use proper - system colormap for the drawable's screen) - -Thu Nov 14 17:30:10 2002 Jonathan Blandford - - * src/Makefile.am (libmetacityinclude_HEADERS): include common.h. - -2002-11-12 Havoc Pennington - - * src/theme.c (draw_op_as_pixbuf): don't read from op->data.image - when the op is an icon - -2002-11-12 Havoc Pennington - - * src/stack.c (meta_stack_get_default_focus_window): never use a - window with input = FALSE take_focus = FALSE as the default focus - window #95454 fix from Hidetoshi Tajima - -2002-11-10 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Major changes - to look of theme. I'd also recommend "minimize,maximize:close" - for the button_layout, it looks really slick :-). - -2002-11-08 Mark McLoughlin - - * src/workspace.c: - (meta_motion_direction_to_string), - (meta_screen_corner_to_string): impl for nice debugging. - (meta_workspace_get_neighbor): fix broken logic and - cleanup debugging. - -Thu Nov 7 17:07:21 2002 Jonathan Blandford - - * src/libmetacity-private.pc.in: add a pc file for - libmetacity-private - - * src/Makefile.am: Install a few files as a shared library so that - others can draw metacity themes. - -2002-11-06 Havoc Pennington - - * src/keybindings.c (grab_keys): push an error trap around the - whole window-key-grab loop - (ungrab_all_keys): avoid requiring return value from the error - trap, unless in debugging mode - (regrab_window_bindings, regrab_screen_bindings): push traps - around the loops, for efficiency - - * src/display.c (event_callback): fix from Padraig O'Briain to - compress extra MappingNotify events to avoid extra work. - -2002-11-05 Calum Benson - - * src/themes/Crux/active-restore-button.png: - * src/themes/Crux/inactive-restore-button.png: - * src/themes/Crux/metacity-theme-1.xml: add a restore button - for maximized windows, and un-hard-code titlebar text colors. - Fixes #97759. - -2002-11-05 Havoc Pennington - - * src/workspace.c (meta_workspace_get_neighbor): apply patch from - Nikos Mouat to fix this function - -2002-11-04 Havoc Pennington - - * src/theme.c (scale_and_alpha_pixbuf): fix bug I introduced in - case where scaling was done in both directions. - -2002-11-04 Havoc Pennington - - Patch from Brian Cameron to implement the vertical/horizontal - striped image accelerated scaling from the gtk pixbuf engine. - - * src/theme.c (scale_and_alpha_pixbuf): if an image is - vertical/horizontal stripes, use special extra-fast scaling - routines. - - * src/theme-parser.c (parse_draw_op_element): when loading an - image, mark it as vertically/horizontally striped when appropriate - -2002-11-04 Erwann Chenede - - - * src/xprops.c (meta_prop_get_values): changed __FUNCTION__ - to G_GNUC_FUNCTION as __FUNCTION__ is not portable. - -2002-11-03 Havoc Pennington - - * src/display.c (meta_display_grab): remove XSync calls from here - (meta_display_ungrab): remove XSync from here, but put in - an XFlush to be sure we get the ungrab sent. - - * src/util.c (meta_topic): track sync count here - - * src/errors.c: move sync count out of here - - Throughout: error spew on all XSync() calls - - * src/run-metacity.sh: don't set METACITY_DEBUG - -2002-11-03 Havoc Pennington - - * src/window-props.c (meta_display_init_window_prop_hooks): add - _NET_WM_NAME, WM_NAME, _NET_WM_ICON_NAME, WM_ICON_NAME support - - * src/window.c (meta_window_new): use window-props.h for - _NET_WM_NAME, WM_NAME, _NET_WM_ICON_NAME, WM_ICON_NAME - -2002-11-03 Havoc Pennington - - * src/window.c (meta_window_new): use window-props.h stuff for a - couple of properties - (implement_showing): fix printf string - - * src/xprops.c (meta_prop_free_values): new function - - * src/window-props.h, src/window-props.c: start moving code that - handles loading window properties into this file. - -2002-11-03 Havoc Pennington - - * src/stack.c (create_constraints): filter out windows that aren't - in the stack for whatever reason, avoids a crash - -2002-11-03 Havoc Pennington - - * src/window.c (meta_window_calc_showing): split into "see if we - should be showing" and "actually show/hide" functions - (idle_calc_showing): rework to first unmap all newly-hidden - windows from bottom to top then map all newly-showing windows from - top to bottom resulting in fewer exposes, #95220 - -2002-11-03 Havoc Pennington - - * src/theme.c (meta_frame_layout_calc_geometry): fix from Garrett - LeSage for which button backgrounds we draw when - -2002-11-03 Havoc Pennington - - * src/workspace.c (meta_workspace_get_name): new function, - and remove workspace->name field, instead just get the - name from prefs each time - - * src/screen.c (meta_screen_update_workspace_names): update the - gconf key to persist workspace names here, instead of changing - the names we use - - * src/util.c (topic_name): add META_DEBUG_PREFS - - * src/prefs.c: change NUM_COMMANDS to 32 to allow more custom - commands, implement workspace names - - * src/metacity.schemas.in: add workspace_names/name_NN gconf keys. - -2002-11-01 Christian Neumair - - * configure.in: We want at least autoconf 2.5. - -2002-10-29 Havoc Pennington - - * configure.in: 2.4.3, why not - -2002-10-28 Havoc Pennington - - * src/window.c (update_size_hints): use meta_prop_get_size_hints - - * src/xprops.c: add support for getting XSizeHints - -2002-10-28 Havoc Pennington - - * src/window.c, src/display.c: store the window menu on the - display and blow it away when a window closes, so we don't - get funny stuck menus. Patch from Martin Garton #87514 - -2002-10-27 Anders Carlsson - - * configure.in: Make XRandr detection work better. - -2002-10-27 Havoc Pennington - - * src/window.c (meta_window_free): move - meta_window_shutdown_group() much earlier in the destroy process. - May fix #96928 tracked down by Kjartan Maraas and Martin Garton. - - * src/group.c (meta_window_get_group): never add window to a group - after we've started unmanaging the window - -2002-10-26 Havoc Pennington - - * src/iconcache.c: include config.h - - * src/group.c: include config.h - - * src/frame.c: include config.h - - * src/core.c: include config.h so it doesn't crash all over the - place due to #ifdef HAVE_STARTUP_NOTIFICATION - - * src/util.c (meta_print_backtrace): export from this file - - * src/main.c (log_handler): print backtrace here - -2002-10-26 Havoc Pennington - - * src/wm-tester/main.c (evil_timeout): make windows randomly - transient for each other http://bugzilla.gnome.org/show_bug.cgi?id=96928 - -2002-10-26 Havoc Pennington - - * src/xprops.c (meta_prop_get_text_property): new function - (meta_prop_get_wm_hints): new function - (meta_prop_get_class_hint): new function - -2002-10-26 Havoc Pennington - - * src/window.c (meta_window_new): use multi-value-get on a couple - of properties for testing - - * src/xprops.c (meta_prop_get_values): implement multi-value-get - - * src/window.c (update_mwm_hints): XFree motif hints as we changed - it to use Xmalloc - - * src/xprops.c: massively rework this to set up a - get-multiple-properties-at-once API. - - * src/async-getprop.c (ag_Xmalloc): new function - -2002-10-25 Havoc Pennington - - Add "busy cursor on app startup" support, conditionally - works - only if libstartup-notification is found, and in practice requires - a GTK patch that's not in yet. - - * src/screen.c: monitor startup events and set busy cursor if - appropriate - - * src/display.c (meta_display_open): create SnDisplay - - * configure.in: check for startup notification, - and add the cute "configure summary" at the end - -2002-10-24 Havoc Pennington - - * src/theme.c (meta_frame_layout_calc_geometry): if only one - right-corner button, use right_right_background not - right_left_background - -2002-10-24 Havoc Pennington - - * src/window.c (meta_window_get_icon_geometry): make public - - * src/screen.c (meta_screen_ensure_tab_popup): put the alt+tab - highlight-window indicator on the icon, not the window itself, - if the window is minimized. - -2002-10-24 Havoc Pennington - - * src/display.c (meta_display_get_tab_list): put minimized windows - at the end of Alt+Tab, #89416 - -2002-10-23 Havoc Pennington - - * src/theme.c (meta_frame_layout_calc_geometry): initialize the - left button background rectangles. - -2002-10-21 Havoc Pennington - - Optimizations for managing new windows (do not all take effect if - METACITY_DEBUG=1). Bug #96404 - - * src/keybindings.c (meta_change_keygrab): use error trap nesting - and conditionalize on meta_is_verbose() to avoid a ton of XSync - - * src/display.c (meta_change_button_grab): ditto - - Throughout: move to new error trap setup to save on XSync calls, - new setup is: - - * src/errors.c (meta_error_trap_push_with_return): new function, - an error trap that needs to care about return value and thus - sync even if an outer trap still exists - (meta_error_trap_pop_with_return): new function - (meta_error_trap_pop): add "last_request_was_roundtrip" - argument allowing us to avoid XSync() if we just did - a GetProperty or whatever. - - * src/util.c (meta_warning): flush the warning file descriptor - - * src/Makefile.am (INCLUDES): define G_LOG_DOMAIN - -2002-10-20 Havoc Pennington - - * src/ui.c (meta_image_window_new): put multihead stuff in - HAVE_GTK_MULTIHEAD, reported by John Palmieri - -2002-10-20 Havoc Pennington - - * src/keybindings.c (handle_raise_or_lower): check above->mapped - before deciding if it overlaps the window being raiselowered, - fix from Stephane Chauveau - -2002-10-19 Jeremy Katz - - * configure.in: make Xrandr check less noisy - -2002-10-18 Havoc Pennington - - * src/effects.c (meta_effects_draw_box_animation): call - meta_image_window_new in multihead-safe way - - * src/ui.c (meta_image_window_new): multihead safety - -2002-10-18 Havoc Pennington - - * src/window.c (meta_window_refresh_resize_popup): only create the - resize popup if width_inc or height_inc are > 1 - - * src/resizepopup.c: Clear out all the weird tickmark cruft, - saves us about 2.5K of binary size, whee - (meta_ui_resize_popup_new): take display/screen arguments and make - multihead-safe #94349 - -2002-10-18 Havoc Pennington - - * src/keybindings.c (do_choose_window): don't start the cycle - process if the binding for switching windows has no modifier bits, - just focus the window immediately. - - * src/prefs.c, src/keybindings.c: add a keybinding to move between - windows that goes in the opposite direction. This is mostly - useful if you want to bind unmodified keys to the switch windows - functions, e.g. if you have "Forward" and "Back" keys on your - keyboard. Patch from Shilad Sen - -2002-10-18 Havoc Pennington - - * src/prefs.c, src/frames.c: add "what happens when you double - click the titlebar" setting, patch from Sean Middleditch bug - #95625. This is basically an "add Windows emulation mode" patch. - -2002-10-18 Havoc Pennington - - * src/metacity.schemas.in: move window-click to Super+click not - Alt+click by default. Super should be the Windows key on keyboards - that have one and are so configured. Prepare for the FAQ on this. - -2002-10-18 Havoc Pennington - - * src/window.c (constrain_size): fix min aspect handling, - patch from Martin Garton #94943 - -2002-10-18 Andras Timar - - * configure.in: Added hu to ALL_LINGUAS. - -2002-10-18 Havoc Pennington - - * src/stack.c (constrain_stacking): replace the old - apply_constraints with wacky new approach involving graphing all - the constraints then walking the graph. Fixes #94876 and probably - other stacking bugs as well, thanks to Arvind for tracking down - the issue. - - (compute_layer): add FIXME and reference to bug #96140 - -2002-10-17 Havoc Pennington - - * src/stack.c (apply_constraints): don't place - transient-for-whole-group windows above _each other_, only - above other windows in the group that aren't themselves - transient-for-whole-group. Should help with part of #94876 - -2002-10-17 Havoc Pennington - - * src/stack.c (apply_constraints): fix memory leak of - group_windows, and don't use the variable name "tmp" twice. Shadow - variables bad. - -2002-10-17 Havoc Pennington - - * src/tools/metacity-window-demo.c (dialog_cb): add code to create - big stacks of dialogs transient for each other, for testing. - -2002-10-16 Havoc Pennington - - * src/workspace.c: workspaces are all per-screen now, fix - accordingly - - * src/core.c: fix multihead workspace stuff - - * src/keybindings.c: multihead-rama - - * src/screen.c (meta_screen_show_desktop): new functions to - replace display equivalents - - * src/display.c (meta_display_get_workspace_by_screen_index): get - rid of this - (meta_display_get_workspace_by_index): get rid of this - (event_callback): handle _NET_SHOWING_DESKTOP message per-screen - - * src/screen.c (meta_screen_get_workspace_by_index): new function - - * src/screen.h (struct _MetaScreen): move workspace list, and - showing_desktop flag, to be per-screen - - * src/window.c (window_query_root_pointer): return whether pointer - is on window's screen - (meta_window_handle_mouse_grab_op_event): don't use coordinates - from other screens when updating a window operation on the current - screen. I can't believe no one has reported this... - -2002-10-16 Havoc Pennington - - * src/window.c (meta_window_client_message): update window layer - when above/below state is changed. Fixed by Ross Burton. - -2002-10-14 Federico Mena Quintero - - * src/display.c (event_callback): Ignore EnterNotify events when - the detail field is set to NotifyInferior. Fixes #95747. - -2002-10-12 Havoc Pennington - - * src/metacity.schemas.in: button layout key - - * src/prefs.c: Add button layout gconf key - (change_notify): use some "else if" instead of "if" where we - should have been - -2002-10-11 Havoc Pennington - - * src/display.c (event_callback): don't raise window on button 2 - click, only on button 1 and button 3. - - * src/frames.c (meta_frames_button_press_event): lower on button 2 - press on frame - - * src/core.c (meta_core_user_lower): new function - -2002-10-11 Havoc Pennington - - * src/stack.c (window_is_fullscreen_size): make the checks here - allow windows larger than the screen in addition to - exactly-screen-size - - * src/window.c (meta_window_configure_request): delete the "try to - auto-enter-fullscreen-state" hack here, because it was broken, and - the changes to the stacking code to move screen-size focused - windows to the fullscreen layer should work better. - (meta_window_new): remove auto-fullscreen hack from here too - -2002-10-09 Havoc Pennington - - * src/stack.c (apply_constraints): also keep utility/menu/toolbar - windows above their whole group. - - (get_standalone_layer): don't use META_LAYER_FOCUSED_WINDOW, but - only use META_LAYER_FULLSCREEN while the fullscreen window has - focus. Also, put screen-sized windows in the fullscreen layer, - even if we didn't dare to actually put them in the fullscreen - state. - -2002-10-07 Havoc Pennington - - Add a modifier key preference for the Alt+click stuff. - Can be set to "disabled" as well. - - * src/run-metacity.sh: load .Xmodmap in the Xnest if it exists - - * src/display.c (meta_display_ungrab_window_buttons): ungrab - AnyModifier in case the modifier changed since we grabbed - (meta_display_open): rearrange code to use meta_display_close() to - mop up when we can't find any screens, avoiding the need to - keep the bail-out code in sync with meta_display_close. - - * src/keybindings.c (devirtualize_modifiers): move this function - to a public place in display.c - - * src/metacity.schemas.in: add setting for the modifier key - to use for Alt+left/middle/right click. - - * src/prefs.c (update_binding): add a missing newline to a warning - (meta_prefs_get_mouse_button_mods): new function - - * src/ui.c (meta_ui_parse_modifier): new function - -2002-10-07 Havoc Pennington - - * src/async-getprop.c: don't include unportable Xproto.h, fix from - Glynn Foster. - -2002-10-06 Havoc Pennington - - * src/async-getprop.c: change to add only one _XAsyncHandler per - display, speeding things up a bit. - -2002-10-06 Havoc Pennington - - * src/async-getprop.c: Add wacky hack suggested by Keith Packard - to get X properties asynchronously. Not actually used by metacity - yet, but thinking about it. - -2002-10-04 Havoc Pennington - - * configure.in: actually link to RANDR_LIBS - -2002-10-04 Havoc Pennington - - * src/display.c (event_callback): do XRRUpdateConfiguration() - if we have RandR extension, else poke in Xlib's screen struct to - update the screen size. - - * configure.in: fix a bogus overwrite of cppflags, - add a check for RandR extension - -2002-10-04 Arvind Samptur - - * src/window.c (meta_window_change_workspace): call - meta_window_unstick before adding window to workspace. - (menu_callback): call meta_workspace_activate before - meta_window_change_workspace. This would avoid us running an - extra loop for determining the window workspace list. - - Patches from Jeyasudha and Arvind. Fixes #92575 - -2002-10-03 Havoc Pennington - - * src/themes/Esco/metacity-theme-1.xml: only specify the - middle backgrounds, let left/right fall back to middle - - * src/theme.c (get_button): fall back to middle_background draw - routines when missing the left/right button backgrounds. - (button_rect): fix to handle drawing middle button backgrounds - (meta_frame_style_draw): draw middle background once per middle - button - -2002-10-03 Havoc Pennington - - Button-reordering patch. Has all the code except actually - installing a gconf schema and reading the gconf key in prefs.c. - metacity-theme-viewer displays the button layouts for testing - themes. - - * src/preview-widget.c (meta_preview_size_request): make up a - width/height if no child widget - - * src/prefs.c (meta_prefs_get_button_layout): new function - - * src/frames.c: get the button layout from prefs and - use it when drawing - - * src/theme.c (meta_frame_layout_calc_geometry): enhance to be - able to lay out buttons in different arrangements - (button_rect): draw the new button background rectangles - (meta_theme_draw_frame): require a button layout argument - (meta_theme_calc_geometry): pass in the button layout - - * src/preview-widget.h: mod to handle button layouts - - * src/theme-viewer.c: mod to handle button layouts - -2002-10-03 Havoc Pennington - - * configure.in: 2.4.2 - -2002-10-03 Havoc Pennington - - * src/window.c (check_moveresize_frequency): handle the case where - the clock is set backward - -2002-10-01 Havoc Pennington - - * src/place.c (find_next_cascade): try extra cascades alongside - the first, if the first fails; patch from readams@hmc.edu - -2002-10-01 Havoc Pennington - - * src/stack.c (get_standalone_layer): put ABOVE windows in same - layer as docks. - -2002-10-01 Havoc Pennington - - * src/screen.c (meta_screen_resize_func): make it static - - * src/stack.c (get_standalone_layer): put above/below windows - in an appropriate layer. - - * src/screen.c (set_supported_hint): say we support above/below - - * src/display.h (struct _MetaDisplay): add _NET_WM_STATE_ABOVE, - _NET_WM_STATE_BELOW atoms - - * src/window.c (meta_window_client_message): handle above/below - state messages - (set_net_wm_state): handler above/below state - (update_net_wm_state): handle above/below states - -2002-10-01 Mark McLoughlin - - * src/screen.c: (meta_screen_new): default to - topleft starting corner. - (meta_screen_update_workspace_layout): handle - new property format : orient,x,y,starting corner. - Fixes #89373. - - * src/screen.h: add MetaScreenCorner enum. - -2002-10-01 Havoc Pennington - - * src/window.c (constrain_position): always align fullscreen - windows to top, as we do with maximized windows. - -2002-10-01 Stanislav Brabec - - * configure.in: Added cs to ALL_LINGUAS. - -2002-09-30 Havoc Pennington - - * src/screen.c (reload_xinerama_infos): fix compilation on - Solaris, patch from Satyajit Kanungo - -2002-09-29 Havoc Pennington - - * src/eggaccelerators.c: update from libegg to get fix from Ralph - Loader for parsing, #93005 - -2002-09-29 Havoc Pennington - - * src/effects.h (META_MINIMIZE_ANIMATION_LENGTH): shorten minimize - animation a bit - -2002-09-28 Havoc Pennington - - Patch from Keith Packard to handle root window resizes. - - * src/screen.c (reload_xinerama_infos): factor out Xinerama code - (meta_screen_resize): implement this, to be called from display.c - on screen resize - - * src/display.c (event_callback): handle ConfigureNotify on root - windows - -2002-09-28 Havoc Pennington - - * src/stack.c (get_standalone_layer): re-enable the FOCUSED_WINDOW - layer, should now work correctly. - -2002-09-28 Havoc Pennington - - * src/window.c, src/stack.c: Rewrite stack code to work a lot - differently. Should be better now, and not lose relative positions - of windows when moving among layers. Also should now be possible - to get session management to restore the stacking order. Probably - breaks some stuff, and makes all the stack.c changes I made - yesterday sort of irrelevant. - -2002-09-27 Havoc Pennington - - * src/stack.c (get_standalone_layer): Temporarily disable use of - the FOCUSED_WINDOW layer, because given the fact that moving - multiple windows into the same layer changes the Z-order of those - windows, it was breaking click-to-focus. - -2002-09-27 Havoc Pennington - - * src/screen.c (meta_screen_focus_top_window): raise the focused - window, since it may not be the window on top, given the below - change. - - * src/stack.c (meta_stack_get_default_focus_window): make this - more complex to prefer to focus the transient parent, followed by - other windows in group, followed by topmost non-dock, followed by - dock. Previously was just topmost non-dock followed by dock - ignoring groups and transiency. - -2002-09-27 Havoc Pennington - - * src/place.c (constrain_placement): constrain placement to try to - keep windows from going offscreen to the right/bottom - - * src/stack.c (compute_layer): rearrange the logic here to say - that a window must always be in at least as high a layer as any of - its transient parents or group members, rather than special-casing - fullscreen. Also, group_member_is_fullscreen was leaking the list - of group members every time, a fairly major memory leak. - -2002-09-27 Havoc Pennington - - * src/themes/Makefile.am (THEMES): use AgingGorilla not Gorilla - (renamed on the CVS server) - -2002-09-27 Havoc Pennington - - Try to handle Solaris Xinerama, all coded blind, someone - on Solaris will need to debug the typos. - - * src/display.c: updates for Solaris Xinerama - - * src/screen.c: updates for Solaris Xinerama - - * configure.in: make Xinerama check more complicated to catch - Solaris Xinerama - -2002-09-27 Havoc Pennington - - * src/window.c (update_transient_for): keep a flag - transient_parent_is_root_window for whether the - root-window-as-parent convention was used. - -2002-09-25 Arvind Samptur - - * src/stack.c (sort_window_list): Keep dialogs without - transient parent above entire app. Fixes #88926 - -2002-09-26 Havoc Pennington - - * src/menu.c (meta_window_menu_new): use MetaAccelLabel to display - accelerators for the menu items - - * src/metaaccellabel.c: cut-and-paste GtkAccelLabel and port to - use virtual modifiers - - * src/Makefile.am (metacity_SOURCES): add metaaccellabel.[hc] - - * src/prefs.c (meta_prefs_get_window_binding): new function - - * src/core.c (meta_core_get_menu_accelerator): new function - -2002-09-25 Havoc Pennington - - * src/metacity.schemas.in: Change short desc of switch_windows and - cycle_windows to be different - -2002-09-24 Havoc Pennington - - * src/place.c (fit_rect_in_xinerama): update best_overlap as we go - through the loop - doh. Fix from readams@hmc.edu for #90799. - (find_first_fit): try the origin of each xinerama screen - after the first. Also from readams@hmc.edu - -2002-09-24 Havoc Pennington - - * src/window.c (meta_window_save_rect): new function, - only saves rect after checking current state, #93795 - (meta_window_make_fullscreen): use new function - (meta_window_maximize): use new function - -2002-09-24 Havoc Pennington - - * src/window.c (meta_window_update_layer): new function - - * src/stack.c (compute_layer): put focused window in a layer above - all other windows, in click-to-focus mode. #93022 - - * src/window.c (meta_window_notify_focus): update window layer on - focus change. - -2002-09-24 Havoc Pennington - - * src/main.c (main): support --version, #92796 patch from - Christian Neumair - - * autogen.sh: change gettext test to be happy with - glib-gettextize, #81425 - - * src/menu.c: change mnemonics to match bug #78999 - - * src/theme.c (meta_theme_validate): consolidate some - nearly-identical themes for ease of translation, #70962 - -2002-09-24 Arvind Samptur - - * src/menu.c: Replace strings Shade with Roll Up and - Unshade with Unroll. - -2002-09-23 Havoc Pennington - - * src/main.c (main): re-enable the log handler, maybe it will - break something, I don't remember why I turned it off. - - * src/display.c: s/_NET_SHOW_DESKTOP/_NET_SHOWING_DESKTOP/ which - is what's in the spec - -2002-09-22 Havoc Pennington - - * src/window.c (recalc_window_features): small reordering of - code - - * src/display.c (meta_spew_event): more spew for MapNotify, - UnmapNotify - - * src/window.c (recalc_window_features): spew more stuff - - * src/display.c (meta_spew_event): spew override_redirect field of - ConfigureNotify - -2002-09-20 Arvind Samptur - * src/metacity.schemas.in: added keybindings for - moving windows between workspaces. - - Patch from Jeyasudha. Fixes #91944. - -2002-09-19 Arvind Samptur - * src/tools/metacity-properties.desktop.in : - change in the tooltip suggested in ui-review. - -2002-09-18 Havoc Pennington - - * src/window.c (update_net_wm_state): handle fullscreen state - here. - -2002-09-15 Havoc Pennington - - * src/session.c (save_state): escape the window title before - saving in the session file, reported by Jos Vos - -2002-09-12 Havoc Pennington - - * src/workspace.c (meta_workspace_screen_index) - (meta_workspace_index): fix compiler warnings - - * src/tools/metacity-window-demo.c (menu_items): add a test for - dialogs with no transient parent - - * src/place.c (find_first_fit): Try placing window at origin of - first Xinerama, even if there are no windows to place next to; - makes placement work when no other windows are open on the screen. - -2002-09-09 Havoc Pennington - - * configure.in: 2.4.1 - -2002-09-09 Christian Neumair - - * src/keybindings.c: Make virtual desktops apply - instantly and still show the pager popup by - Benjamin Kahn , fixes #86590. - -2002-09-06 Frederic Crozat - - * src/themes/Crux/metacity-theme-1.xml: Fix titlebar - glitch on small dialogs. - -2002-09-06 Arvind Samptur - * theme-format.txt : corrected some of the attributes - which were not in sync with theme-parser.c - Patch from Jim Bowen. #92057. - -2002-09-05 Havoc Pennington - - * configure.in: put ro back in ALL_LINGUAS - -2002-09-05 Havoc Pennington - - * configure.in (ALL_LINGUAS): remove 'ro' from ALL_LINGUAS, it - contained invalid XML and broke the build. No <> in the - translations of gconf keys! - -2002-09-04 Marius Andreiana - - * configure.in: added 'ro' to ALL_LINGUAS - -2002-09-03 Havoc Pennington - - * src/display.c (meta_display_get_tab_current): new function - - * src/keybindings.c (do_choose_window): apply modified patch from - JeyaSudha to still display tab popup if only one window is on the - desktop. - -2002-06-25 JeyaSudha - - * src/session.c, src/window.c: Session saves the unmaximized - postion, size of a maximized window. #86059 - -2002-09-03 Havoc Pennington - - * src/frames.c (meta_frames_update_prelit_control): don't filter - out prelight for unmaximize button. #83860 - (meta_frames_paint_to_drawable): handle unmaximize here as well - -2002-08-27 Havoc Pennington - - * src/theme.c (meta_frame_layout_calc_geometry): always apply - rounding for shaded windows, fixes Bluecurve theme when shaded - -2002-08-25 Havoc Pennington - - * src/window.c (meta_window_free): when freeing a fullscreen - window, update layers of the window's group. - -2002-08-25 Havoc Pennington - - * src/display.c (meta_display_open): _NET_SUPPORTING_WM_CHECK is - supposed to have type WINDOW not CARDINAL. reported by - Ben Jansens - -2002-08-24 Havoc Pennington - - * src/window.c (process_property_notify): recalculate mapped-ness - of frame after toggling decorations on/off, so that windows don't - disappear when decorations are toggled on. - - * src/tools/metacity-window-demo.c (toggle_decorated_cb): add a - test for toggling decoration state on the fly - -2002-08-24 Havoc Pennington - - * src/window.c (update_sm_hints): hack around bug in kmail etc. - where SM_CLIENT_ID was set on the window, not the client leader. - - * src/theme.c (meta_frame_layout_calc_geometry): don't round - corners unless we have enough frame to chop off. - -2002-08-24 Havoc Pennington - - * src/util.c: translate some strings that should have been, and - convert to locale encoding before printing stuff. - - * src/stack.c (group_member_is_fullscreen): if window itself is - fullscreen, return TRUE immediately. - - * src/window.c (meta_window_configure_request): add hack to - fullscreenize large undecorated windows. - -2002-08-21 Deepa Natarajan - - * src/keybindings.c, src/metacity.schemas.in, src/prefs.[ch]: - add maximize and unmaximize keybinding setting. Partly fixes - bug# 78999. - -2002-08-20 Steve Fox - - * metacity.spec.in: Add so that the spec file gets auto-updated - whenever configure.in gets bumped. Include some missing - directories. - - * Makefile.am - * configure.in: Necessary changes for spec file magic - -2002-08-20 Havoc Pennington - - * src/frames.c (get_control): if in the title rect check for y - <= TOP_RESIZE_HEIGHT - - * src/display.c (meta_spew_event): put x/y coordinates in spew for - enter/leave notify - - * src/frames.c (meta_frames_motion_notify_event): move cursor - changing from here to update_prelit_control so it happens on enter - notify as well - (get_control): change test "y < TOP_RESIZE_HEIGHT" to - "y <= TOP_RESIZE_HEIGHT" - - * src/Makefile.am (EXTRA_DIST): include .in files in EXTRA_DIST - -2002-08-17 Simos Xenitellis - - * configure.in (ALL_LINGUAS): Added Greek (el). - -2002-08-17 Evandro Fernandes Giovanini - - * configure.in (ALL_LINGUAS): Added Brazilian Portuguese (pt_BR). - -2002-08-15 Havoc Pennington - - * src/metacity.schemas.in: default to "Sans Bold 10" for the - titlebar font. - -2002-08-15 Havoc Pennington - - * src/window.c (recalc_window_features): leave has_fullscreen_func - set to TRUE if the window is screen sized and undecorated, even if - the window isn't resizable. idea from Christian - Manny Calavera - - Neumair - - * src/keybindings.c (handle_toggle_fullscreen) - (handle_toggle_maximize): these disabled fullscreen/maximize if - the window wasn't resizable, should have used has_fullscreen_func - has_maximize_func instead. - -2002-08-15 Havoc Pennington - - * src/keybindings.c: implement raise/lower - - * src/metacity.schemas.in: add raise/lower - - * src/prefs.c: add "raise" and "lower" prefs to keybindings - - * src/display.c (meta_display_set_grab_op_cursor): assert that - the screen arg is non-NULL in appropriate cases - -2002-08-14 Jayaraj Rajappan - - * src/display.c (meta_display_set_grab_op_cursor): - In XGrabPointer, set the confine_to argument to the root window - of the screen the window is on. - - * src/display.h: add screen argument. - - * src/window.c (meta_window_update_resize_grab_op): - pass screen argument as NULL. - -2002-08-14 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: use button positioning - theme stuff. - -2002-08-14 Mark McLoughlin - - * src/screen.c: (set_number_of_spaces_hint), move from - workspace.c. - (update_num_workspaces): set the hint here. Fixes #90123. - - * src/workspace.c: - (meta_workspace_new), (meta_workspace_free): don't set - the hint here. - (update_num_workspaces): move to screen.c - -2002-08-12 Havoc Pennington - - * src/stack.c (compute_layer): window is in fullscreen layer if - any member of its group is fullscreen - - * src/window.c (meta_window_unmake_fullscreen): update layer for - whole window group - (meta_window_make_fullscreen): ditto - - * src/util.c (meta_unsigned_long_hash): move hash/equal funcs for - Window in here. - - * src/group.c: track window groups so we can do stuff with them. - -2002-08-11 Havoc Pennington - - * src/menu.c: don't include nonexistent stock-icons.h file - -2002-08-10 Havoc Pennington - - * src/metacity.schemas.in: default keybindings for move, resize, - maximize, etc. from Deepa #78999 - -2002-08-10 Havoc Pennington - - * src/window.c (meta_window_maximize): unshade window if shaded, - from JeyaSudha - (meta_window_make_fullscreen): ditto - -2002-08-10 Havoc Pennington - - * src/menu.c: reorder the menu items so that Close is at the - bottom - - * src/theme-viewer.c (main): set debugging mode if METACITY_DEBUG - enabled - -2002-08-10 Havoc Pennington - - * src/xprops.c (meta_prop_get_motif_hints): allow Motif hints to - be smaller than expected; GLUT for example seems to set a smaller - struct. #89841 - - * src/window.c (update_mwm_hints): use g_free on motif hints as we - don't use the XGetWindowProperty return directly anymore - -2002-08-10 Havoc Pennington - - * src/window.c (meta_window_free): be sure window is - mapped if we unmanage it and it's not withdrawn; - bug #90369 - - * src/screen.c (meta_screen_new): change string - s/override/replace/ bug #89077 - - * src/theme.c (scale_and_alpha_pixbuf): dump the - sometimes-use-NEAREST-instead-of-BILINEAR optimization, - bug #87489 - -2002-08-10 Havoc Pennington - - * src/window.c (menu_callback): raise window when moving to - another workspace bug #88896 - - * src/keybindings.c (switch_to_workspace): raise window when - moving between spaces - -2002-08-10 Jorn Baayen - - Register window menu icons with the Gtk stock system, instead - of using the ones from the Metacity theme (which looked very bad with - some themes). - - * src/Makefile.am: - * src/main.c: - * src/menu.c: - * src/stock_delete.png: added these files - * src/stock_minimize.png: - * src/stock_maximize.png: - * src/ui.c - -2002-08-10 Havoc Pennington - - * src/keybindings.c (meta_display_process_key_event): filter out - key events that happen on popup menus etc. - - * src/ui.c (meta_ui_window_is_widget): new function to check - whether a window belongs to a GtkWidget such as the popup menu - - * src/prefs.c (change_notify): put in a no-op line for AIX - compiler, #84252 - -2002-08-10 Havoc Pennington - - * src/window.c (update_resize): track time to avoid sending a - deluge of move/resize requests, suggestion from - xavier.bestel@free.fr bug #86830. Not really sure if this will - make a difference or not. We'll see I guess. - (update_move): do same on move though it seems less important - here. - - * src/display.h (struct _MetaDisplay): store the - last time we sent a move/resize event. - -2002-08-10 Havoc Pennington - - * src/window.c (meta_window_notify_focus): add a FIXME comment - with a link to bug #90382 - -2002-08-09 Havoc Pennington - - * src/keybindings.c (handle_toggle_maximize): disable maximize, - fullscreen, shade via keybindings on windows that don't support - it. - -2002-08-08 Craig Black - - Patch to provide extra cues when using the window menu - move and resize items, #85724. - - * src/common.h: add new cursors - - * src/display.c: (grab_op_is_mouse) - (meta_display_create_x_cursor), (xcursor_for_op), - (meta_display_set_grab_op_cursor), - (meta_display_begin_grab_op): - The keyboard move and resize grab ops now also use the mouse. - Allow the grab cursor to be changed during the grab op. - Hold onto the initial grab position in case of reset. - - * src/display.h: save the initial grab position - - * src/keybindings.c: (process_keyboard_move_grab), - (process_keyboard_resize_grab), (handle_begin_move), - (handle_begin_resize): - The keyboard move and resize grab ops now also use the mouse. - - * src/window.c: (meta_window_client_message), (menu_callback), - (update_move), (update_resize), - (meta_window_handle_mouse_grab_op_event), (warp_pointer), - (meta_window_warp_pointer), (meta_window_begin_grab_op), - (meta_window_update_resize_grab_op): - When moving or resizing a window use the last grab position - in computing change increment. - Provide support for warping the mouse pointer. - - * src/window.h: new warp pointer and grab op helper functions - -2002-08-08 Craig Black - - * src/display.h: update comment - * src/window.c: (meta_window_focus): also set expected - focus window when setting input focus. - -2002-08-07 Craig Black - - * src/display.c: (meta_display_unshow_desktop): focus - top window after showing desktop, fixes #88080. - -2002-08-07 Craig Black - - * src/core.c: (meta_core_show_window_menu): focus window - on right click for menu, #87299. - -2002-08-07 Craig Black - - * src/display.c: (meta_display_open): clear expected focus window - on open - - * src/display.h: add expected_focus_window field - - * src/window.c: (meta_window_make_fullscreen), - (meta_window_unmake_fullscreen): change meta_window_update_layer() - to meta_stack_update_layer() so build works again. - (meta_window_free), (meta_window_make_fullscreen), - (meta_window_focus), (meta_window_notify_focus): keep track of - expected focus window after sending WM_TAKE_FOCUS event, - previously if a UnmapNotify event arrived before the FocusIn event - we would lose focus, fixes #84564. - -2002-08-07 Havoc Pennington - - * src/window.c (meta_window_unmake_fullscreen): update layer - (meta_window_make_fullscreen): update layer - - * src/stack.c (compute_layer): put window on fullscreen layer if - fullscreen - -2002-08-06 Craig Black - - * src/window.c: (meta_window_client_message): implement - _NET_WM_MOVERESIZE enhancements, see #90077. - -2002-08-06 Havoc Pennington - - * configure.in: 2.4.0 (this version number has no special - significance, just didn't want to go to 4-digit micro version ;-) - -2002-07-28 Havoc Pennington - - * src/window.c (meta_window_shade): disable animation when shading - windows, just doesn't really convey the idea anyway. - - * src/effects.c: Move to using a shaped window instead of - IncludeInferiors to do the animations, looks a lot better - because we don't have to grab the server. - - * src/window.c (meta_window_change_workspace): remove bogus - assertion that was causing a crash - (meta_window_new): auto-fullscreen huge undecorated windows. - - * src/keybindings.c (switch_to_workspace): use - meta_window_change_workspace() to avoid same bug in cut-and-paste - code from there - -2002-08-06 He Qiangqiang - - * configure.in: Added "zh_CN" to ALL_LINGUAS. - -2002-08-05 Ross Burton - - * src/window.c: (meta_window_client_message): Set - ->wm_state_skip_pager (ditto for _taskbar) instead of ->skip_pager - so that these hints actually work. Fixes #89850. - -2002-08-04 Havoc Pennington - - * src/frames.c (meta_frames_paint_to_drawable): init button - states for the button backgrounds - - * src/themes/Atlanta/metacity-theme-1.xml: adapt to work correctly - with button repositioning - -2002-08-04 Havoc Pennington - - * src/frames.c (meta_frames_button_press_event): raise/focus - on click, even if the click was on the client area - (this makes Alt+button1 raise windows again, yay) - - * src/stack.c (compute_layer): put panels in the DOCK layer always - (keep them on top of other windows). Still sloppy-focus raised - with respect to other docks. - - * configure.in: remove -Wshadow for now as GTK headers make all - kinds of noise with it. - -2002-08-02 Mark McLoughlin - - * src/screen.c: (meta_screen_new): set active_workspace - to NULL. Also actually activate the first workspace instead - of just setting active_workspace. Fixes #87367. - (meta_screen_ensure_workspace_popup): don't re-use our - iterator for setting the entries list, stop iterating - when we've gone beyond the last workspace (there may - be empty spaces in the last row). - - * src/workspace.c: (meta_workspace_activate): if no workspace - was previously activated, return. - -2002-08-04 Havoc Pennington - - * src/theme.c (free_menu_ops): use MetaMenuIconType not button - type for the size of the menu ops array - (meta_theme_define_int_constant): return TRUE on success (how the - heck did this ever work?) - (meta_theme_define_float_constant): return TRUE on success - (meta_frame_style_validate): allow the "positional" buttons to - be omitted for now. - - * src/testgradient.c (render_multi): don't define N_COLORS twice - - * src/theme-viewer.c (run_theme_benchmark): don't define - ITERATIONS twice - - * src/theme.c (button_rect): handle new button types - (meta_button_type_to_string): update - (meta_button_type_from_string): update - - * src/theme.h (enum): add button types for the 6 possible button - positions. No way to reposition buttons still but this will allow - themes to go ahead and support doing so. - -2002-08-03 Craig Black - - * src/keybindings.c: (meta_display_process_key_event), - (process_tab_grab), (do_choose_window): change alt+tab to a - windowless grab, fixes #83499 - -2002-08-03 Craig Black - - * src/display.c: (event_callback): Have ButtonPress and - UnmapNotify events account for a null grab window, fixes #87896 - -2002-08-03 Gaute Lindkvist - - Corrected some issues with the Bright theme. Mainly - making sure the text does not clip, as well as increasing - the size of the menu icon. - -2002-08-01 Mark McLoughlin - - Implements support for _NET_WM_ALLOWED_ACTIONS. - Fixes #84282. - - * src/display.[ch]: (meta_display_open): add - _NET_WM_ALLOWED_ACTIONS atoms. - - * src/screen.c: (set_supported_hint): set them - as being supported. - - * src/window.c: - (set_allowed_actions_hint): impl setting - _NET_WM_ALLOWED_ACTIONS. - (recalc_window_features): use it here, but only - if things have changed. - -2002-08-01 Christophe Fergeau - - * src/metacity-dialog.c: focus the "Close" button by default on - the dialog which appears at exit when some apps can't be session - managed - -2002-08-01 Mark McLoughlin - - * src/session.c: - (save_yourself_possibly_done): send a SaveYourselfDone - if we're skipping this global save. - (save_yourself_callback): don't not save session state - if the save style is Global. Fixes #89390. - - * theme-format.txt: update. - -2002-07-30 Pablo Saratxaga - - * configure.in: Added Vietnamese (vi) to ALL_LINGUAS - -2002-07-24 Havoc Pennington - - * src/themes/Makefile.am (THEMES): add Metabox theme from Garrett - - * README: updates - -2002-07-21 Havoc Pennington - - * src/window.c (meta_window_new): don't automaximize fullscreen - windows. - -2002-07-14 Havoc Pennington - - * src/window.c (recalc_window_features): don't allow shading of - border-only windows. - -2002-07-24 Havoc Pennington - - * src/theme-parser.c (meta_theme_load): look for themes in - ~/.themes/NAME/metacity-1/ and datadir/themes/NAME/metacity-1 - instead of the old locations. - - * src/themes/Makefile.am: install themes to - datadir/themes/NAME/metacity-1/ to match how GTK works, breaking - third-party themes yet again! woot! - -2002-07-20 Havoc Pennington - - * src/display.c (meta_display_open): grab display across managing - each screen; XGetInputFocus() on startup. - -2002-07-19 Havoc Pennington - - * src/window.c (meta_window_configure_request): disable configure - requests during a user move/resize operation, mostly a workaround - for stoopid apps. - -2002-07-24 jacob berkman - - * configure.in: fix x11 header checks when x11 is not in the - default include path - -2002-07-23 Ross Burton - - * src/menu.c (meta_window_menu_new): Use the real workspace names - instead of making up numbers. - -2002-07-23 Havoc Pennington - - * src/themes/Makefile.am (THEMES): put Gorilla back in the build - - * src/themes/Gorilla/metacity-theme-1.xml, - src/themes/Crux/metacity-theme-1.xml: fixes from - Sebastien Delestaing so that these themes work properly with - different font sizes. - - * src/frames.c (get_control): patch from Balamurali Viswanathan - for #81984 (resize titlebar from the top not the bottom) - -2002-07-23 Havoc Pennington - - * src/keybindings.c (meta_display_process_key_event): handle - NULL screen from screen_for_xwindow - - * src/display.c (meta_display_screen_for_xwindow): put an error - trap around the XGetWindowAttributes(), should fix the popular - "closing a window results in a crash" bug. - - * src/util.c (print_backtrace): support optional backtrace - feature using gnu libc backtrace() call - -2002-07-15 jacob berkman - - * src/update-from-egg.sh: steal from profterm to fix build - -2002-07-13 Havoc Pennington - - * src/workspace.c (meta_workspace_new): don't put a newline after - the default workspace name - -2002-07-13 Havoc Pennington - - * src/keybindings.c: adapt to virtual modifiers - (meta_display_process_mapping_event): we need to reload the - binding tables now when the modmap changes. - - * src/prefs.c (update_binding): parse virtual modifiers, not - plain modmask - - * src/common.h (MetaVirtualModifer): new enum - - * src/ui.c (meta_ui_parse_accelerator): use - egg_accelerator_parse_virtual() - - * src/Makefile.am: add eggaccelerators.[hc] for the virtual - accelerator parsing function - -2002-07-13 Christophe Fergeau - - * configure.in: added fr to ALL_LINGUAS - -2002-07-12 Havoc Pennington - - * src/session.c (warn_about_lame_clients_and_finish_interact): - don't display the dialog if all the apps were session managed. - -2002-07-12 Havoc Pennington - - * src/session.c: don't send SmInteractDone until the warning - dialog about crappy clients has been closed. - -2002-07-12 Havoc Pennington - - * src/window.c (meta_window_new): try to maximize windows that - are too big for the work area - - * src/place.c (find_next_cascade): don't let the cascade algorithm - place windows off the screen, and fix it to always exhaustively - search the window list for cascade parents. - -2002-07-11 Havoc Pennington - - * src/metacity-dialog.c (main): option to display error when a - command fails to run. - - * src/keybindings.c (handle_run_command): run commands - in response to keybindings. - - * src/prefs.c: add command keybinding stuff - - * src/metacity.schemas.in: add keybindings for running commands, - and keys to store the commands themselves. - -2002-07-10 Havoc Pennington - - * src/display.c: properly attribute selection code to Matthias - Clasen - -2002-07-10 Havoc Pennington - - * README: couple of updates - - * src/main.c (usage): add --replace to usage, reported by Matthias - Clasen - -2002-07-09 Havoc Pennington - - * src/metacity.schemas.in: fix short description for - begin_resize, patch from Jayaraj, #87654 - - * src/keybindings.c (handle_begin_resize): apply patch from - Jayaraj to actually handle the begin resize keybinding. - -2002-07-09 Havoc Pennington - - * src/window.c (constrain_position): don't center vertically for - maximized windows that don't fill the screen, just leave them at - the top. - -2002-07-06 Havoc Pennington - - * src/tabpopup.c (selectable_workspace_new): increase the size of - the mini workspaces - -2002-07-06 Havoc Pennington - - Apply blackc@speakeasy.net patch, bug #83940, to do - mini-workspaces similar to the pager, when switching - spaces. - - * src/window.c (update_net_wm_state): actually fill in - wm_state_skip_taskbar, wm_state_skip_pager flags - - * src/tabpopup.c: support drawing a mini-workspace similar to the - one the pager draws. - - * src/stack.c (meta_stack_list_windows): new function to list - the windows in stacking order - - * src/screen.c (meta_screen_ensure_workspace_popup): don't pass in - the ugly default app icon for workspaces - - * src/display.c (event_callback): fix from blackc@speakeasy.net - to avoid dereferencing a NULL grab window. - -2002-07-06 Havoc Pennington - - * src/display.c (meta_display_open): put _NET_DESKTOP_NAMES in the - array of atom names, so desktop names might work and we don't read - uninitialized memory. - - * src/main.c (main): add VERSION/timestamp verbose message. - - * src/keybindings.c: implement cycle_windows cycle_panels - - * src/metacity.schemas.in: add the cycle_windows cycle_panels - keybindings - - * src/prefs.h (META_KEYBINDING_FOCUS_PREVIOUS): replace - FOCUS_PREVIOUS key binding with CYCLE_WINDOWS and CYCLE_PANELS - (not good names really, but I don't have ideas). - - * src/common.h: add a grab op for alt+esc window cycling - -2002-07-05 Havoc Pennington - - * src/themes/Makefile.am (THEMES): Take Gorilla out until it gets - repaired. - -2002-07-05 Havoc Pennington - - * src/window.c (update_wm_hints): Change default value of input - hint (if not specified) to true instead of false. This is what - some clients assume, such as Visual SlickEdit. - -2002-07-02 Havoc Pennington - - * src/window.c (meta_window_show_menu): use new macros to get - whether we allow move/resize correct - - * src/frame.c (meta_frame_get_flags): use new macros to get - whether we can move/resize correct, considering - maximized/fullscreen for the move case. - - * src/window.h (META_WINDOW_ALLOWS_RESIZE, - META_WINDOW_ALLOWS_MOVE): new macros - - * src/keybindings.c (process_keyboard_resize_grab): finish the - right/left resize, patch from Jayaraj #78179. - - Has the same old move/resize bug, if it hits a constraint it - starts to break because we move without resizing. - -2002-07-02 Mark McLoughlin - - * src/keybindings.c: - (grab_keyboard), (ungrab_keyboard): rename from - {un}grab_all_keys_and_keyboard and only do an XKeyboardGrab, - the XKeyGrab isn't neccessary. - (meta_screen_grab_all_keys), (meta_screen_ungrab_all_keys), - (meta_window_grab_all_keys), (meta_window_ungrab_all_keys): - update for above change. - (handle_workspace_switch): don't use a MetaWindow when - workspace switching, use the root window instead. - -2002-07-01 Mark McLoughlin - - Fix broken workspace switching from my previous commit. - - * src/display.c: (meta_display_begin_grab_op): don't - leak a pointer grab if we fail to grab the keyboard. - - * src/keybindings.c: (meta_screen_grab_keys): check - screen->all_keys_grabbed. - (meta_screen_grab_all_keys): regrab our standard - bindings if we fail. - (handle_workspace_switch): revert to our previous - behaviour of using the last focused window to do - the grab upon. Only use the RootWindow if there - isn't anything else to use. - - * src/screen.c: (meta_screen_new): initialise - all_keys_grabbed. - -2002-06-26 Mark McLoughlin - - Fixes not being able to tab out of a - workspace which contains no windows. - - * src/core.c: (meta_core_begin_grab_op): upd - for meta_display_begin_grab_op change. - (meta_core_get_grab_frame): allow for - grab_window == NULL. - - * src/display.[ch]: - (meta_display_screen_for_xwindow): implement. - (meta_display_begin_grab_op): grab on the root window - if window == NULL. - (meta_display_end_grab_op): use grab_screen instead of - grab_window. - - * src/keybindings.c: - (grab_all_keys_and_keyboard): split out from - meta_window_grab_all_keys. - (ungrab_all_keys_and_keyboard): split out from - meta_window_ungrab_all_keys. - (meta_screen_grab_all_keys), (meta_screen_ungrab_all_keys): - implement grabbing and ungrabbing on the root window. - (meta_display_process_key_event): if window == NULL, - check the event is from the same screen and process. Only - happens with workspace switching. - (process_workspace_switch_grab): kill window param and - don't use grab_window. - (handle_tab_forward), (handle_begin_move): upd for - meta_display_begin_grab_op change. - (handle_workspace_switch): remove brokeness. Always do - the grab op on the root window. - - * src/keybindings.h: add meta_screen_{un}grab_all_keys. - - * src/window.c: (meta_window_client_message), (menu_callback): - update for meta_display_begin_grab_op change. - -2002-06-25 Mark McLoughlin - - * src/fixedtip.c: (meta_fixed_tip_show): - * src/frames.c: (meta_frames_new): - * src/tabpopup.c: (meta_ui_tab_popup_new): - s/gdk_get_default_display/gdk_display_get_default/ - s/gdk_get_default_screen/gdk_screen_get_default/ - -2002-06-25 Mark McLoughlin - - * src/themes/Crux/active-border-top-left-border.png: - * src/themes/Crux/active-border-top-right-border.png: - * src/themes/Crux/active-top-left-corner.png: - * src/themes/Crux/active-top-mid-left-border.png: - * src/themes/Crux/active-top-mid-right-border.png: - * src/themes/Crux/active-top-right-corner.png: - * src/themes/Crux/inactive-border-top-left-border.png: - * src/themes/Crux/inactive-border-top-right-border.png: - * src/themes/Crux/inactive-top-left-corner.png: - * src/themes/Crux/inactive-top-mid-border.png: - * src/themes/Crux/inactive-top-right-corner.png: - * src/themes/Crux/metacity-theme-1.xml: added support - for border only windows. - -2002-06-24 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Added some stuff to - the window buttons, so they use the ACTIVE bg/fg. - -2002-06-25 Mark McLoughlin - - * src/display.[ch]: (meta_display_open): - src/screen.c: (set_supported_hint), (set_work_area_hint): - Its _NET_WORKAREA, not _NET_WM_WORKAREA silly :-) - -2002-06-25 Mark McLoughlin - - * src/screen.[ch]: - (update_num_workspaces), recalc workarea hint when - new workspaces created. Fixes bug that workarea - not calculated until first non-dock window is - mapped. - (set_work_area_hint), (set_work_area_idle_func), - (meta_screen_queue_workarea_recalc): move all this - stuff from workspace.c. - - * src/workspace.c: (meta_workspace_invalidate_work_area): - use meta_screen_queue_workarea_recalc. - -2002-06-23 Gediminas Paulauskas - - * src/themes/Bright/metacity-theme-1.xml: Update with border-only - window stuff from Atlanta. - -2002-06-22 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Update for "border" - frame stuff, minor button/spacing improvements. - -2002-06-22 Havoc Pennington - - Partially fix Jacob's SM bugs. - - * src/window.c (meta_window_apply_session_info): restore the extra - stuff we're saving, except stack position I didn't figure out yet. - - * src/session.c: save stack position, minimized, maximized, - in the session file. - -2002-06-22 Havoc Pennington - - * src/workspace.c (set_number_of_spaces_hint): do nothing if - screen is being unmanaged, we don't want to blow away state, - we want to remember it for the next window manager. - -2002-06-22 Havoc Pennington - - * src/workspace.c (meta_screen_ensure_workspace_popup): rename - from meta_workspace_ensure_tab_popup, and use workspace->name - instead of a hardcoded name - -2002-06-22 Havoc Pennington - - * src/xprops.c (meta_prop_get_utf8_list): new utility function - - * src/display.c (meta_display_open): _NET_DESKTOP_NAMES atom - (event_callback): update workspace names when the property changes - - * src/screen.c (set_supported_hint): "support" _NET_DESKTOP_NAMES - (nothing to do really) - -2002-06-21 Havoc Pennington - - Theme breakage! Themes have to implement "border" frames - now, see Atlanta for an example. Fixes #84285 - - * src/tools/metacity-window-demo.c (do_appwindow): add a - border-only window - - * src/window.c (update_mwm_hints): read border only from the MWM - hints - - * src/window.h (struct _MetaWindow): add border_only flag - - * src/core.c (meta_core_get_frame_type): report border type if - required - - * src/common.h (enum): add META_FRAME_TYPE_BORDER - -2002-06-20 Mark McLoughlin - - * src/window.c: (meta_window_visible_on_workspace): sticky - windows aren't visibile on all screens. Check the workspace - is on the same screen as the window. - - * src/workspace.c: (meta_workspace_list_windows): use - meta_window_visible_on_workspace here. - -2002-06-19 Havoc Pennington - - * src/display.c (meta_resize_gravity_from_grab_op): handle UNKNOWN - keyboard resizing state - - * src/keybindings.c (process_keyboard_resize_grab): implement - keyboard resize key handling somewhat (only vertical resize works, - left/right arrow not implemented, and visual feedback of the - edge we're resizing isn't implemented) - - * src/window.c (menu_callback): start keyboard resize grab when - it's chosen from the menu - -2002-06-17 Havoc Pennington - - * src/stack.c (meta_stack_get_default_focus_window): don't use a - minimized window as the next focus window, patch from - blackc@speakeasy.net - -2002-06-17 Havoc Pennington - - * src/place.c (find_next_cascade): increase the cascade threshold - a bit. - (find_first_fit): implement a somewhat lame first fit algorithm - -2002-06-17 Havoc Pennington - - * src/window.c (meta_window_change_workspace): fix from Gaute - Lindkvist #82977 for unsticking windows - -2002-06-17 Frederic Crozat - - * src/metacity.schemas.in: associate close_window keybinding to - Alt-F4 - -2002-06-16 Havoc Pennington - - * src/main.c (main): fix spelling error, #85452 - -2002-06-15 Havoc Pennington - - * src/keybindings.c (meta_display_process_key_event): don't pass a - null string to printf - - * src/display.c (key_event_description): don't pass a null string - to printf - - * src/keybindings.c (meta_set_keybindings_disabled): allow - enable/disable keybindings regardless of debug mode. - -2002-06-15 Havoc Pennington - - * src/draw-workspace.h, src/draw-workspace.c: workspace-drawing - code factored out of libwnck, needs wiring up to tabpopup.c - (which is kind of annoying since you have to get the list of - workspaces and MetaWindow across the barrier between the GDK-aware - and non-GDK-aware sides of metacity) - -2002-06-14 Havoc Pennington - - * src/window.c (meta_window_show): always focus new windows, - trying to be smart about it was a flop. - -2002-06-14 Jayaraj Rajappan - - * src/delete.c (io_from_ping_dialog): Check for NULL string - before calling strlen(). Fixes the core dump issue reported in #84873. - -2002-06-13 Anders Carlsson - - * src/theme.c (meta_frame_layout_calc_geometry): Set client height - as 0 when the window actually is shaded, not the other way around. - -2002-06-12 Havoc Pennington - - * src/theme.c (meta_frame_layout_calc_geometry): when a window is - shaded, don't include client height in the height calculation. - - * src/workspace.c (meta_workspace_get_neighbor): apply fix from - Mads Villadsen for the Up arrow key, #84582 - -2002-06-12 Havoc Pennington - - * src/theme.c (meta_frame_style_draw): Draw the buttons right - before the "overlay" piece. - -2002-06-12 Jayaraj Rajappan - - * src/tools/metacity-properties.glade: accessibility work for - metacity-properties capplet. Set appropriate atk relations. - Fixes bug #84749 - -2002-06-11 Havoc Pennington - - * src/window.c (meta_window_show): allow dialogs to steal focus - from panels/desktop - -2002-06-10 Jayaraj Rajappan - - * src/fixedtip.c: include - fix for #83960 - -2002-06-10 Erwann Chenede - - - * src/keybindings.c : (handle_close_window, handle_minimize_window) - verify the active window has the appropriate close/minimize function - before closing or minimizing the window. - -2002-06-09 Havoc Pennington - - * configure.in: 2.3.987 - -2002-06-09 Havoc Pennington - - * src/delete.c (delete_ping_timeout_func): add G_IO_NVAL to watch - condition, patch from Gustavo Giraldez, avoids another 100% CPU - thingy - -2002-06-09 Havoc Pennington - - * src/place.c (meta_window_place): don't run constrain_placement - on windows we allow to go anywhere (docks, etc.). Fixes - positioning of panel windows in certain cases. - -2002-06-09 Havoc Pennington - - * src/frames.c (meta_frames_button_press_event): don't raise/focus - the window if minimize/close are clicked, patch from Gaute - Lindkvist #75460 - -2002-06-08 Havoc Pennington - - Cleanups to workspace popup patch. Space before all parens - in a couple places. - - * src/prefs.c (meta_prefs_get_keybinding_action): fix brace - indentation, and use while instead of for loop. Take a "mask" - argument to avoid ambiguity issues. - - * src/keybindings.c (handle_workspace_switch): rename from - handle_workspace_forward since there's no directionality here - (handle_workspace_switch): add a FIXME about how screwed it is - that we need a window in order to do our grab. Should be able to - grab on a dummy window like no_focus_window or the root window. - (process_workspace_switch_grab): rename from tab_grab for clarity, - no tab involved here. - - * src/common.h (enum): have only one grab op for all workspace - switching directions, instead of one for each. - -2002-06-08 Havoc Pennington - - Apply big patch from blackc@speakeasy.net adding a popup window - to the Ctrl+Alt+arrows shortcuts. #83940 - -2002-06-08 Havoc Pennington - - * src/screen.c (meta_screen_new): select key press/release on the - display->no_focus_window, another attempted fix for not getting - keybindings when no window is focused. Still doesn't seem to work - though. I don't get what's going wrong. - (meta_create_offscreen_window): new function, used instead of - XCreateSimpleWindow so we get override redirect offscreen windows. - -2002-06-08 Havoc Pennington - - * src/display.c (meta_display_open): set net_supporting_wm_check - in addition to win_supporting_wm_check, patch from - JeyaSudha for #83365 - - * src/screen.c (set_wm_check_hint): remove setting - win_supporting_wm_check on leader window here, done already in - display.c - -2002-06-08 Havoc Pennington - - * src/keybindings.c (meta_window_ungrab_keys): set keys_grabbed to - FALSE, patch from Jayaraj for #81857 - -2002-06-08 Havoc Pennington - - * src/xprops.c (meta_prop_get_utf8_string): don't die on bad atom - name - - * src/display.c (meta_display_close): don't unmanage windows here, - do it in screen_free and then closing the display unmanages - windows as a side effect of unmanaging the screen - (meta_display_unmanage_screen): new function - (process_selection_clear, process_selection_request): handle - selection stuff - (meta_spew_event): don't crash on client message containing - invalid atom - (meta_spew_event): don't crash on property notify with invalid - atom - - * src/main.c (main): add --replace option to replace existing - window manager. - - * src/screen.c: implement holding manager selection. - - * src/display.c (meta_display_open): add new selection-related - atoms. - -2002-06-08 Havoc Pennington - - * src/screen.c (meta_screen_new): select keypress/keyrelease - events on root window, this may fix the bug where keybindings - didn't work if you didn't have a focused window. - -2002-06-08 Havoc Pennington - - * src/main.c (main): call meta_session_shutdown when exiting - cleanly - - * src/session.c (meta_session_shutdown): function to change use to - RestartIfRunning - (meta_session_init): change normal restart hint to - RestartImmediately - -2002-06-08 Havoc Pennington - - Yeah I know maximization is broken, I'm too tired to fix it. - Probably because of the change to update_struts() that was - supposed to fix the 100% CPU bug. - - * src/place.c (meta_window_place): don't run docks and things - through the placement algorithm. Thought it might fix - metacity-window-demo but it didn't. - - * src/window.c (constrain_size): only get work area when needed - (meta_window_new): init the do_not_cover field - -2002-06-08 Havoc Pennington - - * src/screen.c (meta_screen_get_xinerama_for_window): - short-circuit the "only one xinerama" case, and use outer rect of - window instead of window->rect, so we get root window coords. - - * src/theme.c (meta_frame_layout_get_borders): if fullscreen all - frame edges are zero-width. - - * src/frame.c (meta_frame_get_flags): init fullscreen flag. - - * src/common.h (enum): add META_FRAME_FULLSCREEN frame flag - - * src/place.c: fix up calls to meta_window_get_work_area - - * src/window.c (meta_window_get_work_area): add an arg for whether - the work area is for the screen or the xinerama subscreen. - (constrain_position): fix up calls to meta_window_get_work_area - (constrain_size): ditto - - * src/screen.c (meta_screen_new): add METACITY_DEBUG_XINERAMA - environment variable which simulates xinerama on a single head. - -2002-06-08 Havoc Pennington - - * src/window.c (update_struts): only invalidate things if the - struts actually change, since the panel likes to set them over and - over. May fix the infinite loop that caused 100% CPU usage. - -2002-06-07 Havoc Pennington - - * src/screen.c (meta_screen_new): use XineramaIsActive() not - XineramaQueryExtension() - -2002-06-07 Havoc Pennington - - * src/screen.c (meta_screen_get_current_xinerama): don't return - null on non-multihead - -2002-06-06 Havoc Pennington - - * src/screen.c (meta_screen_get_current_xinerama): implement - - * src/place.c (meta_window_place): cascade windows on the active - Xinerama screen - - * src/window.c (meta_window_move_resize_internal): strip out the - #if 0 cruft about guessing fullscreen mode - (constrain_position, constrain_size): fullscreen/maximize to the - Xinerama head, not the whole screen - (meta_window_get_work_area): autocreate struts at the Xinerama - physical screen edges for the screen the window is on. - - * src/screen.c (meta_screen_get_xinerama_for_window): someone - snuck in a for loop, fix it. ;-) - -2002-06-06 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Increase the border size - of the buttons so they aren't quite so huge on my box. Also get - a *little* closer to finally fixing the horizontal line behind - the icon. It now works decently with common font sizes (in pixels). - -2002-06-05 Havoc Pennington - - * src/theme.c (meta_color_spec_new_from_string): parse - "shade/foo/factor" as a color - (colorize_pixbuf): remove the unused hsv_to_rgb and vice-versa - stuff, add the gtk_style_shade stuff. - (meta_color_spec_render): render the shaded color spec - - * src/theme.h (struct _MetaColorSpec): add "shade" mode to - MetaColorSpec. - -2002-06-04 Seth Nickell - - * src/metacity.desktop.in: - - Add X-GnomeWMSettingsLibrary to desktop file to support new - Window capplet. - -2002-06-04 Havoc Pennington - - * src/window.c (update_wm_hints): fix for how we read the input - hint, from Hidetoshi Tajima - - (meta_window_show): from Hidetoshi, don't autofocus windows with - input = FALSE wm_take_focus = FALSE when they first appear. We do - allow these windows to be focused (so keynav works), but they - don't get focused automatically. Now how do we keep them out of - the task list? - -2002-06-04 Gustavo GirÃ�¡ldez - - * src/theme.c (draw_op_as_pixbuf): Use icon's instead of image's - fill_type when type is META_DRAW_ICON. - -2002-06-03 Havoc Pennington - - * src/window.c (meta_window_new): don't automatically fullscreen - things opened fullscreen, because there's no GUI to un-fullscreen - them. - -2002-06-03 Havoc Pennington - - * src/theme-parser.c (parse_aspect_ratio): fix error message about - bad aspect ratio name. - -2002-06-03 Havoc Pennington - - * src/themes/Esco/metacity-theme-1.xml: test button aspect ratio - instead of hardcoded button size, James feel free to revert if you - don't like it this way. - - * src/theme-parser.c: parse the aspect_ratio element for button - aspect ratios. - - * src/theme.h (struct _MetaFrameLayout): allow button sizes to be - given as an aspect ratio derived from the titlebar height, - instead of as a fixed size. - - * src/theme.c (meta_frame_layout_validate): validate new button - sizing parameters - - * src/theme.c (meta_frame_layout_calc_geometry): use new button - layout params - -Mon Jun 3 15:12:11 2002 HideToshi Tajima - - * configure.in (METACITY_LIBS): put -lXext into SHAPE_LIBS - -2002-06-03 Kjartan Maraas - - * src/tools/metacity-properties.desktop.in: Someone forgot to mark - the two strings in here for translation :) - -2002-06-02 Havoc Pennington - - * configure.in: 2.3.610 - -2002-06-01 Havoc Pennington - - * src/frames.c (meta_frames_finalize): move the remove_listener - to finalize instead of destroy, thanks to Jayaraj for tracking - down the bug. - -2002-06-01 Havoc Pennington - - * src/session.c: add some missing \n - (meta_session_init): remove the #if 0 interact callback from our - initial SmcOpenConnection call, this arg to SmcOpenConnection - doesn't exist. - -2002-06-01 Havoc Pennington - - * src/session.c: put in more debug spew about the session - -2002-05-30 Havoc Pennington - - * src/Makefile.am (INCLUDES): use $(prefix)/@DATADIRNAME@/locale - for localedir to work with Solaris native gettext, patch from - Hidetoshi Tajima - - * src/tools/Makefile.am: ditto - -2002-05-31 Havoc Pennington - - * src/theme.c: add MetaImageFillType and implement TILE in - addition to the existing SCALE - - * src/theme.h (struct _MetaDrawOp): remove no-longer-used "alpha" - field - -2002-05-31 Havoc Pennington - - * src/theme.c (multiply_alpha): now just uses - meta_gradient_add_alpha - (draw_op_as_pixbuf): implement alpha gradients for tint, gradient, - and image draw ops, so I can implement garrett's stuff. - - * src/gradient.c (meta_gradient_add_alpha): new function to - multiply the alpha channel of a pixbuf by an alpha gradient - -2002-05-30 Havoc Pennington - - * src/main.c (main): verbose-log on startup whether we were - compiled with various extensions - - * src/display.c (meta_display_queue_retheme_all_windows): reapply - shape mask when changing themes, sucks to do it here though, makes - theme changing slower. Needs fixing. - - * src/theme-parser.c (parse_toplevel_element): parse rounded - corner options to frame_geometry - - * src/frames.c (meta_frames_apply_shapes): apply rounded corners - if requested by the theme - - * configure.in (HAVE_SHAPE): check for shape extension - -2002-05-30 Stephen Browne - - * src/tools/metacity-properties.c: - Some day I'll make all my changes in one commit :) - Needed to rip out code for adding icon to the dialog since it was - removed from teh galde file in my previous change. - -2002-05-30 Stephen Browne - - * src/tools/metacity-properties.glade: - Some UI changes demanded by Pat and Calum. - Make Close default response - Change mnemonic for Click so as not to clash with Close - -2002-05-30 Stephen Browne - - * src/tools/metacity-properties.glade: changed window title - to match other control center dialogs - -2002-05-29 Havoc Pennington - - * src/session.c (meta_session_init): improve error about failing - to open session manager. - (shutdown_cancelled_callback): send SmcSaveYourselfDone when we - get cancelled - (interact_callback): implement an interact callback that complains - about lame clients that can't be saved. Still somewhat buggy - in that it sends InteractDone before the user has closed the - dialog. - -2002-05-29 Havoc Pennington - - * src/tools/metacity-mag.c: add a magnifier I'm using when making - themes. Not installed. - - * src/tools/metacity-properties.c: reindentation, show window, add - copyright info. - - * src/tools/metacity-properties.glade: make main window !visible - on startup, to avoid funkiness. - -2002-05-29 Jacob Berkman - - * src/tools/Makefile.am (EXTRA_DIST): dist .desktop.in files - -2002-05-29 Stephen Browne - - New simple metacity-properties dialog to configure focus mode - and auto raise. - - * configure.in: added build support for metacity-properties - * src/tools/Makefile: more build stuff - * src/tools/metacity-properties.c: added these files - * src/tools/metacity-properties.glade: - * src/tools/metacity-properties.desktop.in: - * src/tools/metacity-properties.png: - -2002-05-29 Havoc Pennington - - * src/window.c (meta_window_move_resize_internal): add code to - also guess that client wants to come out of fullscreen, then - #if 0 the whole deal, I'm not sure it's such a good idea. - -2002-05-29 Havoc Pennington - - * src/window.c (meta_window_move_resize_internal): guess if a - window meant to be fullscreen, and if so put it in that state. - -2002-05-28 Havoc Pennington - - * src/window.c (redraw_icon): handle missing frame, prevents segv - with undecorated windows. #83298 - -2002-05-28 Havoc Pennington - - Patch from Erwann Chenede for raise_or_lower keybinding - - * src/display.c, src/common.h: POINT_IN_RECT moved to a common - location, removed from here - (meta_rectangle_intersect): move here and make it public - - * src/prefs.c: add raise_or_lower keybinding - - * src/stack.c (meta_stack_get_below, meta_stack_get_above): add an - arg to only get windows within the same layer - - * src/keybindings.c (handle_raise_or_lower): add handling for a - "raise window if obscured, else lower" keybinding - -2002-05-28 Havoc Pennington - - * src/window.c (meta_window_configure_request): handle CWStackMode - in configure requests - (meta_window_new): if a window is opened at 0,0 and screen size, - put it in the fullscreen state. - (meta_window_new): remove old code that set the window position to - 0,0 if PPosition/USPosition unset, that will be handled by whether - we place the window or not. - -2002-05-28 Abel Cheung - - * configure.in: Added "zh_TW" to ALL_LINGUAS. - -2002-05-27 Havoc Pennington - - * src/window.c (meta_window_new): search for the window's screen - by root window instead of Screen*, maybe it will help with - bug #82664 - -2002-05-27 Kjartan Maraas - - * autogen.sh: Hook up intltoolize here. - * configure.in: Initialize intltool. - * src/metacity.schemas.in: Add this. - * src/metacity.desktop.in: Add this too - * src/Makefile.am: Hook up intltool support for .schemas and .desktop. - * Makefile.am: Dist the intltool files. - -2002-05-27 Anders Carlsson - - * src/themes/Gorilla/metacity-theme-1.xml: Apparently someone - thinks my name is Anders Carlsom. Well, it's not. - (Thanks to Carl-Johan Kjellander for noticing.) - -2002-05-26 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Remove borders from - Esco theme as well (didn't know you could), apparently fixed - the problem where the spacing between the icon & the title - got larger as the fontsize went up. - -2002-05-26 Havoc Pennington - - * src/themes/Atlanta/metacity-theme-1.xml: totally drop the - borders off of maximized windows. - -2002-05-26 Havoc Pennington - - Patch from Gaute Lindkvist so you can't move the panel or desktop - to only one workspace. - - * src/keybindings.c (handle_move_to_workspace): don't allow moving - window to another space if the window is always_sticky - - * src/window.c (recalc_window_features): set the always_sticky - field for desktop/dock windows. - (meta_window_show_menu): disable unsticking always sticky windows - via the menus - - * src/menu.c (meta_window_menu_new): disable workspace items - if requested - -2002-05-26 Matthias Warkus - - * po/de.po: Added. - * configure.in: de added to ALL_LINGUAS - -2002-05-25 Erwann Chenede - - - * src/keybindings.c (rebuild_screen_binding_table, - rebuild_window_binding_table, - meta_change_keygrab): allow key grabbing for - unmodified keys (e.g F1, etc) fix #82630 - -2002-05-25 Anders Carlsson - - * src/place.c: (get_vertical_edges), (get_horizontal_edges): - Take Xinerama screen edges into consideration. - - * src/screen.c: (meta_rectangle_intersect), - (meta_screen_get_xinerama_for_window): - * src/screen.h: - Add a new function that returns the xinerama monitor that - a window is on. - -2002-05-24 Havoc Pennington - - * src/window.c (menu_callback): follow windows to their new - workspace - - * src/keybindings.c (handle_move_to_workspace): follow windows to - their new workspace - -2002-05-24 Havoc Pennington - - * src/metacity.schemas: add minimize window binding - - * src/keybindings.c (handle_minimize_window): add minimize keybinding - -2002-05-24 Havoc Pennington - - * src/window.c (meta_window_show): change how focusing windows - on initial map works, so that we only steal focus from our - transient parent or from a panel/desktop, never from other - normal windows. - -2002-05-24 Havoc Pennington - - * src/window.c (meta_window_configure_request): modify to ignore - PPosition and USPosition once the window has been placed - -2002-05-24 Anders Carlsson - - * src/window.c: Redraw the window frame when the icon changes. - Fixes #78543, reported by Kang Jeong-Hee. - -2002-05-23 Havoc Pennington - - * src/display.c (event_callback): also filter out LeaveNotify - with NotifyInferior - -2002-05-23 Jayaraj Rajappan - - * src/display.c (event_callback): fix for bugzilla bug #72314, - filter out LeaveNotify caused by grabs when in mouse focus mode. - -2002-05-23 Havoc Pennington - - * src/metacity.schemas: clean up the font preference - - * src/prefs.c: font pref - - * src/frames.c: pay attention to the font pref - -2002-05-23 Havoc Pennington - - Crack from Erwann - - * src/metacity.schemas: add autoraise crackrock - - * src/display.c (event_callback): autoraise window if autoraise is - enabled - - * src/prefs.c: autoraise crack - -2002-05-21 Havoc Pennington - - * src/window.c (constrain_position): fix positioning in fullscreen - mode, patch from Gustavo GirÃ�¡ldez - -2002-05-20 Alessio Frusciante - - * configure.in: Added Italian to ALL_LINGUAS. - -2002-05-20 Pablo Saratxaga - - * configure.in: Added Catalan (ca) and Azeri (az) to ALL_LINGUAS - -2002-05-17 Havoc Pennington - - * configure.in: 2.3.377 - -2002-05-16 Havoc Pennington - - * src/workspace.c (meta_workspace_get_neighbor): fix it, maybe - -2002-05-16 Havoc Pennington - - * src/window.c (constrain_position): lock desktop to position 0,0 - -2002-05-16 Havoc Pennington - - * src/window.c (meta_window_show): don't focus dock, desktop, - etc. windows on initial map, only windows that should have focus. - -2002-05-15 Havoc Pennington - - * src/workspace.c (meta_workspace_get_neighbor): use the layout - information to figure out up/down neighbors - - * src/display.c (event_callback): catch propertynotify on - _NET_DESKTOP_LAYOUT - - * src/screen.c (meta_screen_update_workspace_layout): keep track - of the layout of workspaces as set by the pager - -2002-05-15 James M. Cape - - * src/themes/Esco/metacity-theme-1.xml: Minor tweak to minimize - button. - -2002-05-14 Havoc Pennington - - * src/themes/Makefile.am (THEMES): add Esco theme from James Cape - -2002-05-12 Havoc Pennington - - * src/place.c (meta_window_place): move pposition/usposition - honoring code into here, instead of putting it in window.c. - Makes focusing new windows work, and cleans things up a bit. - #81585 - -2002-05-12 Havoc Pennington - - * src/main.c (main): turn on --g-fatal-warnings if - METACITY_G_FATAL_WARNINGS env variable is set. - -2002-05-11 Anders Carlsson - - * src/display.c: (find_tab_forward), (find_tab_backward), - (meta_display_get_tab_next): - * src/display.h: - * src/keybindings.c: (handle_tab_forward), (handle_focus_previous): - Add screen argument to meta_display_get_tab_next, since we only - want windows on the same screen to appear in the tab chain. - - * src/screen.c: (meta_screen_new): - Or the event mask with existing events since gtk+ may listen to - certain events and we don't want to disable those events. - - (meta_screen_ensure_tab_popup): - * src/tabpopup.c: (meta_ui_tab_popup_new): - * src/tabpopup.h: - Add a screen number argument to meta_ui_tab_popup_new so we - can position the popup on the correct screen. - -2002-05-11 Havoc Pennington - - * src/main.c: include locale.h, fix from Hidetoshi Tajima - - * src/window.c (meta_window_new): disable show desktop mode when a - new window is managed. - -2002-05-11 Havoc Pennington - - * src/fixedtip.c (meta_fixed_tip_show): keep the tooltip - on the screen horizontally, #76825 - - * src/window.c (meta_window_handle_mouse_grab_op_event): end grab - op _after_ doing the final update of the move or resize. - Hopefully I didn't have a reason for the order I was using before. - -2002-05-10 Havoc Pennington - - * src/tools/metacity-window-demo.c: add override redirect test - window - - * src/stack.c (raise_window_relative_to_managed_windows): new - function, used to avoid moving windows above override redirect - popup windows. - - * src/display.c (event_callback): don't lower panels on - LeaveNotify if they have focus, #70895 - -2002-05-10 Havoc Pennington - - * src/window.c (constrain_position): when maximizing/fullscreening - something with a grid, like a terminal, center it in the - maximization area in case it can't fill the whole area. - #70554 - - * src/main.c (main): use g_strerror() to get proper UTF-8. - -2002-05-10 Havoc Pennington - - * src/keybindings.c (reload_modmap): put LockMask into the - ignored_modifier_mask so that caps lock doesn't mess up - keybindings. - -2002-05-10 Havoc Pennington - - * src/window.c (meta_window_focus): if window is not mapped after - the calc_showing, don't focus it, it's probably on another - workspace or something. - -2002-05-09 Havoc Pennington - - * src/frames.c (show_tip_now): DefaultScreen() returns the screen - number not Screen* - - * src/frame.c (meta_frame_sync_to_window): immediately repaint - frame whenever we resize it, if we're inside a grab operation. - - * src/frames.c (meta_frames_repaint_frame): new function - - * src/window.c (meta_window_new): initialize window's colormap - (meta_window_notify_focus): install the colormap for a window when - it gets focus, uninstall on unfocus. - - * src/window.h (struct _MetaWindow): store window's colormap - - * src/display.c (event_callback): note changes to window colormap - - * src/frame.c (EVENT_MASK): add ColormapChangeMask - -2002-05-09 Havoc Pennington - - * src/display.c (event_callback): make Alt+button2 do a resize - -2002-05-08 Anders Carlsson - - * src/fixedtip.c (meta_fixed_tip_show): - #ifdef out call to gtk_window_set_screen, reported by - Erwann Chenede. - -2002-05-08 Anders Carlsson - - * configure.in: - * src/display.c: (meta_display_open): - * src/fixedtip.c: (meta_fixed_tip_show): - * src/fixedtip.h: - * src/frames.c: (meta_frames_new), (show_tip_now): - * src/frames.h: - * src/menu.c: (meta_window_menu_new): - * src/ui.c: (meta_ui_new): - Add multi-screen support. Also add patch by Erwann Chenede - to make tooltips appear on the correct screen. - -2002-05-07 Anders Carlsson - - * src/workspace.c (set_work_area_hint): Doh, only update - the tmp pointer when the screen matches. Fixes a segfault - when running with multiple screens. - - * src/display.c: (meta_display_open), (event_callback), - (meta_display_update_show_desktop_hint): - * src/display.h: - * src/screen.c: (set_supported_hint): - Fix atom name; it's _NET_SHOW_DESKTOP, not - _NET_WM_SHOW_DESKTOP. - - * src/frames.c: (meta_frames_unmanage_window): - Restore the mouse cursor to default when unmanaging a window. - -2002-05-06 Anders Carlsson - - * src/display.c: (set_utf8_string_hint): - Fix an off-by-one error. - - (meta_display_open), - (event_callback), (meta_display_update_show_desktop_hint), - (meta_display_show_desktop), (meta_display_unshow_desktop): - * src/display.h: - * src/screen.c: (set_supported_hint): - Add support for _NET_WM_SHOW_DESKTOP, both as a message and - as a root window property. - -2002-05-05 Havoc Pennington - - * src/window.c (meta_window_unminimize): on unminimize, queue - calc_showing on all transients - (meta_window_activate): on activate, unminimize all a window's - ancestors, not just the window itself. - - * src/workspace.c (set_work_area_hint): don't increment "tmp" by - 16 unsigned long, increment by 4 - - * src/window.c (meta_window_free): if a window isn't minimized, - restore its WM_STATE to NormalState instead of IconicState, - since IconicState on initial window map means that the window - should be minimized. - - * src/workspace.c (meta_workspace_invalidate_work_area): queue an - idle to recompute the work area hint. - (set_work_area_hint): we need 4*num_workspaces ints, not just - num_workspaces. - - * src/screen.c (meta_screen_new): add work_area_idle field, - handle it on screen shutdown - - * src/common.h (META_PRIORITY_PREFS_NOTIFY, - META_PRIORITY_WORK_AREA_HINT): define some idle priorities - - * src/window.c (meta_window_calc_showing): hide windows if - their parent window is minimized - (meta_window_minimize): also queue_calc_showing on all - transients of the window being minimized - - * src/place.c (constrain_placement): function to apply - placement-time-only constraints, such as "not off the left of the - screen" - (meta_window_place): put dialogs down a bit over their parent, - not right at the top. - (meta_window_place): when centering a dialog, center it - on the current xinerama screen, rather than the entire - screen. - - * src/screen.c (meta_screen_get_current_xinerama): new function, - but not implemented - -2002-05-04 Havoc Pennington - - * src/frames.c (meta_frames_paint_to_drawable): chop out the - portion of the region that's outside the screen. - - * src/core.c (meta_core_get_screen_size): new function - (meta_core_get_frame_extents): new function - -2002-05-04 Havoc Pennington - - * src/frames.c (meta_frames_init): disable automatic GTK double - buffering, since it resulted in gigantic backing pixmaps the size - of the whole screen. - (meta_frames_paint_to_drawable): change to take a region argument; - punch the client area out of the expose region, then iterate over - rectangles in the region and draw each, manually doing - begin_paint_rect. Results in 4 long thin backing pixmaps - per frame repaint, instead of one large backing pixmap. - Suggested by Owen. - -2002-05-05 Bastien Nocera - - * src/workspace.c: (meta_workspace_get_neighbor): - Wrap-around workspaces (ie. when on the last workspace, - "switch_to_workspace_right" goes back to the - first one) - -2002-05-05 Anders Carlsson - - * src/metacity.schemas: Fix a spelling error and change - switch_to_workspace_up and switch_to_workspace_down to use - Ctrl+Alt since Nautilus uses Alt now. - -2002-05-04 Havoc Pennington - - * src/window.c (update_net_wm_type): correctly print things if the - type_atom is unset - (meta_window_new): with workarounds disabled, always allow - self-placement for windows with PPosition or USPosition set. - -2002-05-03 Havoc Pennington - - * src/Makefile.am: fix for automake 1.5, patch from Tomasz Kloczko - -2002-05-03 Laszlo Peter - - * configure.in: add the X libs to METACITY_MESSAGE_LIBS and - METACITY_WINDOW_DEMO_LIBS - -2002-05-02 Havoc Pennington - - * README: updates - - * configure.in: 2.3.233 - -2002-05-02 Bastien Nocera - - * src/metacity.schemas: change the default for switch_to_workspace_* - to be arrow as just arrow collides with some apps - (especially web browsers) - -2002-05-01 Havoc Pennington - - * src/screen.c (meta_screen_new): Xlib doesn't like NULL for out - arguments; fix for #80472 from lbedford - -2002-04-30 Havoc Pennington - - * src/keybindings.c: finish mopping up mode_switch_mask field - - * src/display.h (struct _MetaDisplay): remove mode_switch_mask - field - -2002-04-30 Havoc Pennington - - * src/window.c (recalc_window_features): don't try to decorate - toolbars. - - * src/tools/metacity-window-demo.c: add menu and toolbar tests - - * src/place.c (meta_window_place): only dialogs should be centered - over parent, not anything with transient for set. - - * src/window.c (meta_window_configure_request): become more - fascist about window positioning if workarounds are disabled, and - less fascist if they are enabled. - - * src/metacity.schemas: add a "disable_workarounds" option. Kind - of crack-smoking. But we just can't get all applications - fixed. And I need no-workarounds mode to monitor which apps are - broken and what needs fixing in specs. - - * src/window.c (meta_window_configure_request): always allow - windows to resize themselves - - * src/keybindings.c (reload_modmap): don't filter out Mode_switch, - apparently some people bind window manager shortcuts to that. - -2002-04-30 Havoc Pennington - - * src/window.c (constrain_position): oops, fix - maximization. Pointed out by Gustavo GirÃ�¡ldez - -Tue Apr 30 06:24:09 2002 Jonathan Blandford - - * src/menu.c: give Maximize/Unmaximize and Shade/Unshade the same - mnemonic for consistency's sake. - -2002-04-29 Havoc Pennington - - * src/window.c (TITLEBAR_LENGTH_ONSCREEN): require 36 pixels - onscreen so you typically get a sliver of titlebar, suggested by - tigert. Should still fix this to consider actual theme geometry. - (constrain_position): change to allow movement off the left - -2002-04-29 Havoc Pennington - - * src/display.c (event_callback): always raise windows on focus - click, regardless of focus mode. - -2002-04-29 Havoc Pennington - - * configure.in: 2.3.144 - -2002-04-29 Havoc Pennington - - * src/ui.c (meta_ui_init): don't leak the PangoContext - -2002-04-28 Anders Carlsson - - * src/display.c: (meta_display_open): - * src/display.h: - * src/screen.c: (set_supported_hint): - * src/workspace.c: (set_number_of_spaces_hint), - (set_workarea_hint): - Add support for setting the _NET_WM_WORKAREA hint. No code - does it yet though. - -2002-04-28 Havoc Pennington - - * README: remove caveats about keybindings - - * src/metacity.schemas: add schemas for all the keybindings. - - * src/window.c (meta_window_activate): if in "show desktop" mode - when a window is activated, leave show desktop mode. So e.g. - when you click on a task in the task list, show desktop mode - will be turned off. - - * src/workspace.c (meta_workspace_get_neighbor): new function - that doesn't quite work yet (needs support for getting - workspace layout from the pager) - - * src/prefs.c: keybindings stuff - - * src/keybindings.c: make keybindings configurable - - * src/ui.c (meta_ui_parse_accelerator): new function - -2002-04-25 Havoc Pennington - - * metacity.spec: fix to install gconf schemas - -2002-04-25 jacob berkman - - * src/session.c (load_state): g_file_get_contents() takes a gsize - not int (fixes bus error on 64-bit platforms) - -2002-04-22 Havoc Pennington - - * src/main.c (main): call setlocale ourselves because due to a - GLib bug that sticks us in ASCII if you call g_print or anything - prior to setlocale, and print a warning if we don't set the locale - successfully. #79280 - - * src/workspace.c (meta_workspace_get_work_area): be more verbose - about how the work area was computed, to help find bugs here. - - * src/main.c (main): put locale and codeset in the log file - -2002-04-21 Havoc Pennington - - * src/window.c (meta_window_send_icccm_message): add error trap, - fixes a possible BadWindow if a window closed itself in response - to the delete window message prior to us sending the ping message. - -2002-04-21 Havoc Pennington - - * src/window.c (meta_window_move_resize_now): never revert to - user_rect.width, user_rect.height. Maybe fixes assorted resize - screwups e.g. with gnome-terminal. - -2002-04-21 Anders Carlsson - - * src/iconcache.c (scaled_from_pixdata): Add padding if - icon width and height differ. - -2002-04-17 Havoc Pennington - - * src/screen.c (meta_screen_new): query Xinerama screen - information if HAVE_XINERAMA - - * configure.in (found_xinerama): check for Xinerama - -2002-04-17 Changwoo Ryu - - * configure.in (ALL_LINGUAS): Added ko (Korean). - -2002-04-16 Akira TAGOH - - * configure.in (ALL_LINGUAS): add ja.po entry. - -2002-04-15 Havoc Pennington - - * src/window.c (update_title): fix issue with GNU libc - mangling %.10s format - - * metacity.spec: Fix up spec file - - * README: update README - - * configure.in (ALL_LINGUAS): require GTK 2.0.0 - -2002-04-15 Havoc Pennington - - * src/display.c (meta_display_ping_window): reply immediately for - windows that don't support _NET_WM_PING - - * src/window.c (update_protocols): check whether windows - support _NET_WM_PING - -2002-04-13 Havoc Pennington - - * src/ui.c (get_cmap): same fix as libwnck, avoid using cmap - with the wrong depth - -2002-04-13 Havoc Pennington - - * src/delete.c: new file containing all the - wacky mess I just added to a simple "click the close button", - contains all the dealing-with-dead-application cruft. - Use metacity-window-demo to test by clicking the - toolbar button that locks it up. - -2002-04-12 Havoc Pennington - - * src/tools/metacity-window-demo.c (do_appwindow): make one of the - toolbar buttons lock up the demo - - * src/window.c (meta_window_delete): move error trap to be around - a narrower part of the function, and add part of the ping stuff, - nothing user-visible yet - - * src/metacity-dialog.c (main): metacity-dialog executable to - live in libexecdir and pop up dialogs for us. - -2002-04-09 Havoc Pennington - - * src/theme.c (multiply_alpha): fix alpha multiplication routine - to perhaps work correctly, reported by tigert. Also, be sure - we always copy the image if necessary before modifying the - alpha channel. - -2002-04-05 Havoc Pennington - - * src/stack.c: remove the unused tab stuff - - * src/display.c: implement tab list among panels - - * src/keybindings.c: fill in move-between-panels keybindings - -2002-03-31 Johan Dahlin - - * src/menu.c (meta_window_menu_new): Make sure all menu items are - translated. - -2002-03-27 Havoc Pennington - - * src/window.c (meta_window_free): remove - unmanaged windows from save set, and unselect - input so we don't get events from them. Fixes annoying - bug where withdrawn windows would decide to map themselves - due to save set stuff. - -2002-03-22 Zbigniew Chyla - - * configure.in (ALL_LINGUAS): Added pl (Polish). - -2002-03-21 Havoc Pennington - - * src/themes/Bright/metacity-theme-1.xml: Added "Bright" theme - from Gaute Lindkvist, with some small clipping tweaks to keep - text/icons from overlapping their frames. - -2002-03-19 Havoc Pennington - - * src/resizepopup.c (place_vertical_size_window) - (place_horizontal_size_window): disable the little shaped windows - with the window size, they caused a crash anytime you tried to - resize with Xft. And they were kind of on crack anyway. - -2002-03-17 Havoc Pennington - - * src/resizepopup.c (ensure_tick_windows): turn off the tick - marks, that got annoying after about 5 minutes. One big shape - window instead of lots of little windows might fix it. - -2002-03-17 Havoc Pennington - - * src/resizepopup.c: Add some total crackrock resize-grid - indication for windows that have width_inc/height_inc - so I can debug gnome-terminal sizing. - -2002-03-17 Havoc Pennington - - * src/session.c (set_clone_restart_commands): use proper property - name for SmDiscardCommand (instead of setting the clone command to - "rm"). Also fix typo that iterated over clonev not discardv to - fill in prop list, and NULL-terminate discardv. #74584 from Kang - Jeong-Hee. - -2002-03-13 Havoc Pennington - - * src/main.c (main): put back --sm-client-id argument, needed - for including us in a default session - -2002-03-13 Havoc Pennington - - * src/session.c (meta_session_init): don't save a file here, only - in response to SaveYourself. Change the code to properly use a - unique state file for each SaveYourself. Totally, totally - untested. - -2002-03-12 Havoc Pennington - - * src/theme-viewer.c: improve the theme viewer so people - can see the broken aspects of their themes. - -2002-03-11 Havoc Pennington - - * src/keybindings.c: use new functions - - * src/display.c (meta_display_get_tab_next): - (meta_display_get_tab_list): new tab order functions using - MRU list instead of map order - - * src/window.c (meta_window_notify_focus): maintain focus MRU list - - * src/display.h (struct _MetaDisplay): Keep an MRU list of - windows. - -2002-03-10 Havoc Pennington - - * src/display.c (event_callback): support _NET_NUMBER_OF_DESKTOPS - message so you can change number of desktops with the pager - - * src/prefs.c (meta_prefs_set_num_workspaces): new function - - * src/display.c (meta_spew_event): print stacking aspects of - configure requests - -2002-03-10 Havoc Pennington - - * src/screen.c (set_supported_hint): we didn't claim to support - _NET_ACTIVE_WINDOW so gtk_window_present() didn't work. Mumble. - Only worked with tasklist because libwnck didn't check for - WM support. - - * src/window.c (meta_window_free): clean off window state - when windows are withdrawn, to avoid sticking dialogs - to their initial desktop. - (meta_window_queue_calc_showing): return if window is withdrawn - -2002-03-08 Laszlo Peter - - * configure.in: fix the X linker flags - -2002-03-06 Havoc Pennington - - * src/core.c (meta_core_get_grab_frame): add some assertions - - * src/menu.c (meta_window_menu_new): make another warning - into a verbose - - * src/display.c (meta_change_button_grab): use verbose rather than - warning to log failures to grab button, since these are typically - BadWindow from a destroyed window. - -2002-03-06 Havoc Pennington - - * src/frames.c (meta_frames_manage_window): use hash_table_replace - instead of g_hash_table_insert - - * src/main.c (main): only enable verbose/debug if you set - METACITY_VERBOSE/METACITY_DEBUG - - * src/util.c (ensure_logfile): only use a log file if - METACITY_USE_LOGFILE is set - - * src/display.c (meta_display_for_x_display): add warning if - MetaDisplay isn't found - - * src/window.c (meta_window_free): add an assertion that we - successfully cleared the grab window - -2002-03-05 Havoc Pennington - - Work on opaque animations more, still suck too much - to turn on. Not sure how to make them good. - - * src/effects.c (meta_effects_draw_box_animation): - add a slide-up mode for shading - - * src/ui.c (meta_image_window_set): change image window to work by - setting back pixmap on the GtkWindow, instead of using GtkImage. - -2002-03-04 Havoc Pennington - - * src/main.c (main): try ignoring SIGXFSZ, though I'm not - sure what that does exactly. I'm hoping it gives me EFBIG. - - * src/util.c (ensure_logfile): log to a file in /tmp instead - of to ~/metacity.log. - -2002-03-04 Havoc Pennington - - * configure.in: fix configure.in since GTK no longer gives us - -L/usr/X11R6/lib - -2002-03-03 Havoc Pennington - - * src/window.c: improve debug spew about initial workspace - -2002-03-02 Havoc Pennington - - * src/window.c (recalc_window_features): disable resize etc. if - we're fullscreen - (constrain_size): fix size constraints when fullscreen - - * src/display.c (meta_display_open): fix missing comma that - ended up concatenating two of the properties breaking - FULLSCREEN state and PING protocol - -2002-03-02 Havoc Pennington - - * src/display.c: Add hacking to fix the problem that we made our - XGrabPointer() during Alt+Tab actually succeed, so on popping down - Alt+Tab we got an EnterNotify from the ungrab, which resulted in - focusing the window under the mouse. i.e. Alt+Tab didn't work with - sloppy focus. - -2002-02-26 Havoc Pennington - - Screw around with Anders's ping patch so he'll get plenty of CVS - conflicts. ;-) - - * src/display.c (meta_display_ping_window): spew warnings - if we try to call this with CurrentTime - (meta_display_ping_timeout): remove ping from the pending pings - after it times out. - - * src/util.h: added PING debug category - - * src/display.c (remove_pending_pings_for_window): don't remove - "tmp" just before "tmp->next", don't break out of loop after - finding the first match - (meta_display_open): no trailing comma in array init - (event_callback): move the processing of ping replies into a - separate function - - * src/screen.c (set_supported_hint): add _NET_WM_PING to supported - list - - * src/display.h: change gpointer to void* - -2002-02-26 Anders Carlsson - - * src/display.c: (ping_data_free), - (remove_pending_pings_for_window), (meta_display_open), - (event_callback), (meta_display_unregister_x_window), - (meta_display_ping_timeout), (meta_display_ping_window), - (meta_display_window_has_pending_pings): - Implement meta_display_ping_window, and filter out scroll wheel - events. - - * src/display.h: - Add MetaWindowPingFunc, meta_display_ping_window and - meta_display_window_has_pending_pings. - -2002-02-24 Havoc Pennington - - * src/display.c (xcursor_for_op): switch on the op passed in, not - the active op. Gives us the right cursor during resizing, etc. - - * src/errors.c: rearrange all the error stuff to adapt to the GDK - change a while back, so now we print our X errors again - - * src/display.c (meta_display_begin_grab_op): remove KeyPressMask - and KeyReleaseMask from the XGrabPointer(), this caused BadValue - and kept the grab from ever succeeding. Fixes the problem with the - GTK resize grip - this is why you shouldn't break your X error - spew. ;-) - - * src/display.c: debug spew tweaks - - * src/window.c (meta_window_client_message): do some - s/verbose/topic/ stuff - -2002-02-23 Havoc Pennington - - * src/ui.c (meta_ui_init): fix the - be-sure-we-create-coverage-cache hack - -2002-02-19 Havoc Pennington - - * src/ui.c (meta_ui_init): put in hack to keep Pango from mangling - our server grab and locking up on startup. (hack doesn't work - but I want to fix it on my real computer not this laptop) - - * src/window.c: Implement _NET_WM_STATE_FULLSCREEN - - * src/display.c (meta_display_open): add atoms for - _NET_WM_STATE_FULLSCREEN - -2002-02-16 Kjartan Maraas - - * src/main.c: Use bind_textdomain_codeset etc. - -2002-02-14 Havoc Pennington - - * src/theme-viewer.c: use the preview widget here - - * src/preview-widget.h, src/preview-widget.c: make the theme - preview into a nice widget - - * src/frames.c (meta_frames_ensure_layout): replace frame layout - if the frame style changes, this only ends up mattering if you - e.g. changed the font size for windows in a different state such - as maximized, which is crack, but the code may as well be correct - - * src/theme.c (meta_theme_get_frame_style): new function so we can - detect an invalid cache of the PangoLayout in a frame - -2002-02-14 Anders Carlsson - - * src/themes/Crux/metacity-theme-1.xml: Fix some bugs with - prelighting. - -2002-02-13 Anders Carlsson - - * src/theme.c (meta_pango_font_desc_get_text_height): Use - pango_context_get_metrics instead of loading the font. - -2002-02-12 Anders Carlsson - - * src/frames.c (meta_frames_manage_window): Set prelit_control - to META_FRAME_CONTROL_NONE. - (meta_frames_update_prelit_control): New function for setting - the prelit control. - (meta_frames_paint_to_drawable): Set prelight state. - (meta_frames_enter_notify_event): Update prelit control. - (meta_frames_leave_notify_event): Likewise. - (meta_frames_motion_notify_event): Likewise. - - * src/frames.h (struct _MetaUIFrame): add prelit_control. - - * src/window.c (update_mwm_hints): and MWM_FUNC_ALL - with hints->functions instead of hints->flags. - -2002-02-11 Anders Carlsson - - * src/theme.c (meta_frame_layout_new): Set title_scale to 1.0 - -2002-02-11 Bastien Nocera - - * src/theme-viewer.c: (main): change default theme to be Atlanta - like in the .schema file - -2002-02-10 Havoc Pennington - - * src/tools/Makefile.am (EXTRA_DIST): add $(icon_DATA) - - * configure.in: 2.3.55 - - * HACKING: update - - * README: update - -2002-02-09 Havoc Pennington - - * src/theme.c (meta_theme_set_current): add a newline to an error - message - - * src/themes/Gorilla: add Gorilla theme by Jakub Steiner ported to - metacity by Kenneth Christiansen - -2002-02-09 Havoc Pennington - - * src/theme.c (meta_draw_op_draw_with_env): implement wacky "tile" - draw op to lose some of the PNG files in Gorilla theme - - * src/theme-parser.c: parse the tile primitive - -2002-02-09 Havoc Pennington - - * src/window.c (update_icon): port to icon cache - - * src/iconcache.c, src/iconcache.c: begin process of cleaning up - window.c by moving the icon-reading code in here, based on the - code in libwnck, which was in turn based on the earlier metacity - code - -2002-02-09 Havoc Pennington - - * src/stack.c (meta_stack_sync_to_server): hmm, and don't set - last_window at all if we don't ++newp. Fixes even more obscure - stacking bug. - -2002-02-09 Havoc Pennington - - * src/stack.c (meta_stack_sync_to_server): assign last_window - prior to ++newp, so we don't try to stack windows with respect to - themselves. Fixes some obscure stacking bugs. - -2002-02-09 Havoc Pennington - - * src/theme-parser.c: try to make more error message strings the - same, easier for translators - - * src/theme.c (meta_draw_op_free): free color spec for line op - (meta_theme_free): free the integer_constants hash - - * src/theme-parser.c (parse_boolean): move above first use - - * src/theme-viewer.c: fixes for theme.h changes - - * src/frames.c (queue_recalc_func): don't recreate layout - immediately, just save title text. should speed things up. - (meta_frames_set_title): just remove the layout here also, - and save title text. - - * src/theme-parser.c (parse_toplevel_element): parse title_scale - attribute on frame_geometry - - * src/theme.c: support setting the text size - - * src/frames.c: support setting the text size - - * theme-format.txt: updates - -2002-02-09 Havoc Pennington - - * src/themes/Atlanta/metacity-theme-1.xml: put in some kind of - distinctive frame for UTILITY, though it's ugly. Also put in the - borderless look for maximized windows. - - * src/stack.c (compute_layer): put splash screen in the splash - layer - - * src/stack.h (enum): create a splash screen layer - - * src/place.c (meta_window_place): center splashscreen, and fix a - typo in the centering code - - * src/window.c (recalc_window_features): disable most features on - splash screens - - * src/screen.c (set_supported_hint): add UTILITY and SPLASHSCREEN - hints - - * src/window.c: add UTILITY, SPLASHSCREEN implementation - - * src/window.h (enum): add UTILITY, SPLASHSCREEN types - - * src/theme-parser.c (parse_toplevel_element): parser support - for has_title attribute - - * src/theme.c (meta_frame_layout_get_borders): handle a has_title - field in the layout, for utility windows that don't display a - title (would be better to be able to shrink the title text, - but that's kind of tricky to implement :-/) - -2002-02-08 Havoc Pennington - - * src/screen.c (set_supported_hint): add _NET_WM_STATE_HIDDEN - to _NET_SUPPORTED - - * src/keybindings.c (meta_set_keybindings_disabled): put in header - file, to fix warning. - - * src/display.c (meta_display_open): add _NET_WM_STATE_HIDDEN atom - - * src/window.c (set_net_wm_state): set _NET_WM_STATE_HIDDEN for - shaded and minimized windows - (meta_window_show): call set_net_wm_state() if we map the window - or frame - (meta_window_hide): call set_net_wm_state() if we unmap the window - or frame - -2002-02-08 Havoc Pennington - - * src/window.c (set_net_wm_state): only set skip pager/tasklist if - the app set it, don't set it again based on semantic type. - -2002-02-08 Anders Carlsson - - * src/theme.c (scale_and_alpha_pixbuf): If we're only - scaling horizontally or vertically, use GDK_INTERP_NEAREST. - -2002-02-08 Havoc Pennington - - * autogen.sh: unbreak - -2002-02-08 Havoc Pennington - - * src/display.c (meta_display_grab_focus_window_button): grab - buttons 2 and 3 also, so you can focus a window with those, - #70840 - (event_callback): fix this to let you focus a window with any - unmodified click, and also with Alt+button1 - - * configure.in (AC_OUTPUT): add po/Makefile.in - - * autogen.sh: port to glib-gettextize, remove stupid - auto-find-subdirs crap - - * Makefile.am (SUBDIRS): add po to subdirs, #70615 - - * src/window.c (meta_window_activate): unshaded window if shaded, - I thought this was in bugzilla but I don't see it. anyway thanks - whoever mentioned it to me. - -2002-02-08 Havoc Pennington - - * src/tools/metacity-window-demo.c (menu_items): add modal dialog test - -2002-02-08 Havoc Pennington - - * src/window.c (meta_window_show): when mapping a window with - struts, invalidate the work areas it's on. Should fix at least - part of the problem with windows maximizing over panels. - - * src/workspace.c (meta_workspace_invalidate_work_area): also - queue move/resize on sticky windows - - * src/tools/Makefile.am: consolidate reload-theme, restart into a - "metacity-message" app and add enable/disable keybindings to the - messages it knows about. - - * src/keybindings.c: - (meta_change_keygrab): grab keyboard synchronously - (meta_display_process_key_event): if all keybindings are toggled - off, ReplayKeyboard, else AsyncKeyboard, except that the debug - binding for toggling back on is always processed - (meta_set_keybindings_disabled): function to disable/enable - all keybindings - -2002-02-07 Havoc Pennington - - * src/run-metacity.sh: if DEMO_TEST is set then run the window - demo - - * src/tools/metacity-window-demo.c: Create an app with all the - semantic window types, for testing and for designing themes. - -2002-02-07 Havoc Pennington - - Throughout: move to meta_topic rather than meta_verbose so - metacity.log can start being more useful - - * src/util.h (enum): add more debug topics - - * src/frames.c: clean up some cruft that caused warnings - -2002-02-07 Havoc Pennington - - * src/theme.c (colorize_pixbuf): do random voodoo on the algorithm - -2002-02-07 Havoc Pennington - - * src/theme.c (colorize_pixbuf): use the intensity of the gray - pixel for both saturation and value, not just value. - -2002-02-07 Havoc Pennington - - * src/theme.c (INTENSITY): don't define the macro twice - -2002-02-07 Havoc Pennington - - * src/theme.c (colorize_pixbuf): get algorithm right (use HSV/RGB - conversion) at cost of making it a lot slower. It doesn't matter - anyhow with the cache, though. - -2002-02-06 Havoc Pennington - - * src/theme.c (colorize_pixbuf): handle out-of-memory creating - target pixbuf - - * src/themes/Crux/*.png: convert the green-channel images to grayscale - -2002-02-06 Havoc Pennington - - * src/prefs.c (change_notify): s/update_focus_mode/update_theme/ - in case of theme key changing - -2002-02-06 Havoc Pennington - - * src/theme-viewer.c: benchmark theme on startup - - * src/theme-parser.c (parse_draw_op_element): fix "colorize != - NULL" to "colorize_spec != NULL" and free pixbuf on color spec - failure - - * src/theme.c (colorize_pixbuf): minor reformatting, raise - function calls out of inner loop, clamp r/g/b values to uchar - range before assigning to uchar - (draw_op_as_pixbuf): cache the colorized pixbuf - (meta_draw_op_free): free the cache pixbuf - -2002-02-07 Anders Carlsson - - * src/theme-parser.c: (parse_draw_op_element): - Add support for "colorize" image attribute. - - * src/theme.c: (colorize_pixbuf): - New function that colorizes a pixbuf. - - (pos_tokenize): Allow "\n" as a whitespace character. - - (meta_draw_op_free): Free colorize_spec; - - (draw_op_as_pixbuf): Colorize image if needed. - - * src/theme.h: Add colorize_spec to struct. - -2002-02-07 Anders Carlsson - - * src/themes/Crux/metacity-theme-1.xml: Add maximized and - shaded_and_maximized frame styles. - -2002-02-06 Havoc Pennington - - * src/main.c (prefs_changed_callback): redo window - sizes/appearance when the theme changes - - * src/display.c (meta_display_retheme_all): new function - - * src/theme-parser.c (locate_attributes): remove error handling - for MAX_ATTRS reached, add an assert instead, the way this code - ended up the attrs in the array depend on the code not the theme - file. - -2002-02-06 Havoc Pennington - - * src/main.c (main): disable custom log handler and fatal mask for - now - - * src/theme.c (meta_draw_op_list_draw): - Add META_DRAW_CLIP - - * src/main.c: load theme, monitor current theme setting - - * src/prefs.c: add "current theme" setting - - * src/stack.c (meta_stack_free): don't try to free - last_root_children_stacked if it doesn't exist - - * src/themewidget.c: pluggable GtkMisc subclass to use - for menu icons - - * src/screen.c (meta_screen_manage_all_windows): fix - signed/unsigned warning - - * src/frames.c: port to theme system - (meta_frames_style_set): chain up - - * theme-format.txt: new file - - * configure.in: add more compiler warnings - - * src/theme.c: add various stuff needed to get theme parser - working. Remove the "spacer" concept from FrameLayout object. - Add draw op that references a draw op list. - - * configure.in: require GTK 1.3.13 - - * src/Makefile.am: add theme-parser.[hc], implement loading a - theme - - * src/theme.c: add "draw title" and "draw window icon" operations - (meta_draw_op_draw): put object_width/object_height in expression - environment before computing x/y. Handle out-of-memory when - creating pixbufs. Assorted other cleanups. - -2002-02-07 Anders Carlsson - - * src/themes/Crux/metacity-theme-1.xml: - Simplify things so we can remove some - now unnecessary .png files. - * src/themes/Crux/*.png: Remove some files. - -2002-02-07 Anders Carlsson - - * src/themes/Crux/metacity-theme-1.xml - * src/themes/Crux/*.png: - Add Crux theme - -2002-02-07 Kenneth Rohde Christiansen - - * configure.in: add da to ALL_LINGUAS - * po/da.po: add Danish translation - -2002-02-02 Havoc Pennington - - * src/theme-viewer.c: test % operator - - * src/theme.c (pos_tokenize): add % to switch for operators - - * src/theme.c: rework theme stuff so we have - MetaDrawOp/MetaDrawOpList instead of MetaTextureSpec/MetaShapeSpec - -2002-01-28 Havoc Pennington - - * src/theme.c (meta_texture_spec_render): fix shadowed variable - (stupid -Wall should have that) - - * src/theme-viewer.c (main): implement a simple - viewer for frame styles - - * src/theme.c (meta_frame_style_get_test): create partial - frame style to test drawing - -2002-01-27 Havoc Pennington - - * src/theme.c (meta_shape_spec_draw): implement - (meta_texture_spec_draw): implement shape spec and blank - texture support - (meta_frame_style_draw): implement - -2002-01-27 Havoc Pennington - - * src/display.c (meta_set_syncing): move in here so util.c doesn't - require display.[hc] - - * src/theme.h, src/theme.c: implement coordinate expression - parser, write MetaShapeSpec declaration - - * src/util.c (meta_exit): move in here so we can link - to util.c with a different main() - - * src/theme.h: rename the MetaWindow* enums to MetaFrame* - -2002-01-27 Peteris Krisjanis - - * configure.in - Added lv to ALL_LINGUAS - -2002-01-27 Havoc Pennington - - * src/frames.c (get_control): Only consider the bottom of the - titlebar a resize control; I keep accidentally resizing windows - instead of activating them. Also, give south resizing priority - over north, if the window is so small the active regions overlap - - * src/theme.c: add MetaTheme, get MetaFrameStyleSet into - a usable state - - * src/common.h: move window type back to window.h, decided - not to use it on frame side - (MetaFrameType): add this instead - -2002-01-27 Havoc Pennington - - * src/theme.h, src/theme.c: implement all kinds of crazy - compositing-one-texture-onto-another BS. - -2002-01-27 Havoc Pennington - - * src/display.c (event_callback): make the check for whether to - eat focus click a lot more complicated - - * src/window.c (meta_window_same_application): new function - - * src/prefs.h, src/prefs.c: add application based pref - - * src/metacity.schemas: add "application_based" setting to - give me a mode to fool with being application based, - without being unusable in the meantime. Yeah the crack flows - freely these days. Everyone knew it would happen. - -2002-01-27 Havoc Pennington - - * src/frames.c: separate code to draw frame from the - expose_event handler, so in principle we can draw the - frame to a pixmap, but this isn't used yet. - -2002-01-22 Hasbullah Bin Pit - - * configure.in: Added Malay (ms)to ALL_LINGUAS. - * po/ms.po: Added Malay Translation. - -2002-01-19 Havoc Pennington - - * src/wm-tester/test-resizing.c: cheesy client with static - bit gravity, used to test the below change. - - * src/window.c (meta_window_move_resize_internal): implement - Owen's proposal for window resizing. - http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html - - Currently you have to do METACITY_USE_STATIC_GRAVITY=1 in order to - use it, because some GDK bug is screwing up exposes on my frames - when it's enabled. - - * src/display.c (meta_display_create_x_cursor): fix glyph for - NE/NW cursors - - * src/frames.c (get_control): add ability to resize from top - - * src/frame.c (meta_frame_get_flags): can't resize shaded windows - (meta_frame_sync_to_window): add gravity arg - - * src/common.h (MetaWindowType): move here from window.h so - it can be used in themes stuff. - (MetaFrameFlags): remove META_FRAME_TRANSIENT since it - overlaps with window type and was unused. - -2002-01-18 Havoc Pennington - - * src/window.c (constrain_position): give priority to keeping NW - corner onscreen rather than SE, if we need to shift the window - to fit inside constraints - - * src/frames.c (meta_frames_get_geometry): don't depend on the - current window size - - * src/theme.c: move geometry stuff in here, to be calculated as - part of the theme - - * src/core.c (meta_core_get_client_size): new function to replace - meta_core_get_frame_size() so we don't have weird cycles - in the geometry calculation - -2002-01-12 Havoc Pennington - - * src/window.c (meta_window_queue_move_resize): make this actually - queue, rather than being synchronous as it was before. We'll see - what breaks. Should be more efficient and reduce flickery stuff a - bit in some cases. - -2002-01-15 Havoc Pennington - - * src/keybindings.c (handle_tab_backward): fix crash - when grab failed due to another operation in progress - (handle_tab_forward): fix crash when grab failed - -2002-01-10 Havoc Pennington - - * src/frame.c (meta_window_destroy_frame): only bump - unmaps_pending if the window was mapped - (meta_window_ensure_frame): ditto - - * src/keybindings.c: change arrow key bindings to use Ctrl+Alt not - just Alt, and add debug mode key bindings - - * src/stack.c (meta_stack_get_default_focus_window): don't choose - a default focus window with unmaps pending, since we probably just - unmapped it. - - * src/display.c (event_callback): move notify_focus on UnmapNotify - after the window_free check, so we can move focus to another - window when we unmanage - - * src/window.c (meta_window_hide): invalidate work areas when - hiding a window with struts - (meta_window_free): invalidate work areas when unmanaging a window - with struts - -2002-01-09 Havoc Pennington - - * src/window.c, src/window.h: store strut information, - update it on property changes, etc. etc. so we avoid panel - on maximize. - - * src/workspace.c (meta_workspace_get_work_area): add accessor for - work area so we can compute it lazily - - * src/display.h, src/display.c: add _NET_WM_STRUT atom - and _WIN_HINTS atom - -2002-01-08 Havoc Pennington - - * configure.in (ACLOCAL): add code to save ACLOCAL_FLAGS - - * src/frames.c (meta_frames_expose_event): max dither - - * src/testgradient.c (render_simple): change dither mode to MAX - to avoid banding - - * src/theme.c: lose the gradient cache, and put in some initial - data types for the theme format - -2002-01-07 Havoc Pennington - - * src/frames.c (meta_frames_expose_event): make gradient a bit - more subtle (don't go to the full background, but to a blend of - selection and background; put lighter color on top) - -2002-01-06 Havoc Pennington - - * src/window.c (meta_window_notify_focus): rearrange code a bit to - make it clear that has_focus flag always follows - display->focus_window - -2002-01-06 Havoc Pennington - - * src/window.c (meta_window_notify_focus): put in attempted fix - for the GTK 1.2 plug/socket screwup, now that my fixed debug spew - reveals what's actually happening. ;-) - - * src/gradient.c (meta_gradient_description_new): object - to store gradient descriptions - - * src/window.c (meta_window_notify_focus): fix the debug spew - that was confusing me - - * src/wm-tester/focus-window.c: add little program to focus - a window ID - -2002-01-06 Havoc Pennington - - * src/theme.c (meta_theme_get_gradient): change to use spiffy - gradient code. - - * src/gradient.c: copy lovely gradient code from WindowMaker, - as usual Dan and Alfredo have very nice code - -2002-01-06 Fatih Demir - - * configure.in: Added "tr" to the languages list. - -2002-01-05 Havoc Pennington - - * src/frames.c (meta_frames_expose_event): draw titlebar highlight - with snazzy gradient that needs some tweaking to be less - dumb-looking - - * src/theme.c: replace old theme.[hc] contents with newer stuff - that doesn't do anything - -2002-01-05 Havoc Pennington - - GTK 1.2 plug/socket clients still broken, don't know why. - - * src/screen.c (meta_screen_new): select focus change on root - window, for debugging - - * src/display.c (event_callback): when unfocusing, use - no_focus_window to hold the focus - - * src/display.h (struct _MetaDisplay): have a no_focus_window to - hold the focus when we don't want to have anything focused. - Then we can avoid confusing focusing-the-frame stuff. - - * src/window.c (meta_window_notify_focus): improve some debug spew - (meta_window_notify_focus): add hack from WindowMaker to ignore - focus in events with detail > NotifyNonlinearVirtual - -2002-01-04 Havoc Pennington - - * src/display.c (event_callback): don't lower docks when a grab - causes them to get LeaveNotify - -2002-01-04 Havoc Pennington - - * src/screen.c (meta_screen_free): set event mask on root window - to 0 so other window managers (such as ourselves restarting) can - start up; addresses race condition on restart where the old WM - still had RedirectMask when the new WM was trying to start up. - - * src/display.c (meta_display_close): free each screen - - * src/window.c (meta_window_show): always focus new windows in - click-to-focus mode - -2002-01-03 Havoc Pennington - - * src/window.c: use meta_XFree not XFree - - * src/display.h (meta_XFree): add null-safe XFree - - * src/util.c (meta_warning): have message prefix indicate that - it's a warning - (meta_fatal): indicate it's an error - - * src/window.c (update_sm_hints): clean up using - meta_prop_get_latin1_string - (update_role): ditto - (read_client_leader): clean up using meta_prop_get_window - (update_net_wm_type): clean up using meta_prop_get_cardinal - (update_initial_workspace): ditto - (update_net_wm_type): clean up using meta_prop_get_atom_list - (read_rgb_icon): get result from XGetWindowProperty return value - not from error trap - (update_kwm_icon): ditto - (meta_window_new): fix to read WM_STATE correctly - -2002-01-03 Havoc Pennington - - * src/window.c (update_net_wm_state): clean up using - meta_prop_get_atom_list - (update_mwm_hints): clean up using meta_prop_get_motif_hints - - * src/Makefile.am (metacity_SOURCES): add xprops.[hc] - - * src/xprops.c: new file with convenience functions for X - properties - -2002-01-03 Havoc Pennington - - * src/workspace.c (meta_workspace_activate): focus top window when - switching to a new workspace - - * src/util.c (meta_topic): start putting verbose output in - categories - - * src/window.c (meta_window_shade): focus frame after we queue - the calc_showing so the maps/unmaps have already happened. - - * src/display.c (meta_display_get_current_time): add the "get time - of current event" function and call it occasionally. - - * src/window.c (meta_window_free): if we have focus, call - meta_screen_focus_top_window(). - (meta_window_minimize): ditto - (meta_window_delete): ditto - - * src/screen.c (meta_screen_ensure_tab_popup): fix memory leak - - didn't free tab list - (meta_screen_focus_top_window): new function to use when we unmap - or unmanage a focused window - - * src/stack.c (meta_stack_get_default_focus_window): function used - in meta_screen_focus_top_window - -2001-12-21 Havoc Pennington - - * src/frame.c (meta_window_ensure_frame): add a server grab - here since we were failing to have one when calling the function - -2001-12-27 Duarte Loreto - - * configure.in: Added portuguese to ALL_LINGUAS - -2001-12-16 Kjartan Maraas - - * configure.in: Added "no" to ALL_LINGUAS. - -2001-12-11 Stanislav Visnovsky - - * configure.in: Added "sk" to ALL_LINGUAS. - -2001-12-10 Havoc Pennington - - Rework the click-client-area-to-focus support to use synchronous - grabs, avoids a big mess, lets us pass through click when - required (for dock/desktop). Disadvantage is all left-button - clicks now require window manager approval. ;-) - - * src/display.c (event_callback): don't focus dock/desktop when - the mouse enters them; require a click. - (meta_change_button_grab): allow sync grabs - (meta_display_grab_unfocused_window_buttons): establish a - synchronous grab and maintain it all the time, rename to - meta_display_grab_focus_window_button - - * src/window.c: change to reflect display.c - -2001-12-10 Havoc Pennington - - * src/window.c (meta_window_update_unfocused_button_grabs): oops, - unbreak this _again_ - reported by Josh Barrow - -2001-12-10 Havoc Pennington - - * src/window.c (meta_window_update_unfocused_button_grabs): don't - allow grab on docks/desktop for now; needs fixing later to - do the grab, but pass thru click, so we can focus those windows. - And in fact we need to do that even in sloppy mode. - -2001-12-10 Havoc Pennington - - * src/screen.c (meta_screen_foreach_window): fix broken - "tmp = tmp->data" - - Implement do-not-pass-thru-click for click-to-focus mode. - - * src/screen.c (update_focus_mode): when focus mode changes, - update all the window grabs - - * src/display.c (meta_display_grab_unfocused_window_buttons): - implement grabbing button 1 on client area of unfocused - click-to-focus windows - - * src/window.c (meta_window_update_unfocused_button_grabs): update - whether we're grabbing unmodified button 1 on client area - according to focus state and focus mode - (meta_window_new): start out with proper grab state - -2001-12-10 Havoc Pennington - - * src/menu.c (meta_window_menu_new): don't do mnemonics for - workspaces above 9 - -2001-12-10 Havoc Pennington - - * src/screen.c (meta_screen_new): oops, remove extra workspace - creation, and update to current pref. - -2001-12-09 Havoc Pennington - - * src/workspace.c (meta_workspace_free): update number of - workspaces hint - - * src/screen.c (update_num_workspaces): implement number of - workspaces setting - - * src/window.c (meta_window_configure_request): honor configure - requests on windows of type NORMAL, but still be mean to those of - type DIALOG - - * src/main.c (main): add more log domains to those we set a log - handler for, and only set warnings fatal in debug mode - - * src/metacity.schemas: add number of workspaces setting - -2001-12-09 Havoc Pennington - - * src/display.c (event_callback): in click-to-focus mode don't - focus on enter notify. Implement unfocusing on LeaveNotify in - mouse focus mode. Click to focus just ends up working if we - do nothing on enter/leave, because of the way things already - worked. Except I need to add some relatively complex hack to - allow clicking on client area, right now you have to click - on the frame. - -2001-12-09 Havoc Pennington - - * src/main.c (main): move SM init a bit later in the process, and - init prefs - - * src/session.c: fix no SM case (though I hardly know why I'm - bothering) - - * src/main.c (main): call bindtextdomain - - * src/util.h (_): actually call gettext - - * configure.in: put in AM_GLIB_GNU_GETTEXT and gconf stuff - - * src/prefs.c: Preferences - this marks the beginning of our doom. - None of them are actually implemented yet, but we monitor - some stuff from gconf. - -2001-12-07 Havoc Pennington - - * src/window.c (meta_window_unminimize): when unminimizing an app, - if we're in "show desktop" (all windows minimized) mode, leave - show desktop mode. Will occasionally be a bit weird, but allows - people to recover via task list if they accidentally do the show - desktop thing, and don't know what's going on. - -2001-12-06 Havoc Pennington - - * src/ui.c (meta_text_property_to_utf8): fix gdkatom/xatom screwup - - gee, I should read my warnings - -2001-12-03 Laszlo Peter - - * src/frames.c: add a dummy element to the enum so - the signals array is not empty. (breaks the build with Forte C) - - * src/window.c: s/__FUNCTION__/G_GNUC_FUNCTION/ - -2001-11-27 Havoc Pennington - - * src/window.c (constrain_position): change so that window can be - offscreen to the bottom or the right, as long as a small top-left - corner of the window remains onscreen. However, windows still - can't go off the left or top. - -2001-11-26 Havoc Pennington - - * src/window.c (window_query_root_pointer): add error trap - -2001-11-27 Jesus Bravo Alvarez - - * configure.in: Added gl (Galician) to ALL_LINGUAS. - -Tue Nov 20 18:49:16 2001 Owen Taylor - - * configure.in (found_sm): Add some additional quoting to - make it work with autoconf-2.5x. - -2001-11-02 Laszlo Peter - - * src/window.c (update_sm_hints): protect meta_verbose from - a NULL pointer. - -2001-10-29 Havoc Pennington - - * configure.in: bump version - -2001-10-29 Havoc Pennington - - * src/window.c (idle_calc_showing): handle queue/unqueue of - calc showings as we are iterating over the pending list - (meta_window_show): focus placed transients in here instead - of in meta_window_place - now it should actually work, yay - - * src/place.c (meta_window_place): remove focusing of transient - child from here; this was really broken - -2001-10-29 Yuriy Syrota - - * configure.in: Added "uk" to ALL_LINGUAS. - -2001-10-29 Havoc Pennington - - * README: note exciting new unminimize feature for the tab popup - - * src/keybindings.c (process_tab_grab): use meta_window_activate() - when choosing a window with tab popup, this should deiconify it - - * src/window.c (meta_window_client_message): use - meta_window_activate for _NET_ACTIVE_WINDOW message - (meta_window_activate): new function to raise/focus/unminimize - (meta_window_flush_calc_showing): new function - (meta_window_focus): force a calc showing on focus, so that we can - focus the window if appropriate (it must be mapped) - -2001-10-26 Havoc Pennington - - * src/display.c (meta_display_grab_window_buttons): fix for - ignoring NumLock on Alt-windowclick (previous NumLock fix - was only for key grabs not button grabs) - -2001-10-25 Havoc Pennington - - * src/window.c (meta_window_new): set the current workspace hint - -2001-10-25 Havoc Pennington - - * src/window.c (meta_window_visible_on_workspace): - I was using meta_workspace_contains_window() in a number of - places where on_all_workspaces should also have been considered, - thus this new function. Fixes bugs such as pinned windows - not appearing in the tab order. - (meta_window_client_message): use meta_window_visible_on_workspace - - * src/stack.c (find_tab_forward): ditto - (find_tab_backward): ditto - (meta_stack_get_tab_next): ditto - (meta_stack_get_tab_list): ditto - - * src/place.c (get_windows_on_same_workspace): ditto - - * src/keybindings.c (handle_focus_previous): ditto - (handle_focus_previous): ditto - -2001-10-24 Havoc Pennington - - * src/frames.c (meta_frames_expose_event): use bg/fg not base/text - for the window title area. - -2001-10-24 Havoc Pennington - - * src/window.c (meta_window_new): support initial - on-all-workspaces setting - -2001-10-22 Havoc Pennington - - * src/stack.c (meta_stack_sync_to_server): fix to keep desktop - window from appearing on top of everything else, among other stack - bugs. Untested. - -2001-10-15 Havoc Pennington - - * src/window.c (meta_window_new): use queried attributes to check - whether window should be initially maximized, rather than window - rect - -2001-10-15 Havoc Pennington - - * src/main.c (meta_restart): add a restart feature, for debugging - - * src/tools/metacity-restart.c: little utility program to trigger - the restart - -2001-10-14 Havoc Pennington - - * src/frames.c (meta_frames_button_press_event): raise/focus - windows on left-click, seem to have broken that yesterday - - * src/keybindings.c, src/display.c, src/window.c: add keybinding - to show/hide all normal windows (so you can see the desktop). - Currently Ctrl+Alt+D, which I don't like, but yay. - -2001-10-14 Havoc Pennington - - * src/window.c (meta_window_new): take a window mapped at - fullscreen size/pos to desire maximization; once I add a - fullscreen state, will change to copy kwin and take this mapping - as a desire for fullscreen, but for now testing with maximization. - - * src/window.h: remove fullscreen window type, now proposing it - as a window state instead. - -2001-10-14 Havoc Pennington - - * src/window.c (meta_window_maximize): always raise windows on - maximize - (meta_window_client_message): when activating a window, move - it to current workspace, instead of moving user to the - window's workspace. - -2001-10-14 HÃ�©ctor GarcÃ�­a Ã�lvarez - - * configure.in: Added "es" to ALL_LINGUAS for Spanish translation. - -2001-10-14 Havoc Pennington - - * src/display.c (event_callback): only handle events here if - the modmask from our button grab is active. i.e. only the - Alt-click is handled here. - - * src/frames.c: add check for whether button presses are in the - frame client area before handling them, so we don't weirdly let - you move a frame by clicking in its client area if the client - hasn't selected button press events. - -2001-10-13 Havoc Pennington - - * src/stack.c (meta_stack_sync_to_server): set last window before - setting newp, so we don't get the current window as the last - window and screw everything up - (IN_TAB_CHAIN): use type not layer to decide if a window is - in the tab chain, keeps panel out of alt-tab choices - -2001-10-13 Havoc Pennington - - * configure.in: add bad hack to work with GTK 1.3.9.90 RPMs from - gnomehide for now - - * src/ui.c: another piece of bad hack in here - -2001-10-13 Havoc Pennington - - * configure.in: bump version - -2001-10-13 Havoc Pennington - - * src/session.c (meta_session_init): hmm, fix build - -2001-10-12 Havoc Pennington - - * src/session.c (meta_session_init): set the session manager - priority so we start up before other apps. - -2001-10-12 Mikael Hallendal - - * src/ui.c (meta_ui_get_default_window_icon): use - gdk_pixbuf_new_from_inline - (meta_ui_get_default_mini_icon): use - gdk_pixbuf_new_from_inline - -2001-10-11 Christian Rose - - * configure.in: Added "sv" to ALL_LINGUAS. - -2001-10-10 Havoc Pennington - - * src/stack.c (meta_stack_free): fix mem leak of the MetaStack - object - (meta_stack_sync_to_server): try to avoid the restack-flicker - thing - -2001-10-07 Havoc Pennington - - * src/display.c (meta_display_update_active_window_hint): - set _NET_ACTIVE_WINDOW hint - - * src/window.c (meta_window_client_message): support - _NET_ACTIVE_WINDOW client message - -2001-10-07 Havoc Pennington - - * src/window.c (meta_window_client_message): don't allow - shade/maximize/minimize for windows that don't support those - operations. (minimizing the panel = bad) - -2001-10-04 Havoc Pennington - - * src/keybindings.c (meta_change_keygrab): add code to grab all - modifier combinations, so keybindings work with NumLock etc. - - * src/menu.c (meta_window_menu_new): remove newlines from menu - items - -2001-09-27 Havoc Pennington - - * src/session.c (save_state): when encoding text for session file, - escape XML entities - -2001-09-21 Alex Graveley - - * src/Makefile.am (metacity_SOURCES): Add inlinepixbufs.h so - that it gets generated. - - * src/frames.c (meta_frames_style_set): Update for new opaque - PangoFontMetrics. - -2001-09-17 Havoc Pennington - - * src/ui.c (meta_ui_init): add hackaround for the warning about - gtk-menu-bar-accel - -2001-09-17 Havoc Pennington - - * src/ui.c (meta_ui_get_default_mini_icon): - (meta_ui_get_default_window_icon): ref the returned icon, oops. - - * src/main.c (main): get the GLib warning/error output into - the metacity logfile, set warnings to be always fatal - - * configure.in: bump version to 2.3.13 - - * src/window.c (get_text_property): hrm, fix bug where we didn't - check errors on XGetTextProperty - -2001-09-17 Havoc Pennington - - * src/Makefile.am (VARIABLES): fix srcdir != builddir glitch - -2001-09-17 Havoc Pennington - - * src/ui.c: use the inline image data for default icon - - * src/common.h (META_MINI_ICON_HEIGHT): move icon size defines - here - - * src/Makefile.am: Create an inlinepixbufs.h header with inline - images - -2001-09-16 Havoc Pennington - - * src/session.c (process_ice_messages): disconnect this callback - on error - -2001-09-16 Havoc Pennington - - * src/window.c (meta_window_lower): new function - - * configure.in: bump version to 2.3.8 - - * src/display.c (event_callback): raise dock on enter notify, - lower it on leave notify (need to refine this behavior) - - * src/stack.c (compute_layer): experiment with putting the panel - in the normal layer, and raising it on mouseover - -2001-09-15 Havoc Pennington - - * src/window.c: add support for a mini icon in the titlebar - (update_icon): re-enable support for _NET_WM_ICON - - * src/session.c (save_state): add an ferror check when writing - session file - -2001-09-11 Havoc Pennington - - * src/main.c (usage): exit with error code on usage() (kind of - wrong for --help, but oh well). - -2001-09-11 Havoc Pennington - - * src/window.c: fix up handling of text properties, so we - get UTF8_STRING as that type and not as text list, and so - we properly convert from text list to UTF-8 - -2001-09-10 Havoc Pennington - - * src/menu.c (meta_window_menu_new): icon for unmaximize - - * src/ui.c (meta_ui_init): fix call to XDisplayName - - * src/util.c: add missing header - - * src/frames.c: draw an unmaximize control if already maximized - -2001-09-10 Havoc Pennington - - * src/window.c: Don't separate user_has_moved/user_has_resized, - fixes bug in east-resizing Emacs, among other things - - * src/frame.c (meta_frame_sync_to_window): return immediately if - nothing to do - - * src/util.c (ensure_logfile): replace rather than truncate old - logfiles - -2001-09-08 Havoc Pennington - - * src/ui.c (meta_ui_init): don't use gdk_display_name - - * src/frame.c (meta_window_ensure_frame): create frame - with screen default visual, rather than client window visual; - for DRI games, the client window visual was not allowed to be - a child of another window with the same visual, apparently. - Anyhow now we copy twm, etc. so it must be correct. - - * src/place.c (meta_window_place): if a transient is placed and - its parent has focus, focus the transient. - -2001-09-06 Havoc Pennington - - * configure.in: bump version 2.3.5, require newer GTK release - -2001-09-04 Havoc Pennington - - * src/wm-tester/Makefile.am (noinst_PROGRAMS): make test apps - noinst - - * src/metacity.desktop: for the capplet - - * src/Makefile.am: add .desktop file - -2001-09-01 Havoc Pennington - - * src/errors.c: clean up the code, and replace GDK X error handler - with one that chains up to GDK but first logs the error to logfile. - -2001-08-31 Havoc Pennington - - * src/tabpopup.c (meta_ui_tab_popup_new): fix args to - gtk_alignment_new() - -2001-08-29 Havoc Pennington - - * src/display.c (event_callback): avoid focusing a window on tab - popup popdown - - * src/screen.c (meta_screen_ensure_tab_popup): compute frame - outline size here - -2001-08-29 Havoc Pennington - - * src/tabpopup.c: Switch back to outline. - -2001-08-29 Havoc Pennington - - * src/tabpopup.c: experiment with window-cover-with-icon - instead of just the outline; can't decide. - -2001-08-29 Havoc Pennington - - * src/tabpopup.c: add crackrock window-outlining feature - - * src/session.c (window_type_to_string): handle fullscreen - -2001-08-29 Havoc Pennington - - * src/display.c (meta_display_open): wrong atom name - - _NET_SUPPORTED not _NET_WM_SUPPORTED - - * src/window.c (meta_window_configure_request): geez, why were we - honoring configure requests for width/height for normal windows. - Denied! - (meta_window_client_message): _NET_WM_MOVERESIZE support, sort of - (doesn't quite work, acts like owner_events = true?) - - * src/display.c: add _NET_WM_MOVERESIZE atom - -2001-08-28 Havoc Pennington - - Unbreak tab popup a bit. - - * src/stack.c (meta_stack_get_tab_list): add workspace argument - (meta_stack_get_tab_next): add workspace argument - - * src/window.c: implement recording of the last user-initiated - window position, so we can magically handle moving panels around - really nicely. - - * src/wm-tester/main.c (set_up_icon_windows): fix to use new GTK - API - -2001-08-24 Havoc Pennington - - * src/window.c (constrain_position): force fullscreen windows to - be at 0,0 - - * src/ui.c: use NULL colormap to get bitmaps, requires - very latest GTK from CVS or it will spew warnings - and not work. - - * src/window.c (constrain_size): disallow larger than screen in - all cases, even if user has performed a resize operation. - (constrain_position): keep window boxed onscreen. - - * src/keybindings.c (meta_display_process_key_event): revert an - earlier change that disabled global keybindings when a grab is in - effect; instead, only disable global keybindings if a _keyboard_ - grab is in effect. The earlier change was just a broken - workaround, the problems it fixed should have been solved by the - addition of XGrabKeyboard() on the metacity keyboard grabs. - - This should fix the problem with - pick-up-window-and-move-to-another-desktop. - -2001-08-23 Havoc Pennington - - * src/window.c (update_icon): attempt to use the mask as well as - the pixmap. Probably doesn't work so well. - - * src/tabpopup.c: make this look a little nicer - -2001-08-22 Havoc Pennington - - * src/window.c (update_mwm_hints): all the MWM flag tests were - backward - -2001-08-22 Havoc Pennington - - * src/window.c (update_icon): half-ass implementation of - getting pixmap icons (WM_NORMAL_HINTS and KWM_WIN_ICON). - Ignores mask for now, with possibly ugly results for - some apps. - (read_rgb_icon): fixage - -2001-08-19 Havoc Pennington - - * src/window.c: add a "fullscreen" semantic type; if a window - requests the screen size exactly, and is undecorated, and is not a - desktop window, we consider it a fullscreen window and keep it on - top. - - Totally untested. - -2001-08-19 Havoc Pennington - - * src/screen.c (set_supported_hint): we support _NET_WM_ICON - - * src/wm-tester/main.c: add stuff to test _NET_WM_ICON - (but it doesn't work, so it isn't tested yet) - - * src/window.c (update_icon): read _NET_WM_ICON - - * src/screen.c (meta_screen_new): set the WM_ICON_SIZE hint - - * src/tabpopup.c (meta_ui_tab_popup_select): remove assertion - - * src/window.c (meta_window_get_icon_geometry): fix obscure - memleak - -2001-08-19 Havoc Pennington - - * src/display.c (meta_display_grab_window_buttons): remove XSync, - error traps already do that - (meta_display_grab_window_buttons): implement - - * src/keybindings.c: - src/display.c: wire up the tab window, it rulez! - -2001-08-19 Havoc Pennington - - * src/tabpopup.c: add prototype thingy to display windows we're - cycling through with tab. Not wired up to keybindings yet. - -2001-08-18 Havoc Pennington - - * src/effects.c (meta_effects_draw_box_animation): put an XFlush() - right after starting things moving - -2001-08-18 Havoc Pennington - - * src/window.c (meta_window_configure_request): - (meta_window_move_resize_internal): Make a half-hearted - not-very-tested attempt to handle window resizes correctly with - respect to window gravity. - -2001-08-18 Havoc Pennington - - * src/window.c (meta_window_get_gravity_position): hrm, I fixed - this wrong the other day. Fixes static gravity when moving - windows. - -2001-08-18 Havoc Pennington - - * src/ui.c (meta_image_window_set_position): also set the current - size. Lame hack of the day. - - * src/effects.c (effects_draw_box_animation_timeout): use the - delay exposes feature to avoid the screen dirt - - * src/ui.c - (meta_ui_push_delay_exposes): - (meta_ui_pop_delay_exposes): feature to let us delay redraws until - after we do server-grabbed draw-on-inferiors effects - -2001-08-17 Havoc Pennington - - * src/window.c (meta_window_get_gravity_position): fix for - StaticGravity - -2001-08-09 Havoc Pennington - - * src/window.c (meta_window_configure_request): Honor USPosition - even post-map. I know I'll regret this. - -2001-08-07 Havoc Pennington - - * src/display.c (meta_display_open): set _NET_WM_NAME - hint as a UTF8_STRING not STRING. Patch from Anders. - -2001-08-06 Havoc Pennington - - * src/effects.c: disable opaque animations by default, current - implementation suXors. - -2001-08-06 Havoc Pennington - - * src/effects.c (meta_effects_draw_box_animation): Get start - time after we do the pixbuf from drawable, so we don't count - time spent getting pixbuf from drawable in the animation time. - -2001-08-06 Havoc Pennington - - * src/effects.c: add opaque minimize/shade feature. The wireframe - seemed kind of confusing and unclear from a UI standpoint. - I know, I know. The bloat begins here. - - Also, we don't need to grab the server during opaque min/shade, - which has some nice implications. - - * src/ui.c: Add features to render a window with an image in it, - and also wrap pixbuf_from_drawable - - * src/effects.c (meta_effects_draw_box_animation): - modify to be smoother (at least theoretically) by - syncing to current time and "dropping frames" - as appropriate. - - * src/window.c (meta_window_shade): draw animation - for shading too - -2001-08-05 Anders Carlsson - - * src/display.h, src/display.c: Add _NET_WM_ICON_GEOMETRY atom. - - * src/window.c (meta_window_calc_showing): See if the window has - an icon geometry and show a morphing animation from the window's - coordinates to the icon's coordinates. - (meta_window_get_icon_geometry): New function that fetches a - window's icon geometry. - - * src/Makefile.am: Add effects.[ch]. - - * src/effects.c: New file with cool effects. - -2001-08-03 Havoc Pennington - - * src/keybindings.c: Add Alt + left/right arrow to - move between workspaces. - - * src/screen.c (set_wm_check_hint): put property pointing back to - itself on the _WIN_SUPPORTING_WM_CHECK window. - -2001-08-03 Havoc Pennington - - * src/display.c (event_callback): push error trap around configure - of withdrawn window, fixes a crash caused by rapidly - creating/destroying a window. - - * src/window.c (recalc_window_features): don't allow shading - undecorated windows. - - * src/wm-tester/main.c: add a program to torture window managers. - -2001-08-01 Havoc Pennington - - * src/window.c (recalc_window_features): if a window isn't - resizeable, turn off maximize function. If min size is equal to - max size, turn off resize function. - diff --git a/Doxyfile b/Doxyfile deleted file mode 100644 index a8a75411a..000000000 --- a/Doxyfile +++ /dev/null @@ -1,1297 +0,0 @@ -# Doxyfile 1.5.3 - -# This is the doxyfile for Metacity. - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = metacity - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -# Do not enter a setting here; it will only get out of date. -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = doc - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be extracted -# and appear in the documentation as a namespace called 'anonymous_namespace{file}', -# where file will be replaced with the base name of the file that contains the anonymous -# namespace. By default anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = src - -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py - -FILE_PATTERNS = *.c *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH -# then you must also enable this option. If you don't then doxygen will produce -# a warning and turn it on anyway - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the number -# of direct children of the root node in a graph is already larger than -# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/HACKING b/HACKING deleted file mode 100644 index 763bc8830..000000000 --- a/HACKING +++ /dev/null @@ -1,298 +0,0 @@ -Intro... - -Window managers have a few ways in which they are significantly different -from other applications. This file, combined with the code overview in -doc/code-overview.txt, should hopefully provide a series of relatively -quick pointers (hopefully only a few minutes each) to some of the places -one can look to orient themselves and get started. Some of this will be -general to window managers on X, much will be specific to Metacity, and -there's probably some information that's common to programs in general but -is nonetheless useful. - -Overview - Administrative issues - Minimal Building/Testing Environment - Relevant standards and X properties - Debugging and testing - Debugging logs - Adding information to the log - Valgrind - Testing Utilities - Technical gotchas to keep in mind - Other important reading - Extra reading - Ideas for tasks to work on - - -Administrative issues - Don't commit substantive code in here without asking hp@redhat.com. - Adding translations, no-brainer typo fixes, etc. is fine. - - The code could use cleanup in a lot of places, feel free to do so. - - See http://developer.gnome.org/dotplan/for_maintainers.html for - information on how to make a release. The only difference from those - instructions is that the minor version number of a Metacity release - should always be a number from the Fibonacci sequence. - -Minimal Building/Testing Environment - You do not need to _install_ a development version of Metacity to - build, run and test it; you can run it from some temporary - directory. Also, you do not need to build all of Gnome in order to - build a development version of Metacity -- odds are, you may be able - to build metacity from CVS without building any other modules. - - As long as you have gtk+ >= 3.0 and GIO >= 2.25.10 with your distro - (gtk+ >= 2.6 if you manually revert the change from bug 348633), you - should be able to install your distro's development packages - (e.g. gtk2-devel, glib-devel, startup-notification-devel on - Fedora; also, remember to install the gnome-common package which is - needed for building cvs versions of Gnome modules like Metacity) as - well as the standard development tools (gcc, autoconf, automake, - pkg-config, intltool, and libtool) and be ready to build and test - Metacity. Steps to do so: - - $ svn checkout http://svn.gnome.org/svn/metacity/trunk metacity - $ cd metacity - $ ./autogen.sh --prefix /usr - $ make - $ ./src/metacity --replace - - Again, note that you do not need to run 'make install'. - -Relevant standards and X properties - There are two documents that describe some basics about how window - managers should behave: the ICCCM (Inter-Client Communication Conventions - Manual) and EWMH (Extended Window Manager Hints). You can find these at - the following locations: - ICCCM - http://tronche.com/gui/x/icccm/ - EWMH - :pserver:anoncvs@pdx.freedesktop.org:/cvs - The ICCCM is usually available in RPM or DEB format as well. There is - actually an online version of the EWMH, but it is almost always woefully - out of date. Just get it from cvs with these commands (the backslash - means include the stuff from the next line): - cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions login - cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions \ - checkout wm-spec - - DO NOT GO AND READ THOSE THINGS. THEY ARE REALLY, REALLY BORING. - - If you do, you'll probably end up catching up on your sleep instead of - hacking on Metacity. ;-) Instead, just look at the table of contents and - glance at a page or two to get an idea of what's in there. Then only - refer to it if you see something weird in the code and you don't know - what it is but has some funny looking name like you see in one of those - two documents. - - You can refer to the COMPLIANCE file for additional information on these - specifications and Metacity's compliance therewith. - - One of the major things those documents cover that are useful to learn - about immediately are X properties. The right way to learn about those, - though, is through hand on experimentation with the xprop command (and - then look up things you find from xprop in those two manuals if you're - curious enough). First, try running - xprop - in a terminal and click on one of the windows on your screen. That gives - you the x properties for that window. Look through them and get a basic - idea of what's there for kicks. Note that you can get rid of some of the - verboseness by grepping out the _NET_WM_ICON stuff, i.e. - xprop | grep -v _NET_WM_ICON - Next, try running - xprop -root - in a terminal. There's all the properties of the root window (which you - can think of as the "main" Xserver window). You can also manually - specify individual windows that you want the properties of with - xprop -id - if you know the id of the window in question. You can get the id of a - given window by either running xwininfo, e.g. - xwininfo | grep "Window id" | cut -f 4 -d ' ' - or by looking at the _NET_CLIENT_STACKING property of the root - window. Finally, it can also be useful to add "-spy" (without the - quotes) to the xprop command to get it to continually monitor that - window and report any changes to you. - -Debugging information - Trying to run a window manager under a typical debugger, such as gdb, - unfortunately just doesn't work very well. So, we have to resort to - other methods. - - Debugging logs - - First, note that you can start a new version of metacity to replace the - existing one by running - metacity --replace - (which also comes in handy in the form "./src/metacity --replace" when - trying to quickly test a small change while hacking on metacity without - doing a full "make install", though I'm going off topic...) This will - allow you to see any warnings printed at the terminal. Sometimes it's - useful to have these directed to a logfile instead, which you can do by - running - METACITY_USE_LOGFILE=1 metacity --replace - The logfile it uses will be printed in the terminal. Sometimes, it's - useful to get more information than just warnings. You can set - METACITY_VERBOSE to do that, like so: - METACITY_VERBOSE=1 METACITY_USE_LOGFILE=1 metacity --replace - (note that METACITY_VERBOSE=1 can be problematic without - METACITY_USE_LOGFILE=1; avoid it unless running in from something that - won't be managed by the new Metacity--see bug 305091 for more details). - There are also other flags, such as METACITY_DEBUG, most of which I - haven't tried and don't know what they do. Go to the source code - directory and run - grep "METACITY_" * | grep getenv - to find out what the other ones are. - - Adding information to the log - - Since we can't single step with a debugger, we often have to fall back to - the primitive method of getting information we want to know: adding - "print" statements. Metacity has a fairly structured way to do this, - using the functions meta_warning, meta_topic, and meta_verbose. All - three have the same basic format as printf, except that meta_topic also - takes a leading enumeration parameter to specify the type of message - being shown (makes it easier for grepping in a verbose log). You'll find - tons of examples in the source code if you need them; just do a quick - grep or look in most any file. Note that meta_topic and meta_verbose - messages only appear if verbosity is turned on. I tend to frequently add - temporary meta_warning statements (or switch meta_topic or meta_verbose - ones to meta_warning ones) and then undo the changes once I've learned - the info that I needed. - - There is also a meta_print_backtrace (which again is only active if - verbosity is turned on) that can also be useful if you want to learn how - a particular line of code gets called. And, of course, there's always - g_assert if you want to make sure some section isn't executed (or isn't - executed under certain conditions). - - Valgrind - - Valgrind is awesome for finding memory leaks or corruption and - uninitialized variables. But I also tend to use it in a non-traditional - way as a partial substitute for a normal debugger: it can provide me with - a stack trace of where metacity is crashing if I made a change that - caused it to do so, which is one of the major uses of debuggers. (And, - what makes it cooler than a debugger is that there will also often be - warnings pinpointing the cause of the crash from either some kind of - simple memory corruption or an uninitialized variable). Sometimes, when - I merely want to know what is calling a particular function I'll just - throw in an "int i; printf("%d\n", i);" just because valgrind will give - me a full stacktrace whenever it sees that uninitialized variable being - used (yes, I could use meta_print_backtrace, but that means I have to - turn verbosity on). - - To run metacity under valgrind, use options typical for any Gnome - program, such as - valgrind --log-file=metacity.log --tool=memcheck --num-callers=48 \ - --leak-check=yes --leak-resolution=high --show-reachable=yes \ - ./src/metacity --replace - where, again, the backslashes mean to join all the stuff on the following - line with the previous one. - - However, there is a downside. Things run a little bit slowly, and it - appears that you'll need about 1.5GB of ram, which unfortunately prevents - most people from trying this. - - Testing Utilities - - src/run-metacity.sh - The script src/run-metacity.sh is useful to hack on the window manager. - It runs metacity in an Xnest. e.g.: - CLIENTS=3 ./run-metacity.sh - or - DEBUG=memprof ./run-metacity.sh - or - DEBUG_TEST=1 ./run-metacity-sh - or whatever. - - metacity-message - The tool metacity-message can be used as follows: - metacity-message reload-theme - metacity-message restart - metacity-message enable-keybindings - metacity-message disable-keybindings - The first of these is useful for testing themes, the second is just - another way (besides the --restart flag to metacity itself) of - restarting metacity, and the third is useful for testing Metacity when - running it under an Xnest (typically, the Metacity under the Xnest - wouldn't get keybinding notifications--making keyboard navigation not - work--but if you disable the keybindings for the global Metacity then - the Metacity under the Xnest can then get those keybinding notifications). - - metacity-window-demo - metacity-window-demo is good for trying behavior of various kinds - of window without launching a full desktop. - -Technical gotchas to keep in mind - Files that include gdk.h or gtk.h are not supposed to include - display.h or window.h or other core files. Files in the core - (display.[hc], window.[hc]) are not supposed to include gdk.h or - gtk.h. Reasons: - - "Basically you don't want GDK most of the time. It adds - abstractions that cause problems, because they aren't designed to - be used in a WM where we do weird stuff (display grabs, and just - being the WM). At best GDK adds inefficiency, at worst it breaks - things in weird ways where you have to be a GDK guru to figure - them out. Owen also told me that they didn't want to start adding - a lot of hacks to GDK to let a WM use it; we both agreed back in - the mists of time that metacity would only use it for the "UI" - bits as it does. - - Having the split in the source code contains and makes very clear - the interface between the WM and GDK/GTK. This keeps people from - introducing extra GDK/GTK usage when it isn't needed or - appropriate. Also, it speeds up the compilation a bit, though this - was perhaps more relevant 5 years ago than it is now. - - There was also a very old worry that the GDK stuff might have to - be in a separate process to work right; that turned out to be - untrue. Though who knows what issues the CM will introduce." - - Remember that strings stored in X properties are not in UTF-8, and they - have to end up in UTF-8 before we try putting them through Pango. - - If you make any X request involving a client window, you have to - meta_error_trap_push() around the call; this is not necessary for X - requests on the frame windows. - - Remember that not all windows have frames, and window->frame can be NULL. - -Other important reading & where to get started - Extra reading - - There are some other important things to read to get oriented as well. - These are: - http://pobox.com/~hp/features.html - rationales.txt - doc/code-overview.txt - - It pays to read http://pobox.com/~hp/features.html in order - to understand the philosophy of Metacity. - - The rationales.txt file has two things: (1) a list of design choices with - links in the form of bugzilla bugs that discuss the issue, and (2) a list - outstanding bug categories, each of which is tracked by a particular - tracker bug in bugzilla from which you can find several closely related - bug reports. - - doc/code-overview.txt provides a fairly good overview of the code, - including coverage of the function of the various files, the main - structures and their relationships, and places to start looking in the - code tailored to general categories of tasks. - - Ideas for tasks to work on - - There are a variety of things you could work on in the code. You may - have ideas of your own, but in case you don't, let me provide a list of - ideas you could choose from: - - If you're ambitious, there's a list of things Havoc made that he'd really - like to see tackled, which you can find at - http://log.ometer.com/2004-05.html. Be sure to double check with someone - to make sure the item is still relevant if you're interested in one of - these. Another place to look for ideas, of course, is bugzilla. One can - just do queries and look for things that look fixable. - - However, perhaps the best way of getting ideas of related tasks to work - on, is to look at the second half of the rationales.txt file, which tries - to group bugs by type. diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index 0031c7f9c..000000000 --- a/MAINTAINERS +++ /dev/null @@ -1,8 +0,0 @@ -Tomas Frydrych -Email: tf linux intel com -Userid: tomasf - -Owen Taylor -Email: otaylor redhat com -Userid: otaylor - diff --git a/METACITY_MAINTAINERS b/METACITY_MAINTAINERS deleted file mode 100644 index 205dbf224..000000000 --- a/METACITY_MAINTAINERS +++ /dev/null @@ -1,43 +0,0 @@ -Currently active maintainers --------------------------------- - -Elijah Newren -Email: newren gmail com -Userid: newren - - - Usually won't touch the theme bugs (isn't interested) or the - compositor (until open source nvidia drivers are up to snuff). - Tends to be most interested in libwnck/gtk interactions, focus - issues, constraints problems, and raising/stacking, but works on - just about anything other than themes and the compositor. - -Thomas Thurman -Email: thomas thurman org uk -Userid: tthurman - - - Responsible for all theme bugs and the compositor (thank goodness - Thomas got involved, eh?). I'm sure he'll replace this sentence - with his interests when he reads it. ;-) - - -Semi-active maintainers --------------------------------- - -Havoc Pennington -Email: hp redhat com -Userid: hp - - Original author. Doesn't patch metacity anymore, but is active in - answering questions, responding to bugs, providing very helpful - suggestions and insight, and even assisting with debugging. - - -Important historical figureheads --------------------------------- - -Rob Adams (readams readams net) - - Was the main maintainer of metacity for a while; particular areas - of focus included xinerama, placement, and an older version of the - constraints code. Still responds to bugs every once in a while. - -Søren Sandmann (sandmann redhat com) - - Wrote most of the current compositing manager code + libcm diff --git a/Makefile.am b/Makefile.am index 114419ec1..b55c1d144 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,8 +3,6 @@ SUBDIRS=src po doc ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} -EXTRA_DIST = HACKING MAINTAINERS rationales.txt - DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc diff --git a/NEWS b/NEWS index b876052a5..d7dee7268 100644 --- a/NEWS +++ b/NEWS @@ -1,23 +1,21 @@ 3.12.0 ====== +* Fix grab issue with SSD xwayland windows [Rui; #726123] +* Misc. bug fixes [Jasper, Ray, Rui, Florian; #727011] -Translations: - Ask H. Larsen [da], Мирослав Николић [sr, sr@latin], Andika Triwidada [id], - Daniel Korostil [uk], Petr Kovar [cs] +Contributors: + Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode 3.11.92 ======= * Fix identification of CSD windows [Owen; #723029] -* Add minimal handling of touch events [Carlos; #723552] -* Misc bug fixes and cleanups [Owen, Adel, Jasper; #723580, #726352] +* Update keyboard state unconditionally [Rui; #722847] +* Misc bug fixes and cleanups [Owen, Rui, Giovanni, Matthias, Adel, Ryan, + Jasper, Marek, Florian; #723580, #726123, #726683] Contributors: - Adel Gadllah, Carlos Garnacho, Rui Matos, Jasper St. Pierre, Owen W. Taylor - -Translations: - Changwoo Ryu [ko], Rūdolfs Mazurs [lv], Wylmer Wang [zh_CN], - Chao-Hsiung Liao [zh_HK, zh_TW], Yuri Myasoedov [ru], Tiagosdot [pt], - Claude Paroz [fr], Duarte Loreto [pt], A S Alam [pa] + Giovanni Campagna, Marek Chalupa, Matthias Clasen, Adel Gadllah, Ryan Lortie, + Rui Matos, Florian Müllner, Jasper St. Pierre, Owen W. Taylor 3.11.91 ======= @@ -26,125 +24,104 @@ Translations: * Improve keybinding lookups [Rui; #725588] * Fix dynamic updates of titlebar style properties [Owen; #725751] * Fix positioning of manually positioned windows [Owen; #724049] -* Misc. bug fixes [Carlos, Giovanni, Florian, Jasper; #724969, #724402, #722266, - #725338] +* Misc bug fixes and cleanups [Jasper, Carlos, Adel, Giovanni, Florian; #720631, + #724969, #725216, #724402, #722266, #725338, #725525] Contributors: Giovanni Campagna, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner, - Jasper St. Pierre - -Translations: - Aurimas Černius [lt], Milo Casagrande [it], Balázs Úr [hu], - Matej Urbančič [sl], Enrico Nicoletto [pt_BR], Yosef Or Boczko [he], - Piotr Drąg [pl], Fran Diéguez [gl] + Jasper St. Pierre, Owen W. Taylor 3.11.90 ======= -* Use correct output property for backlight control [Robert; #723606] * Fix double-scaling on high DPI resolutions [Adel; #723931] * Make tile previews a compositor effect [Stefano, Florian; #665758] -* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper; #722530, #724257, - #724258, #724364, #720631, #707851, #707897] +* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper, Adel; #722530, #724257, + #724258, #720631, #724364, #724472] Contributors: - Robert Ancell, Giovanni Campagna, Stefano Facchini, Adel Gadllah, + Giovanni Campagna, Marek Chalupa, Stefano Facchini, Adel Gadllah, Ryan Lortie, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz -Translations: - Shankar Prasad [kn], Khaled Hosny [ar], Marek Černocký [cs], - Kjartan Maraas [nb], Daniel Korostil [uk] - 3.11.5 ====== * Fix CSD titlebars being placed off-screen [Jasper; #719772] +* Add support for subsurfaces [Jonas; #705502] * Expose MetaWindow:skip-taskbar property [Florian; #723307] * Fix legacy tray icons showing up blank [Adel; #721596] * Fix configuration of cloned monitors [Adel; #710610] -* Misc bug fixes and cleanups [Jasper, Adel, Jonas; #720631, #723468, #723563] +* Misc bug fixes and cleanups [Jasper, Adel, Marek, Jonas; #720631, #723468, + #720818, #723563, #723564] Contributors: Jonas Ådahl, Marek Ch, Adel Gadllah, Florian Müllner, Jasper St. Pierre -Translations: - Rafael Ferreira [pt_BR], Enrico Nicoletto [pt_BR], Fran Diéguez [gl], - Chao-Hsiung Liao [zh_HK, zh_TW] - 3.11.4 ====== * Don't leave focus on windows that are being unmanaged [Owen; #711618] * Reduce server grabs [Daniel Drake; #721345, #721709] * Improve heuristic to determine display output name [Cosimo Cecchi; #721674] * Atomically unmaximize both directions [Jasper; #722108] -* Misc bug fixes [Debarshi, Andika; #721517, #721674] +* Misc bug fixes [Debarshi, Andika, Florian; #721517, #721674, #722347] Contributors: - Cosimo Cecchi, Daniel Drake, Debarshi Ray, Jasper St. Pierre, + Cosimo Cecchi, Daniel Drake, Florian Müllner, Debarshi Ray, Jasper St. Pierre, Andika Triwidada, Owen W. Taylor -Translations: - Rafael Ferreira [pt_BR], Dimitris Spingos [el], Daniel Mustieles [es], - Milo Casagrande [it], Yosef Or Boczko [he] - 3.11.3 ====== -* xrandr: Use "hotplug_mode_update" property [Marc-André; #711216] -* Fix position of attached dialogs for CSD windows [Giovanni, Owen; #707194] -* Fix focus issues with external OSKs [Jasper; #715030] +* Fix focus issues with external OSKs[Jasper; #715030] * Add a MetaCullable interface [Jasper; #714706] +* Fix window keybindings [Rui; #719724] +* Fix settings keyboard/pointer focus for new clients [Rui; #719725] * Fix window group paint volume [Owen; #719669] * Fix frame extents problems [Owen; #714707] * Add shortcut to move windows between monitors [Florian; #671054] * Fix problems with focus tracking [Owen; #720558] -* Misc. bug fixes and cleanups [Rui, Jasper, Owen; #712833, #678989, #720106, - #720417, #720630] +* Misc. bug fixes and cleanups: [Rui, Colin, Lionel, Jasper, Owen; #712833, + #719557, #719695, #719833, #678989, #720417, #720630] Contributors: - Robert Bragg, Giovanni Campagna, Marc-André Lureau, Rui Matos, Alberto Milone, - Florian Müllner, Sindhu S, Jasper St. Pierre, Rico Tzschichholz, - Owen W. Taylor - -Translations: - 甘露(Gan Lu) [zh_CN], Khaled Hosny [ar] + Lionel Landwerlin, Rui Matos, Alberto Milone, Florian Müllner, + Jasper St. Pierre, Rico Tzschichholz, Owen W. Taylor, Colin Walters 3.11.2 ====== +* Support setting a NULL opaque region [Andreas; #711518] +* Sync keymap from X to wayland [Giovanni; #707446] +* Implement support for subsurfaces [Jonas; #705502] +* Don't focus the no-focus-window for globally active windows [Jasper; #710296] +* Support "hotplug_mode_update" property [Marc-André; #711216] * Fix resize operations using mouse-button-modifier [Lionel; #710251] -* Misc. fixes and cleanups [Jasper, Rico, Florian; #711731] +* Fix position of attached modals for CSD windows [Giovanni, Owen; #707194] +* Misc. bug fixes [Rui, Jasper, Neil, Florian; #712247, #711731] Contributors: - Lionel Landwerlin, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz + Giovanni Campagna, Andreas Heider, Lionel Landwerlin, Marc-André Lureau, + Rui Matos, Florian Müllner, Neil Roberts, Sindhu S, Jasper St. Pierre, + Rico Tzschichholz, Owen W. Taylor, Jonas Ådahl 3.11.1 ====== -* Don't require at least one output device to be connected [Giovanni; #709009] -* Name the guard window [Andrew; #710346] +* Fix tile previews getting stuck on right click during drags [Lionel; #704759] * Use new UPower API [Bastien] +* Set hot spot when cursor set from wl_buffer [Jonas; #709593] * Expose min-backlight-step [Asad; #710380] -* Don't focus the no-focus-window for globally active windows [Jasper; #710296] -* Misc. fixes and cleanups [Jasper, Rico, Olav, Magdalen; #709776] +* Misc. bug fixes and cleanups [Jasper, Olav, Magdalen; #709776] Contributors: - Magdalen Berns, Giovanni Campagna, Asad Mehmood, Bastien Nocera, - Jasper St. Pierre, Rico Tzschichholz, Olav Vitters, Andrew Walton - -Translations: - Reinout van Schouwen [nl] + Magdalen Berns, Lionel Landwerlin, Asad Mehmood, Bastien Nocera, + Jasper St. Pierre, Olav Vitters, Jonas Ådahl 3.10.1 ====== * Don't apply fullscreen workarounds to CSD windows [Giovanni; #708718] * Fix hangs during DND operations [Adel; #709340] -* Use nearest-pixel interpolation when possible [Hans; #708389] -* Fix tile previews getting stuck on right click during drags [Lionel; #704759] -* Misc bug fixes [Giovanni, Jasper; #708420] +* Misc bug fixes [Dan, Giovanni, Jasper; #708813, #708420] Contributors: - Giovanni Campagna, Adel Gadllah, Lionel Landwerlin, Hans Petter Jansson, + Giovanni Campagna, Adel Gadllah, Dan Horák, Hans Petter Jansson, Jasper St. Pierre -Translations: - Khaled Hosny [ar], Reinout van Schouwen [nl], Carles Ferrando [ca@valencia] - 3.10.0.1 ======== * Fix bug when a window changed size twice in a single frame - this @@ -155,24 +132,32 @@ Contributors: 3.10.0 ====== - -Translations: - Ask H. Larsen [da], Gabor Kelemen [hu], Duarte Loreto [pt], - Yosef Or Boczko [he] +* Update dependencies [Giovanni; #708210] 3.9.92 ====== -* Don't create a dummy texture for the texture pipeline template [Neil; #707458] -* Remove holes generated by disabling the laptop lid [Giovanni; #707473] -* https://bugzilla.gnome.org/show_bug.cgi?id=707474 [Giovanni; #707474] +* Constrain the pointer position onto visible monitors [Giovanni; #706655] +* Fix keyboard state handling in face of event compression [Giovanni; #706963] +* Extend the MetaCursorTracker API with query pointer and cursor visibility [Giovanni; #707474] +* Be stricter in checking and exposing the wayland protocol version [#707851] * Don't require plugins to pass event to Clutter [Giovanni; #707482] +* Move the --wayland option from the binary to the library [Giovanni; #707897] +* Implement running from gnome-session (environment variable setting, process group + handling, Clutter backend variables) [Giovanni; #706421] * Add support for more cursor types [Giovanni; #707919] +* Drop man pages for removed utilities [Kalev; #706579] +* Implement monitor configuration on KMS [Giovanni; #706308] +* Implement HW cursors [Giovanni; #707573] +* Implement minimal support for resizing and maximizing wayland clients [Giovanni; #707401] +* Implement transient hints for wayland clients [Giovanni; #707401] +* Implement popup menu surfaces and grabs [Giovanni; #707863] * Immediately fire idle watches that are already expired [Giovanni; #707302] -* Misc bug fixes [Giovanni, Colin, Pavel; #707649, #707563, #708070] +* Remove holes generated by disabling the laptop lid [Giovanni; #707473] +* Misc bug fixes [Giovanni, Pavel, Adel; #707649, #706124, #707584, #707851, #707929, + #708070] Contributors: - Giovanni Campagna, Adel Gadllah, Colin Guthrie, Neil Roberts, - Jasper St. Pierre, Ray Strode, Pavel Vasin + Adel Gadllah, Giovanni Campagna, Kalev Lember, Pavel Vasin Translations: Мирослав Николић po/sr, sr@latin.po, Мирослав Николић [sr, sr@latin], @@ -185,19 +170,30 @@ Translations: 3.9.91 ====== * Drop man pages for removed utilities [Kalev; #706579] -* Add support for idle tracking [Giovanni; #706005] +* Add support for idle tracking [Giovanni, Cosimo; #706005, #707250] * Skip CRTC reconfigurations that have no effect [Giovanni; #706672] * Ignore skip-taskbar hints on parentless dialogs [Giovanni; #673399] * Don't save pixbuf data in user data [Tim; #706777] * Don't queue redraws for obscured regions [Adel; #703332] -* Turn blending off when drawing entirely opaque regions [Jasper; #706930] +* Suppor the opaque region hints for wayland clients [Jasper; #707019] +* Turn blending off when drawing entirely opaque regions [Jasper; #707019] * Check event timestamps before reconfiguring [Giovanni; #706735] +* Merge the DBus API for display configuration in the wayland branch [Giovanni] +* Install an X IO error handler for XWayland [Giovanni; #706962] +* Use the clutter xkbcommon integration for the wayland keyboard [Giovanni; #705862] +* Add a setuid helper for running on KMS+evdev [Giovanni, Colin; #705861] +* Add keybindings for switching VT [Giovanni; #705861] +* Implement plugin modality when running as a wayland compositor [Giovanni; #705917] +* Add support for the application menu for wayland clients [Giovanni; #707128] +* Several Coverity spotted fixes [Jasper] +* Don't create a dummy texture for the texture template [Neil; #707458] +* Use a more conservative paint volume for obscured windows [Adel] * Misc bug fixes [Giovanni, Colin, Seán, Jasper, Cosimo; #706582, #706598, - #706787, #706729, #706825, #707081, #707090, #707250, #707267] + #706787, #706729, #706825, #707081, #707090, #707267, #706982, #706289] Contributors: Giovanni Campagna, Cosimo Cecchi, Adel Gadllah, Colin Guthrie, Kalev Lember, - Tim Lunn, Jasper St. Pierre, Rico Tzschichholz, Seán de Búrca + Tim Lunn, Jasper St. Pierre, Neil Roberts, Rico Tzschichholz, Seán de Búrca Translations: Piotr Drąg [pl], Alexandre Franke [fr], Kjartan Maraas [nb], @@ -206,6 +202,8 @@ Translations: 3.9.90 ====== +* First release from the wayland branch, includes basic support for running + as a wayland compositor [Robert, Neil, Giovanni] * Add support for _GTK_FRAME_EXTENTS [Jasper; #705766] * Fix quick consecutive presses breaking keyboard input [Alban; #666101] * Work towards running as wayland compositor [Giovanni] @@ -220,8 +218,8 @@ Translations: Contributors: Robert Bragg, Giovanni Campagna, Alban Crequy, Adel Gadllah, - Alexander Larsson, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz, - Colin Walters + Alexander Larsson, Florian Müllner, Jasper St. Pierre, Neil Roberts, + Rico Tzschichholz, Colin Walters Translations: Jiro Matsuzawa [ja], Kjartan Maraas [nb], Matej Urbančič [sl], diff --git a/README b/README deleted file mode 100644 index aa45a7616..000000000 --- a/README +++ /dev/null @@ -1,416 +0,0 @@ -The original codebase named "Metacity" is not a meta-City as in an -urban center, but rather Meta-ness as in the state of being -meta. i.e. metacity : meta as opacity : opaque. Also it may have -something to do with the Meta key on UNIX keyboards. - -Since then, it has been renamed mutter after a rebase on top of -clutter as a compositing manager. - -COMPILING MUTTER -=== - -You need GTK+ 2.2. For startup notification to work you need -libstartup-notification at -http://www.freedesktop.org/software/startup-notification/ or on the -GNOME ftp site. -You need Clutter 1.0. You need gobject-introspection 0.6.3. - -REPORTING BUGS AND SUBMITTING PATCHES -=== - -Report new bugs on http://bugzilla.gnome.org. Please check for -duplicates, *especially* if you are reporting a feature request. - -Please do *not* add "me too!" or "yes I really want this!" comments to -feature requests in bugzilla. Please read -http://pobox.com/~hp/features.html prior to adding any kind of flame -about missing features or misfeatures. - -Feel free to send patches too; Metacity is relatively small and -simple, so if you find a bug or want to add a feature it should be -pretty easy. Send me mail, or put the patch in bugzilla. - -See the HACKING file for some notes on hacking Mutter. - -MUTTER FEATURES -=== - - - Uses GTK+ 2.0 for drawing window frames. This means colors, fonts, - etc. come from GTK+ theme. - - - Does not expose the concept of "window manager" to the user. Some - of the features in the GNOME control panel and other parts of the - desktop happen to be implemented in metacity, such as changing your - window border theme, or changing your window navigation shortcuts, - but the user doesn't need to know this. - - - Includes only the window manager; does not try to be a desktop - environment. The pager, configuration, etc. are all separate and - modular. The "libwnck" library (which I also wrote) is available - for writing metacity extensions, pagers, and so on. (But libwnck - isn't metacity specific, or GNOME-dependent; it requires only GTK, - and should work with KWin, fvwm2, and other EWMH-compliant WMs.) - - - Has a simple theme system and a couple of extra themes come with it. - Change themes via gsettings: - gsettings set org.gnome.desktop.wm.preferences theme Crux - gsettings set org.gnome.desktop.wm.preferences theme Gorilla - gsettings set org.gnome.desktop.wm.preferences theme Atlanta - gsettings set org.gnome.desktop.wm.preferences theme Bright - - See theme-format.txt for docs on the theme format. Use - metacity-theme-viewer to preview themes. - - - Change number of workspaces via gsettings: - gsettings set org.gnome.desktop.wm.preferences num-workspaces 5 - - Can also change workspaces from GNOME 2 pager. - - - Change focus mode: - gsettings set org.gnome.desktop.wm.preferences focus-mode mouse - gsettings set org.gnome.desktop.wm.preferences focus-mode sloppy - gsettings set org.gnome.desktop.wm.preferences focus-mode click - - - Global keybinding defaults include: - - Alt-Tab forward cycle window focus - Alt-Shift-Tab backward cycle focus - Alt-Ctrl-Tab forward cycle focus among panels - Alt-Ctrl-Shift-Tab backward cycle focus among panels - Alt-Escape cycle window focus without a popup thingy - Ctrl-Alt-Left Arrow previous workspace - Ctrl-Alt-Right Arrow next workspace - Ctrl-Alt-D minimize/unminimize all, to show desktop - - Change keybindings for example: - - gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 '[F1]' - - Also try the GNOME keyboard shortcuts control panel. - - - Window keybindings: - - Alt-space window menu - - Mnemonics work in the menu. That is, Alt-space then underlined - letter in the menu item works. - - Choose Move from menu, and arrow keys to move the window. - - While moving, hold down Control to move slower, and - Shift to snap to edges. - - Choose Resize from menu, and nothing happens yet, but - eventually I might implement something. - - Keybindings for things like maximize window, vertical maximize, - etc. can be bound, but may not all exist by default. See - metacity.schemas. - - - Window mouse bindings: - - Clicking anywhere on frame with button 1 will raise/focus window - - If you click a window control, such as the close button, then the - control will activate on button release if you are still over it - on release (as with most GUI toolkits) - - If you click and drag borders with button 1 it resizes the window - - If you click and drag the titlebar with button 1 it moves the - window. - - If you click anywhere on the frame with button 2 it lowers the - window. - - If you click anywhere on the frame with button 3 it shows the - window menu. - - If you hold down Super (windows key) and click inside a window, it - will move the window (buttons 1 and 2) or show menu (button 3). - Or you can configure a different modifier for this. - - If you pick up a window with button 1 and then switch workspaces - the window will come with you to the new workspace, this is - a feature copied from Enlightenment. - - If you hold down Shift while moving a window, the window snaps - to edges of other windows and the screen. - - - Session management: - - Mutter connects to the session manager and will set itself up to - be respawned. It theoretically restores sizes/positions/workspace - for session-aware applications. - - - Mutter implements much of the EWMH window manager specification - from freedesktop.org, as well as the older ICCCM. Please refer to - the COMPLIANCE file for information on mutter compliance with - these standards. - - - Uses Pango to render text, so has cool i18n capabilities. - Supports UTF-8 window titles and such. - - - There are simple animations for actions such as minimization, - to help users see what is happening. Should probably - have a few more of these and make them nicer. - - - if you have the proper X setup, set the GDK_USE_XFT=1 - environment variable to get antialiased window titles. - - - considers the panel when placing windows and maximizing - them. - - - handles the window manager selection from the ICCCM. Will exit if - another WM claims it, and can claim it from another WM if you pass - the --replace argument. So if you're running another - ICCCM-compliant WM, you can run "mutter --replace" to replace it - with Metacity. - - - does basic colormap handling - - - and much more! well, maybe not a lot more. - -HOW TO ADD EXTERNAL FEATURES -=== - -You can write a mutter "plugin" such as a pager, window list, icon -box, task menu, or even things like "window matching" using the -Extended Window Manager Hints. See http://www.freedesktop.org for the -EWMH specification. An easy-to-use library called "libwnck" is -available that uses the EWMH and is specifically designed for writing -WM accessories. - -You might be interested in existing accessories such as "Devil's Pie" -by Ross Burton, which add features to Mutter (or other -EWMH-compliant WMs). - -MUTTER BUGS, NON-FEATURES, AND CAVEATS -=== - -See bugzilla: http://bugzilla.gnome.org/query.cgi - -FAQ -=== - -Q: Will you add my feature? - -A: If it makes sense to turn on unconditionally, or is genuinely a - harmless preference that I would not be embarrassed to put in a - simple, uncluttered, user-friendly configuration dialog. - - If the only rationale for your feature is that other window - managers have it, or that you are personally used to it, or - something like that, then I will not be impressed. Metacity is - firmly in the "choose good defaults" camp rather than the "offer 6 - equally broken ways to do it, and let the user pick one" camp. - - This is part of a "no crackrock" policy, despite some exceptions - I'm mildly embarrassed about. For example, multiple workspaces - probably constitute crackrock, they confuse most users and really - are not that useful if you have a decent tasklist and so on. But I - am too used to them to turn them off. Or alternatively - iconification/tasklist is crack, and workspaces/pager are good. But - having both is certainly a bit wrong. Sloppy focus is probably - crackrock too. - - But don't think unlimited crack is OK just because I slipped up a - little. No slippery slope here. - - Don't let this discourage patches and fixes - I love those. ;-) - Just be prepared to hear the above objections if your patch adds - some crack-ridden configuration option. - - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - -Q: Will Mutter be part of GNOME? - -A: It is not officially part of GNOME as of GNOME 2.27. We are - hoping to have mutter officially included as of GNOME 2.28. - -Q: Why does Mutter remember the workspace/position of some apps - but not others across logout/login? - -A: Mutter only stores sizes/positions for apps that are session - managed. As far as I can determine, there is no way to attempt to - remember workspace/position for non-session-aware apps without - causing a lot of weird effects. - - The reason is that you don't know which non-SM-aware apps were - launched by the session. When you initially log in, Metacity sees a - bunch of new windows appear. But it can't distinguish between - windows that were stored in your session, or windows you just - launched after logging in. If Metacity tried to guess that a window - was from the session, it could e.g. end up maximizing a dialog, or - put a window you just launched on another desktop or in a weird - place. And in fact I see a lot of bugs like this in window managers - that try to handle non-session-aware apps. - - However, for session-aware apps, Mutter can tell that the - application instance is from the session and thus restore it - reliably, assuming the app properly restores the windows it had - open on session save. - - So the correct way to fix the situation is to make apps - session-aware. libSM has come with X for years, it's very - standardized, it's shared by GNOME and KDE - even twm is - session-aware. So anyone who won't take a patch to add SM is more - archaic than twm - and you should flame them. ;-) - - Docs on session management: - http://www.fifi.org/doc/xspecs/xsmp.txt.gz - http://www.fifi.org/doc/xspecs/SMlib.txt.gz - - See also the ICCCM section on SM. For GNOME apps, use the - GnomeClient object. For a simple example of using libSM directly, - twm/session.c in the twm source code is pretty easy to understand. - -Q: How about adding viewports in addition to workspaces? - -A: I could conceivably be convinced to use viewports _instead_ of - workspaces, though currently I'm not thinking that. But I don't - think it makes any sense to have both; it's just confusing. They - are functionally equivalent. - - You may think this means that you won't have certain keybindings, - or something like that. This is a misconception. The only - _fundamental_ difference between viewports and workspaces is that - with viewports, windows can "overlap" and appear partially on - one and partially on another. All other differences that - traditionally exist in other window managers are accidental - - the features commonly associated with viewports can be implemented - for workspaces, and vice versa. - - So I don't want to have two kinds of - workspace/desktop/viewport/whatever, but I'm willing to add - features traditionally associated with either kind if those - features make sense. - -Q: Why is the panel always on top? - -A: Because it's a better user interface, and until we made this not - configurable a bunch of apps were not getting fixed (the app - authors were just saying "put your panel on the bottom" instead of - properly supporting fullscreen mode, and such). - - rationales.txt has the bugzilla URL for some flamefesting on this, - if you want to go back and relive the glory. - Read these and the bugzilla stuff before asking/commenting: - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - -Q: Why is there no edge flipping? - -A: This one is also in rationales.txt. Because "ouija board" UI, where - you just move the mouse around and the computer guesses what you - mean, has a lot of issues. This includes mouse focus, shade-hover - mode, edge flipping, autoraise, etc. Metacity has mouse focus and - autoraise as a compromise, but these features are all confusing for - many users, and cause problems with accessibility, fitt's law, and - so on. - - Read these and the bugzilla stuff before asking/commenting: - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - -Q: Why does wireframe move/resize suck? - -A: You can turn it on with the reduced_resources setting. - - But: it has low usability, and is a pain - to implement, and there's no reason opaque move/resize should be a - problem on any setup that can run a modern desktop worth a darn to - begin with. - - Read these and the bugzilla stuff before asking/commenting: - http://pobox.com/~hp/free-software-ui.html - http://pobox.com/~hp/features.html - - The reason we had to add wireframe anyway was broken - proprietary apps that can't handle lots of resize events. - -Q: Why no XYZ? - -A: You are probably getting the idea by now - check rationales.txt, - query/search bugzilla, and read http://pobox.com/~hp/features.html - and http://pobox.com/~hp/free-software-ui.html - - Then sit down and answer the question for yourself. Is the feature - good? What's the rationale for it? Answer "why" not just "why not." - Justify in terms of users as a whole, not just users like - yourself. How else can you solve the same problem? etc. If that - leads you to a strong opinion, then please, post the rationale for - discussion to an appropriate bugzilla bug, or to - usability@gnome.org. - - Please don't just "me too!" on bugzilla bugs, please don't think - flames will get you anywhere, and please don't repeat rationale - that's already been offered. - -Q: Your dumb web pages you made me read talk about solving problems in - fundamental ways instead of adding preferences or workarounds. - What are some examples where metacity has done this? - -A: There are quite a few, though many opportunities remain. Sometimes - the real fix involves application changes. The metacity approach is - that it's OK to require apps to change, though there are also - plenty of workarounds in metacity for battles considered too hard - to fight. - - Here are some examples: - - - fullscreen mode was introduced to allow position constraints, - panel-on-top, and other such things to apply to normal windows - while still allowing video players etc. to "just work" - - - "whether to include minimized windows in Alt+Tab" was solved - by putting minimized windows at the *end* of the tab order. - - - Whether to pop up a feedback display during Alt+Tab was solved by - having both Alt+Tab and Alt+Esc - - - Whether to have a "kill" feature was solved by automatically - detecting and offering to kill stuck apps. Better, metacity - actually does "kill -9" on the process, it doesn't just - disconnect the process from the X server. You'll appreciate this - if you ever did a "kill" on Netscape 4, and watched it keep - eating 100% CPU even though the X server had booted it. - - - The workspaces vs. viewports mess was avoided by adding - directional navigation and such to workspaces, see discussion - earlier in this file. - - - Instead of configurable placement algorithms, there's just one - that works fairly well most of the time. - - - To avoid excess CPU use during opaque move/resize, we rate limit - the updates to the application window's size. - - - Instead of configurable "show size of window while resizing," - it's only shown for windows where it matters, such as terminals. - (Only use-case given for all windows is for web designers - choosing their web browser size, but there are web sites and - desktop backgrounds that do this for you.) - - - Using startup notification, applications open on the workspace - where you launched them, not the active workspace when their - window is opened. - - - and much more. - -Q: I think mutter sucks. - -A: Feel free to use any WM you like. The reason metacity follows the - ICCCM and EWMH specifications is that it makes metacity a modular, - interchangeable part in the desktop. libwnck-based apps such as the - GNOME window list will work just fine with any EWMH-compliant WM. - -Q: Did you spend a lot of time on this? - -A: Originally the answer was no. Sadly the answer is now yes. - -Q: How can you claim that you are anti-crack, while still - writing a window manager? - -A: I have no comment on that. diff --git a/configure.ac b/configure.ac index f27be5ca7..ea9e674a7 100644 --- a/configure.ac +++ b/configure.ac @@ -17,10 +17,14 @@ AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR(src/core/display.c) AC_CONFIG_HEADERS(config.h) -AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar]) +AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar subdir-objects]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AM_MAINTAINER_MODE([enable]) +# Change pkglibdir and pkgdatadir to mutter-wayland instead of mutter +PACKAGE="mutter-wayland" +AC_SUBST([PACKAGE], [$PACKAGE]) + MUTTER_MAJOR_VERSION=mutter_major_version MUTTER_MINOR_VERSION=mutter_minor_version MUTTER_MICRO_VERSION=mutter_micro_version @@ -36,7 +40,7 @@ AC_SUBST(MUTTER_PLUGIN_DIR) # Honor aclocal flags AC_SUBST(ACLOCAL_AMFLAGS, "\${ACLOCAL_FLAGS}") -GETTEXT_PACKAGE=mutter +GETTEXT_PACKAGE=mutter-wayland AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Name of default gettext domain]) @@ -75,7 +79,7 @@ MUTTER_PC_MODULES=" cairo >= 1.10.0 gsettings-desktop-schemas >= 3.7.3 xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0 - $CLUTTER_PACKAGE >= 1.15.90 + $CLUTTER_PACKAGE >= 1.17.5 cogl-1.0 >= 1.17.1 upower-glib >= 0.99.0 gnome-desktop-3.0 @@ -117,11 +121,27 @@ AC_ARG_ENABLE(shape, [disable mutter's use of the shaped window extension]),, enable_shape=auto) +## Wayland support requires the xserver.xml protocol extension found in the weston +## repository but since there aren't currently established conventions for +## installing and discovering these we simply require a location to be given +## explicitly... +AC_ARG_WITH([wayland-protocols], + [AS_HELP_STRING([--with-wayland-protocols], [Location for wayland extension protocol specs])], + [ + ], + []) + +AC_ARG_WITH([xwayland-path], + [AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])], + [XWAYLAND_PATH="$withval"], + [XWAYLAND_PATH="$bindir/Xwayland"]) + AM_GLIB_GNU_GETTEXT ## here we get the flags we'll actually use # GRegex requires Glib-2.14.0 PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0) +PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login) # Unconditionally use this dir to avoid a circular dep with gnomecc GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings" @@ -186,20 +206,15 @@ if test x$found_introspection != xno; then AC_SUBST(META_GIR) fi -AC_MSG_CHECKING([Xcursor]) -if $PKG_CONFIG xcursor; then - have_xcursor=yes - else - have_xcursor=no - fi - AC_MSG_RESULT($have_xcursor) +MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor" -if test x$have_xcursor = xyes; then - echo "Building with Xcursor" - MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor" - AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support]) -fi +AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no]) +AS_IF([test "x$WAYLAND_SCANNER" = "xno"], + AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols])) +AC_SUBST([WAYLAND_SCANNER]) +AC_SUBST(XWAYLAND_PATH) +MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm" PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES) PKG_CHECK_EXISTS([xi >= 1.6.99.1], @@ -437,8 +452,7 @@ doc/man/Makefile doc/reference/Makefile doc/reference/meta-docs.sgml src/Makefile -src/libmutter.pc -src/mutter-plugins.pc +src/libmutter-wayland.pc src/compositor/plugins/Makefile po/Makefile.in ]) @@ -455,7 +469,7 @@ fi dnl ========================================================================== echo " -mutter-$VERSION +mutter-wayland-$VERSION prefix: ${prefix} source code location: ${srcdir} @@ -467,7 +481,6 @@ mutter-$VERSION Session management: ${found_sm} Shape extension: ${found_shape} Xsync: ${found_xsync} - Xcursor: ${have_xcursor} " diff --git a/doc/Makefile.am b/doc/Makefile.am index d16ae33fe..12dc522dd 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,4 +1,4 @@ SUBDIRS = man reference EXTRA_DIST=theme-format.txt dialogs.txt code-overview.txt \ - how-to-get-focus-right.txt + how-to-get-focus-right.txt rationales.txt diff --git a/rationales.txt b/doc/rationales.txt similarity index 100% rename from rationales.txt rename to doc/rationales.txt diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index f411e2629..e0e702e58 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -140,7 +140,7 @@ expand_content_files= \ # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) GTKDOC_CFLAGS=$(MUTTER_CFLAGS) -GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter.la +GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter-wayland.la # This includes the standard gtk-doc make rules, copied by gtkdocize. include $(top_srcdir)/gtk-doc.make diff --git a/po/POTFILES.in b/po/POTFILES.in index fb893350e..f6696d90f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -16,14 +16,14 @@ src/core/monitor.c src/core/mutter.c src/core/prefs.c src/core/screen.c -src/core/session.c +src/x11/session.c src/core/util.c src/core/window.c -src/core/window-props.c -src/core/xprops.c -src/mutter.desktop.in -src/mutter-wm.desktop.in +src/x11/window-props.c +src/x11/xprops.c +src/mutter-wayland.desktop.in src/org.gnome.mutter.gschema.xml.in +src/org.gnome.mutter.wayland.gschema.xml.in src/ui/frames.c src/ui/menu.c src/ui/metaaccellabel.c diff --git a/src/Makefile.am b/src/Makefile.am index dc1cac73a..61cbb7ab0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,16 +1,19 @@ # Flag build for parallelism; see https://savannah.gnu.org/patch/?6905 .AUTOPARALLEL: -lib_LTLIBRARIES = libmutter.la +lib_LTLIBRARIES = libmutter-wayland.la SUBDIRS=compositor/plugins INCLUDES= \ + -DCLUTTER_ENABLE_COMPOSITOR_API \ -DCLUTTER_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_API \ -DCOGL_ENABLE_EXPERIMENTAL_2_0_API \ $(MUTTER_CFLAGS) \ + -I$(top_builddir) \ -I$(srcdir) \ + -I$(srcdir)/backends \ -I$(srcdir)/core \ -I$(srcdir)/ui \ -I$(srcdir)/compositor \ @@ -27,17 +30,56 @@ INCLUDES= \ -DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) \ -DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \ -DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \ - -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" + -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \ + -DXWAYLAND_PATH='"@XWAYLAND_PATH@"' mutter_built_sources = \ - $(dbus_idle_built_sources) \ - $(dbus_xrandr_built_sources) \ - mutter-enum-types.h \ - mutter-enum-types.c + $(dbus_idle_built_sources) \ + $(dbus_display_config_built_sources) \ + mutter-enum-types.h \ + mutter-enum-types.c \ + gtk-shell-protocol.c \ + gtk-shell-server-protocol.h \ + xdg-shell-protocol.c \ + xdg-shell-server-protocol.h -libmutter_la_SOURCES = \ - core/async-getprop.c \ - core/async-getprop.h \ +wayland_protocols = \ + wayland/protocol/gtk-shell.xml \ + wayland/protocol/xdg-shell.xml + +libmutter_wayland_la_SOURCES = \ + backends/meta-backend.c \ + backends/meta-backend.h \ + backends/meta-cursor.c \ + backends/meta-cursor.h \ + backends/meta-cursor-private.h \ + backends/meta-cursor-tracker.c \ + backends/meta-cursor-tracker-private.h \ + backends/meta-idle-monitor.c \ + backends/meta-idle-monitor-private.h \ + backends/meta-idle-monitor-dbus.c \ + backends/meta-idle-monitor-dbus.h \ + backends/meta-monitor-config.c \ + backends/meta-monitor-config.h \ + backends/meta-monitor-manager.c \ + backends/meta-monitor-manager.h \ + backends/meta-monitor-manager-dummy.c \ + backends/meta-monitor-manager-dummy.h \ + backends/edid-parse.c \ + backends/edid.h \ + backends/native/meta-idle-monitor-native.c \ + backends/native/meta-idle-monitor-native.h \ + backends/native/meta-monitor-manager-kms.c \ + backends/native/meta-monitor-manager-kms.h \ + backends/native/meta-weston-launch.c \ + backends/native/meta-weston-launch.h \ + backends/x11/meta-idle-monitor-xsync.c \ + backends/x11/meta-idle-monitor-xsync.h \ + backends/x11/meta-monitor-manager-xrandr.c \ + backends/x11/meta-monitor-manager-xrandr.h \ + backends/x11/meta-xrandr-shared.h \ + core/meta-accel-parse.c \ + core/meta-accel-parse.h \ core/barrier.c \ meta/barrier.h \ core/bell.c \ @@ -65,7 +107,13 @@ libmutter_la_SOURCES = \ compositor/meta-shadow-factory.c \ compositor/meta-shadow-factory-private.h \ compositor/meta-shaped-texture.c \ - compositor/meta-shaped-texture-private.h \ + compositor/meta-shaped-texture-private.h \ + compositor/meta-surface-actor.c \ + compositor/meta-surface-actor.h \ + compositor/meta-surface-actor-x11.c \ + compositor/meta-surface-actor-x11.h \ + compositor/meta-surface-actor-wayland.c \ + compositor/meta-surface-actor-wayland.h \ compositor/meta-texture-rectangle.c \ compositor/meta-texture-rectangle.h \ compositor/meta-texture-tower.c \ @@ -86,7 +134,6 @@ libmutter_la_SOURCES = \ meta/meta-shadow-factory.h \ meta/meta-window-actor.h \ meta/compositor-mutter.h \ - core/above-tab-keycode.c \ core/constraints.c \ core/constraints.h \ core/core.c \ @@ -96,34 +143,17 @@ libmutter_la_SOURCES = \ meta/display.h \ core/edge-resistance.c \ core/edge-resistance.h \ - core/edid-parse.c \ - core/edid.h \ + core/events.c \ + core/events.h \ core/errors.c \ meta/errors.h \ core/frame.c \ core/frame.h \ ui/gradient.c \ meta/gradient.h \ - core/group-private.h \ - core/group-props.c \ - core/group-props.h \ - core/group.c \ - meta/group.h \ - core/iconcache.c \ - core/iconcache.h \ core/keybindings.c \ core/keybindings-private.h \ core/main.c \ - core/meta-cursor-tracker.c \ - core/meta-cursor-tracker-private.h \ - core/meta-idle-monitor.c \ - core/meta-idle-monitor-private.h \ - core/meta-xrandr-shared.h \ - core/monitor.c \ - core/monitor-config.c \ - core/monitor-private.h \ - core/monitor-xrandr.c \ - core/mutter-Xatomtype.h \ core/place.c \ core/place.h \ core/prefs.c \ @@ -132,8 +162,6 @@ libmutter_la_SOURCES = \ core/screen-private.h \ meta/screen.h \ meta/types.h \ - core/session.c \ - core/session.h \ core/stack.c \ core/stack.h \ core/stack-tracker.c \ @@ -141,15 +169,11 @@ libmutter_la_SOURCES = \ core/util.c \ meta/util.h \ core/util-private.h \ - core/window-props.c \ - core/window-props.h \ core/window.c \ core/window-private.h \ meta/window.h \ core/workspace.c \ core/workspace-private.h \ - core/xprops.c \ - core/xprops.h \ meta/common.h \ core/core.h \ ui/ui.h \ @@ -165,13 +189,54 @@ libmutter_la_SOURCES = \ ui/theme.c \ meta/theme.h \ ui/theme-private.h \ - ui/ui.c + ui/ui.c \ + x11/iconcache.c \ + x11/iconcache.h \ + x11/async-getprop.c \ + x11/async-getprop.h \ + x11/group-private.h \ + x11/group-props.c \ + x11/group-props.h \ + x11/group.c \ + meta/group.h \ + x11/session.c \ + x11/session.h \ + x11/window-props.c \ + x11/window-props.h \ + x11/window-x11.c \ + x11/window-x11.h \ + x11/window-x11-private.h \ + x11/xprops.c \ + x11/xprops.h \ + x11/mutter-Xatomtype.h \ + wayland/meta-wayland.c \ + wayland/meta-wayland.h \ + wayland/meta-wayland-private.h \ + wayland/meta-xwayland.c \ + wayland/meta-xwayland.h \ + wayland/meta-xwayland-private.h \ + wayland/meta-wayland-data-device.c \ + wayland/meta-wayland-data-device.h \ + wayland/meta-wayland-keyboard.c \ + wayland/meta-wayland-keyboard.h \ + wayland/meta-wayland-pointer.c \ + wayland/meta-wayland-pointer.h \ + wayland/meta-wayland-seat.c \ + wayland/meta-wayland-seat.h \ + wayland/meta-wayland-stage.h \ + wayland/meta-wayland-stage.c \ + wayland/meta-wayland-surface.c \ + wayland/meta-wayland-surface.h \ + wayland/meta-wayland-types.h \ + wayland/meta-wayland-versions.h \ + wayland/window-wayland.c \ + wayland/window-wayland.h -nodist_libmutter_la_SOURCES = \ +nodist_libmutter_wayland_la_SOURCES = \ $(mutter_built_sources) -libmutter_la_LDFLAGS = -no-undefined -libmutter_la_LIBADD = $(MUTTER_LIBS) +libmutter_wayland_la_LDFLAGS = -no-undefined +libmutter_wayland_la_LIBADD = $(MUTTER_LIBS) # Headers installed for plugins; introspected information will # be extracted into Mutter-.gir @@ -209,16 +274,29 @@ libmutterinclude_base_headers = \ libmutterinclude_extra_headers = \ meta/atomnames.h -libmutterincludedir = $(includedir)/mutter/meta +libmutterincludedir = $(includedir)/mutter-wayland/meta libmutterinclude_HEADERS = \ $(libmutterinclude_base_headers) \ $(libmutterinclude_extra_headers) -bin_PROGRAMS=mutter +bin_PROGRAMS=mutter-wayland -mutter_SOURCES = core/mutter.c -mutter_LDADD = $(MUTTER_LIBS) libmutter.la +mutter_wayland_SOURCES = core/mutter.c +mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la + +bin_PROGRAMS+=mutter-launch + +mutter_launch_SOURCES = \ + backends/native/weston-launch.c \ + backends/native/weston-launch.h + +mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\" +mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam + +install-exec-hook: + -chown root $(DESTDIR)$(bindir)/mutter-launch + -chmod u+s $(DESTDIR)$(bindir)/mutter-launch if HAVE_INTROSPECTION include $(INTROSPECTION_MAKEFILE) @@ -240,41 +318,36 @@ typelib_DATA = Meta-$(api_version).typelib INTROSPECTION_GIRS = Meta-$(api_version).gir -Meta-$(api_version).gir: libmutter.la +Meta-$(api_version).gir: libmutter-wayland.la @META_GIR@_INCLUDES = GObject-2.0 GDesktopEnums-3.0 Gdk-3.0 Gtk-3.0 Clutter-1.0 xlib-2.0 xfixes-4.0 Cogl-1.0 -@META_GIR@_EXPORT_PACKAGES = libmutter +@META_GIR@_EXPORT_PACKAGES = libmutter-wayland @META_GIR@_CFLAGS = $(INCLUDES) -@META_GIR@_LIBS = libmutter.la +@META_GIR@_LIBS = libmutter-wayland.la @META_GIR@_FILES = \ mutter-enum-types.h \ $(libmutterinclude_base_headers) \ - $(filter %.c,$(libmutter_la_SOURCES) $(nodist_libmutter_la_SOURCES)) + $(filter %.c,$(libmutter_wayland_la_SOURCES) $(nodist_libmutter_wayland_la_SOURCES)) @META_GIR@_SCANNERFLAGS = --warn-all --warn-error endif testboxes_SOURCES = core/testboxes.c testgradient_SOURCES = ui/testgradient.c -testasyncgetprop_SOURCES = core/testasyncgetprop.c +testasyncgetprop_SOURCES = x11/testasyncgetprop.c noinst_PROGRAMS=testboxes testgradient testasyncgetprop -testboxes_LDADD = $(MUTTER_LIBS) libmutter.la -testgradient_LDADD = $(MUTTER_LIBS) libmutter.la -testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la +testboxes_LDADD = $(MUTTER_LIBS) libmutter-wayland.la +testgradient_LDADD = $(MUTTER_LIBS) libmutter-wayland.la +testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter-wayland.la @INTLTOOL_DESKTOP_RULE@ desktopfilesdir=$(datadir)/applications -desktopfiles_in_files=mutter.desktop.in +desktopfiles_in_files=mutter-wayland.desktop.in desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop) desktopfiles_DATA = $(desktopfiles_files) -wmpropertiesdir=$(datadir)/gnome/wm-properties -wmproperties_in_files=mutter-wm.desktop.in -wmproperties_files=$(wmproperties_in_files:.desktop.in=.desktop) -wmproperties_DATA = $(wmproperties_files) - xmldir = @GNOME_KEYBINDINGS_KEYSDIR@ xml_in_files = \ 50-mutter-navigation.xml.in \ @@ -282,7 +355,9 @@ xml_in_files = \ 50-mutter-windows.xml.in xml_DATA = $(xml_in_files:.xml.in=.xml) -gsettings_SCHEMAS = org.gnome.mutter.gschema.xml +dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h + +gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml @INTLTOOL_XML_NOMERGE_RULE@ @GSETTINGS_RULES@ @@ -290,9 +365,10 @@ convertdir = $(datadir)/GConf/gsettings convert_DATA = mutter-schemas.convert CLEANFILES = \ - mutter.desktop \ + mutter-wayland.desktop \ mutter-wm.desktop \ org.gnome.mutter.gschema.xml \ + org.gnome.mutter.wayland.gschema.xml \ $(xml_DATA) \ $(mutter_built_sources) \ $(typelib_DATA) \ @@ -300,7 +376,7 @@ CLEANFILES = \ pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libmutter.pc mutter-plugins.pc +pkgconfig_DATA = libmutter-wayland.pc EXTRA_DIST=$(desktopfiles_files) \ $(wmproperties_files) \ @@ -308,14 +384,15 @@ EXTRA_DIST=$(desktopfiles_files) \ $(desktopfiles_in_files) \ $(wmproperties_in_files) \ $(xml_in_files) \ + $(wayland_protocols) \ org.gnome.mutter.gschema.xml.in \ - idle-monitor.xml \ - xrandr.xml \ + org.gnome.mutter.wayland.gschema.xml.in \ mutter-schemas.convert \ - libmutter.pc.in \ - mutter-plugins.pc.in \ + libmutter-wayland.pc.in \ mutter-enum-types.h.in \ - mutter-enum-types.c.in + mutter-enum-types.c.in \ + org.gnome.Mutter.DisplayConfig.xml \ + org.gnome.Mutter.IdleMonitor.xml BUILT_SOURCES = $(mutter_built_sources) MUTTER_STAMP_FILES = stamp-mutter-enum-types.h @@ -340,21 +417,24 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in cp xgen-tetc mutter-enum-types.c && \ rm -f xgen-tetc -dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h +dbus_display_config_built_sources = meta-dbus-display-config.c meta-dbus-display-config.h -$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml +$(dbus_display_config_built_sources) : Makefile.am org.gnome.Mutter.DisplayConfig.xml $(AM_V_GEN)gdbus-codegen \ --interface-prefix org.gnome.Mutter \ --c-namespace MetaDBus \ - --generate-c-code meta-dbus-xrandr \ - $(srcdir)/xrandr.xml + --generate-c-code meta-dbus-display-config \ + $(srcdir)/org.gnome.Mutter.DisplayConfig.xml -dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h - -$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml +$(dbus_idle_built_sources) : Makefile.am org.gnome.Mutter.IdleMonitor.xml $(AM_V_GEN)gdbus-codegen \ --interface-prefix org.gnome.Mutter \ --c-namespace MetaDBus \ --generate-c-code meta-dbus-idle-monitor \ --c-generate-object-manager \ - $(srcdir)/idle-monitor.xml + $(srcdir)/org.gnome.Mutter.IdleMonitor.xml + +%-protocol.c : $(srcdir)/wayland/protocol/%.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ +%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@ diff --git a/src/core/edid-parse.c b/src/backends/edid-parse.c similarity index 100% rename from src/core/edid-parse.c rename to src/backends/edid-parse.c diff --git a/src/core/edid.h b/src/backends/edid.h similarity index 100% rename from src/core/edid.h rename to src/backends/edid.h diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c new file mode 100644 index 000000000..b8a6dc1cf --- /dev/null +++ b/src/backends/meta-backend.c @@ -0,0 +1,157 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "meta-backend.h" +#include + +#include +#include +#include + +#include "backends/native/meta-weston-launch.h" +#include + +/* Mutter is responsible for pulling events off the X queue, so Clutter + * doesn't need (and shouldn't) run its normal event source which polls + * the X fd, but we do have to deal with dispatching events that accumulate + * in the clutter queue. This happens, for example, when clutter generate + * enter/leave events on mouse motion - several events are queued in the + * clutter queue but only one dispatched. It could also happen because of + * explicit calls to clutter_event_put(). We add a very simple custom + * event loop source which is simply responsible for pulling events off + * of the queue and dispatching them before we block for new events. + */ + +static gboolean +event_prepare (GSource *source, + gint *timeout_) +{ + *timeout_ = -1; + + return clutter_events_pending (); +} + +static gboolean +event_check (GSource *source) +{ + return clutter_events_pending (); +} + +static gboolean +event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + ClutterEvent *event = clutter_event_get (); + + if (event) + { + clutter_do_event (event); + clutter_event_free (event); + } + + return TRUE; +} + +static GSourceFuncs event_funcs = { + event_prepare, + event_check, + event_dispatch +}; + +static MetaLauncher *launcher; + +void +meta_clutter_init (void) +{ + GSource *source; + + /* When running as an X11 compositor, we install our own event filter and + * pass events to Clutter explicitly, so we need to prevent Clutter from + * handling our events. + * + * However, when running as a Wayland compostior under X11 nested, Clutter + * Clutter needs to see events related to its own window. We need to + * eventually replace this with a proper frontend / backend split: Clutter + * under nested is connecting to the "host X server" to get its events it + * needs to put up a window, and GTK+ is connecting to the "inner X server". + * The two would the same in the X11 compositor case, but not when running + * XWayland as a Wayland compositor. + */ + if (!meta_is_wayland_compositor ()) + { + clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); + clutter_x11_disable_event_retrieval (); + } + + /* If we're running on bare metal, we're a display server, + * so start talking to weston-launch. */ +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + launcher = meta_launcher_new (); +#endif + + if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS) + g_error ("Unable to initialize Clutter.\n"); + + source = g_source_new (&event_funcs, sizeof (GSource)); + g_source_attach (source, NULL); + g_source_unref (source); +} + +gboolean +meta_activate_vt (int vt, GError **error) +{ + if (launcher) + return meta_launcher_activate_vt (launcher, vt, error); + else + { + g_debug ("Ignoring VT switch keybinding, not running as display server"); + return TRUE; + } +} + +/** + * meta_activate_session: + * + * Tells mutter to activate the session. When mutter is a + * Wayland compositor, this tells logind to switch over to + * the new session. + */ +gboolean +meta_activate_session (void) +{ + GError *error = NULL; + + if (!meta_launcher_activate_vt (launcher, -1, &error)) + { + g_warning ("Could not activate session: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} diff --git a/src/backends/meta-backend.h b/src/backends/meta-backend.h new file mode 100644 index 000000000..03d8a5633 --- /dev/null +++ b/src/backends/meta-backend.h @@ -0,0 +1,34 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef META_BACKEND_H +#define META_BACKEND_H + +#include + +void meta_clutter_init (void); + +gboolean meta_activate_vt (int vt, GError **error); + +#endif /* META_BACKEND_H */ diff --git a/src/backends/meta-cursor-private.h b/src/backends/meta-cursor-private.h new file mode 100644 index 000000000..b1490212a --- /dev/null +++ b/src/backends/meta-cursor-private.h @@ -0,0 +1,50 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Author: Giovanni Campagna + */ + +#ifndef META_CURSOR_PRIVATE_H +#define META_CURSOR_PRIVATE_H + +#include "meta-cursor.h" + +#include +#include + +typedef struct { + CoglTexture2D *texture; + struct gbm_bo *bo; + int hot_x, hot_y; +} MetaCursorImage; + +struct _MetaCursorReference { + int ref_count; + + MetaCursorImage image; +}; + +CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor, + int *hot_x, + int *hot_y); + +struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor, + int *hot_x, + int *hot_y); + +#endif /* META_CURSOR_PRIVATE_H */ diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h new file mode 100644 index 000000000..ef8de4b98 --- /dev/null +++ b/src/backends/meta-cursor-tracker-private.h @@ -0,0 +1,98 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Author: Giovanni Campagna + */ + +#ifndef META_CURSOR_TRACKER_PRIVATE_H +#define META_CURSOR_TRACKER_PRIVATE_H + +#include +#include + +#include "meta-cursor.h" + +struct _MetaCursorTracker { + GObject parent_instance; + + MetaScreen *screen; + + gboolean is_showing; + gboolean has_hw_cursor; + + /* The cursor tracker stores the cursor for the current grab + * operation, the cursor for the window with pointer focus, and + * the cursor for the root window, which contains either the + * default arrow cursor or the 'busy' hourglass if we're launching + * an app. + * + * We choose the first one available -- if there's a grab cursor, + * we choose that cursor, if there's window cursor, we choose that, + * otherwise we choose the root cursor. + * + * The displayed_cursor contains the chosen cursor. + */ + MetaCursorReference *displayed_cursor; + + MetaCursorReference *grab_cursor; + + /* Wayland clients can set a NULL buffer as their cursor + * explicitly, which means that we shouldn't display anything. + * So, we can't simply store a NULL in window_cursor to + * determine an unset window cursor; we need an extra boolean. + */ + gboolean has_window_cursor; + MetaCursorReference *window_cursor; + + MetaCursorReference *root_cursor; + + MetaCursorReference *theme_cursors[META_CURSOR_LAST]; + + int current_x, current_y; + MetaRectangle current_rect; + MetaRectangle previous_rect; + gboolean previous_is_valid; + + CoglPipeline *pipeline; + int drm_fd; + struct gbm_device *gbm; +}; + +struct _MetaCursorTrackerClass { + GObjectClass parent_class; +}; + +gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, + XEvent *xevent); + +void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor); +void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor); +void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker); +void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor); + +void meta_cursor_tracker_update_position (MetaCursorTracker *tracker, + int new_x, + int new_y); +void meta_cursor_tracker_paint (MetaCursorTracker *tracker); + +void meta_cursor_tracker_force_update (MetaCursorTracker *tracker); + +#endif diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c new file mode 100644 index 000000000..28a6af2fc --- /dev/null +++ b/src/backends/meta-cursor-tracker.c @@ -0,0 +1,738 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Author: Giovanni Campagna + */ + +/** + * SECTION:cursor-tracker + * @title: MetaCursorTracker + * @short_description: Mutter cursor tracking helper. Originally only + * tracking the cursor image, now more of a "core + * pointer abstraction" + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "meta-cursor-private.h" +#include "meta-cursor-tracker-private.h" +#include "screen-private.h" +#include "meta-monitor-manager.h" + +#include "wayland/meta-wayland-private.h" + +G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); + +enum { + CURSOR_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, + MetaCRTC *crtc, + gboolean has_hw_cursor); +static void sync_cursor (MetaCursorTracker *tracker); + +static void +meta_cursor_tracker_init (MetaCursorTracker *self) +{ + /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of + detecting if the system mouse cursor is showing or not. + + On wayland we start with the cursor showing + */ + self->is_showing = TRUE; +} + +static void +meta_cursor_tracker_finalize (GObject *object) +{ + MetaCursorTracker *self = META_CURSOR_TRACKER (object); + int i; + + if (self->displayed_cursor) + meta_cursor_reference_unref (self->displayed_cursor); + if (self->root_cursor) + meta_cursor_reference_unref (self->root_cursor); + + for (i = 0; i < META_CURSOR_LAST; i++) + if (self->theme_cursors[i]) + meta_cursor_reference_unref (self->theme_cursors[i]); + + if (self->pipeline) + cogl_object_unref (self->pipeline); + if (self->gbm) + gbm_device_destroy (self->gbm); + + G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object); +} + +static void +meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_cursor_tracker_finalize; + + signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +on_monitors_changed (MetaMonitorManager *monitors, + MetaCursorTracker *tracker) +{ + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + + if (!tracker->has_hw_cursor) + return; + + /* Go through the new list of monitors, find out where the cursor is */ + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = meta_rectangle_overlap (&tracker->current_rect, rect); + + /* Need to do it unconditionally here, our tracking is + wrong because we reloaded the CRTCs */ + meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); + } +} + +static MetaCursorTracker * +make_wayland_cursor_tracker (MetaScreen *screen) +{ + MetaWaylandCompositor *compositor; + CoglContext *ctx; + MetaMonitorManager *monitors; + MetaCursorTracker *self; + + self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); + self->screen = screen; + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + self->pipeline = cogl_pipeline_new (ctx); + + compositor = meta_wayland_compositor_get_default (); + compositor->seat->cursor_tracker = self; + meta_cursor_tracker_update_position (self, + wl_fixed_to_int (compositor->seat->pointer.x), + wl_fixed_to_int (compositor->seat->pointer.y)); + +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx)); + self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); + self->gbm = gbm_create_device (self->drm_fd); + } +#endif + + monitors = meta_monitor_manager_get (); + g_signal_connect_object (monitors, "monitors-changed", + G_CALLBACK (on_monitors_changed), self, 0); + + return self; +} + +static MetaCursorTracker * +make_x11_cursor_tracker (MetaScreen *screen) +{ + MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); + self->screen = screen; + + XFixesSelectCursorInput (screen->display->xdisplay, + screen->xroot, + XFixesDisplayCursorNotifyMask); + + return self; +} + +/** + * meta_cursor_tracker_get_for_screen: + * @screen: the #MetaScreen + * + * Retrieves the cursor tracker object for @screen. + * + * Returns: (transfer none): + */ +MetaCursorTracker * +meta_cursor_tracker_get_for_screen (MetaScreen *screen) +{ + MetaCursorTracker *self; + + if (screen->cursor_tracker) + return screen->cursor_tracker; + + if (meta_is_wayland_compositor ()) + self = make_wayland_cursor_tracker (screen); + else + self = make_x11_cursor_tracker (screen); + + screen->cursor_tracker = self; + return self; +} + +static void +set_window_cursor (MetaCursorTracker *tracker, + gboolean has_cursor, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->window_cursor = meta_cursor_reference_ref (cursor); + tracker->has_window_cursor = has_cursor; + sync_cursor (tracker); +} + +gboolean +meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, + XEvent *xevent) +{ + XFixesCursorNotifyEvent *notify_event; + + if (meta_is_wayland_compositor ()) + return FALSE; + + if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify) + return FALSE; + + notify_event = (XFixesCursorNotifyEvent *)xevent; + if (notify_event->subtype != XFixesDisplayCursorNotify) + return FALSE; + + set_window_cursor (tracker, FALSE, NULL); + + return TRUE; +} + +static MetaCursorReference * +meta_cursor_reference_take_texture (CoglTexture2D *texture, + int hot_x, + int hot_y) +{ + MetaCursorReference *self; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + self->image.texture = texture; + self->image.hot_x = hot_x; + self->image.hot_y = hot_y; + + return self; +} + +static void +ensure_xfixes_cursor (MetaCursorTracker *tracker) +{ + XFixesCursorImage *cursor_image; + CoglTexture2D *sprite; + guint8 *cursor_data; + gboolean free_cursor_data; + CoglContext *ctx; + + if (tracker->has_window_cursor) + return; + + cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay); + if (!cursor_image) + return; + + /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit + * quantities as arrays of long; we need to convert on 64 bit */ + if (sizeof(long) == 4) + { + cursor_data = (guint8 *)cursor_image->pixels; + free_cursor_data = FALSE; + } + else + { + int i, j; + guint32 *cursor_words; + gulong *p; + guint32 *q; + + cursor_words = g_new (guint32, cursor_image->width * cursor_image->height); + cursor_data = (guint8 *)cursor_words; + + p = cursor_image->pixels; + q = cursor_words; + for (j = 0; j < cursor_image->height; j++) + for (i = 0; i < cursor_image->width; i++) + *(q++) = *(p++); + + free_cursor_data = TRUE; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + sprite = cogl_texture_2d_new_from_data (ctx, + cursor_image->width, + cursor_image->height, + CLUTTER_CAIRO_FORMAT_ARGB32, + cursor_image->width * 4, /* stride */ + cursor_data, + NULL); + + if (free_cursor_data) + g_free (cursor_data); + + if (sprite != NULL) + { + MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite, + cursor_image->xhot, + cursor_image->yhot); + set_window_cursor (tracker, TRUE, cursor); + } + XFree (cursor_image); +} + +/** + * meta_cursor_tracker_get_sprite: + * + * Returns: (transfer none): + */ +CoglTexture * +meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker) +{ + g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL); + + if (!meta_is_wayland_compositor ()) + ensure_xfixes_cursor (tracker); + + if (tracker->displayed_cursor) + return meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL); + else + return NULL; +} + +/** + * meta_cursor_tracker_get_hot: + * @tracker: + * @x: (out): + * @y: (out): + * + */ +void +meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, + int *x, + int *y) +{ + g_return_if_fail (META_IS_CURSOR_TRACKER (tracker)); + + if (!meta_is_wayland_compositor ()) + ensure_xfixes_cursor (tracker); + + if (tracker->displayed_cursor) + meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, x, y); + else + { + if (x) + *x = 0; + if (y) + *y = 0; + } +} + +void +meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->grab_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->grab_cursor = meta_cursor_reference_ref (cursor); + + sync_cursor (tracker); +} + +void +meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + set_window_cursor (tracker, TRUE, cursor); +} + +void +meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker) +{ + set_window_cursor (tracker, FALSE, NULL); +} + +void +meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, + MetaCursorReference *cursor) +{ + g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref); + if (cursor) + tracker->root_cursor = meta_cursor_reference_ref (cursor); + + sync_cursor (tracker); +} + +static gboolean +should_have_hw_cursor (MetaCursorTracker *tracker) +{ + if (tracker->displayed_cursor) + return (meta_cursor_reference_get_gbm_bo (tracker->displayed_cursor, NULL, NULL) != NULL); + else + return FALSE; +} + +static void +update_hw_cursor (MetaCursorTracker *tracker) +{ + MetaMonitorManager *monitors; + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + gboolean enabled; + + enabled = should_have_hw_cursor (tracker); + tracker->has_hw_cursor = enabled; + + monitors = meta_monitor_manager_get (); + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = enabled && meta_rectangle_overlap (&tracker->current_rect, rect); + + if (has || crtcs[i].has_hw_cursor) + meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); + } +} + +static void +move_hw_cursor (MetaCursorTracker *tracker) +{ + MetaMonitorManager *monitors; + MetaCRTC *crtcs; + unsigned int i, n_crtcs; + + monitors = meta_monitor_manager_get (); + meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); + + g_assert (tracker->has_hw_cursor); + + for (i = 0; i < n_crtcs; i++) + { + MetaRectangle *rect = &crtcs[i].rect; + gboolean has; + + has = meta_rectangle_overlap (&tracker->current_rect, rect); + + if (has != crtcs[i].has_hw_cursor) + meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has); + if (has) + drmModeMoveCursor (tracker->drm_fd, crtcs[i].crtc_id, + tracker->current_rect.x - rect->x, + tracker->current_rect.y - rect->y); + } +} + +static MetaCursorReference * +get_displayed_cursor (MetaCursorTracker *tracker) +{ + if (!tracker->is_showing) + return NULL; + + if (tracker->grab_cursor) + return tracker->grab_cursor; + + if (tracker->has_window_cursor) + return tracker->window_cursor; + + return tracker->root_cursor; +} + +static void +update_displayed_cursor (MetaCursorTracker *tracker) +{ + if (meta_is_wayland_compositor ()) + { + if (tracker->displayed_cursor) + { + CoglTexture *texture = meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL); + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, texture); + } + else + cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL); + + update_hw_cursor (tracker); + } +} + +static void +sync_displayed_cursor (MetaCursorTracker *tracker) +{ + MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker); + + if (tracker->displayed_cursor == displayed_cursor) + return; + + g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref); + if (displayed_cursor) + tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor); + + update_displayed_cursor (tracker); + g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); +} + +static void +meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker) +{ + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + ClutterActor *stage = compositor->stage; + cairo_rectangle_int_t clip; + + g_assert (meta_is_wayland_compositor ()); + + /* Clear the location the cursor was at before, if we need to. */ + if (tracker->previous_is_valid) + { + clip.x = tracker->previous_rect.x; + clip.y = tracker->previous_rect.y; + clip.width = tracker->previous_rect.width; + clip.height = tracker->previous_rect.height; + clutter_actor_queue_redraw_with_clip (stage, &clip); + tracker->previous_is_valid = FALSE; + } + + if (tracker->has_hw_cursor || !tracker->displayed_cursor) + return; + + clip.x = tracker->current_rect.x; + clip.y = tracker->current_rect.y; + clip.width = tracker->current_rect.width; + clip.height = tracker->current_rect.height; + clutter_actor_queue_redraw_with_clip (stage, &clip); +} + +static void +sync_cursor (MetaCursorTracker *tracker) +{ + MetaCursorReference *displayed_cursor; + + sync_displayed_cursor (tracker); + displayed_cursor = tracker->displayed_cursor; + + if (displayed_cursor) + { + CoglTexture *texture; + int hot_x, hot_y; + + texture = meta_cursor_reference_get_cogl_texture (displayed_cursor, &hot_x, &hot_y); + + tracker->current_rect.x = tracker->current_x - hot_x; + tracker->current_rect.y = tracker->current_y - hot_y; + tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture)); + tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture)); + } + else + { + tracker->current_rect.x = 0; + tracker->current_rect.y = 0; + tracker->current_rect.width = 0; + tracker->current_rect.height = 0; + } + + if (meta_is_wayland_compositor ()) + { + if (tracker->has_hw_cursor) + move_hw_cursor (tracker); + else + meta_cursor_tracker_queue_redraw (tracker); + } +} + +void +meta_cursor_tracker_update_position (MetaCursorTracker *tracker, + int new_x, + int new_y) +{ + g_assert (meta_is_wayland_compositor ()); + + tracker->current_x = new_x; + tracker->current_y = new_y; + + sync_cursor (tracker); +} + +void +meta_cursor_tracker_paint (MetaCursorTracker *tracker) +{ + g_assert (meta_is_wayland_compositor ()); + + if (tracker->has_hw_cursor || !tracker->displayed_cursor) + return; + + cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), + tracker->pipeline, + tracker->current_rect.x, + tracker->current_rect.y, + tracker->current_rect.x + + tracker->current_rect.width, + tracker->current_rect.y + + tracker->current_rect.height); + + tracker->previous_rect = tracker->current_rect; + tracker->previous_is_valid = TRUE; +} + +static void +meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker, + MetaCRTC *crtc, + gboolean has) +{ + if (has) + { + MetaCursorReference *displayed_cursor = tracker->displayed_cursor; + struct gbm_bo *bo; + union gbm_bo_handle handle; + int width, height; + int hot_x, hot_y; + + bo = meta_cursor_reference_get_gbm_bo (displayed_cursor, &hot_x, &hot_y); + + handle = gbm_bo_get_handle (bo); + width = gbm_bo_get_width (bo); + height = gbm_bo_get_height (bo); + + drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32, + width, height, hot_x, hot_y); + crtc->has_hw_cursor = TRUE; + } + else + { + drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0); + crtc->has_hw_cursor = FALSE; + } +} + +static void +get_pointer_position_gdk (int *x, + int *y, + int *mods) +{ + GdkDeviceManager *gmanager; + GdkDevice *gdevice; + GdkScreen *gscreen; + + gmanager = gdk_display_get_device_manager (gdk_display_get_default ()); + gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID); + + gdk_device_get_position (gdevice, &gscreen, x, y); + if (mods) + gdk_device_get_state (gdevice, + gdk_screen_get_root_window (gscreen), + NULL, (GdkModifierType*)mods); +} + +static void +get_pointer_position_clutter (int *x, + int *y, + int *mods) +{ + ClutterDeviceManager *cmanager; + ClutterInputDevice *cdevice; + ClutterPoint point; + + cmanager = clutter_device_manager_get_default (); + cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE); + + clutter_input_device_get_coords (cdevice, NULL, &point); + if (x) + *x = point.x; + if (y) + *y = point.y; + if (mods) + *mods = clutter_input_device_get_modifier_state (cdevice); +} + +void +meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, + int *x, + int *y, + ClutterModifierType *mods) +{ + /* We can't use the clutter interface when not running as a wayland compositor, + because we need to query the server, rather than using the last cached value. + OTOH, on wayland we can't use GDK, because that only sees the events + we forward to xwayland. + */ + if (meta_is_wayland_compositor ()) + get_pointer_position_clutter (x, y, (int*)mods); + else + get_pointer_position_gdk (x, y, (int*)mods); +} + +void +meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, + gboolean visible) +{ + if (visible == tracker->is_showing) + return; + tracker->is_showing = visible; + + if (meta_is_wayland_compositor ()) + { + sync_cursor (tracker); + } + else + { + if (visible) + XFixesShowCursor (tracker->screen->display->xdisplay, + tracker->screen->xroot); + else + XFixesHideCursor (tracker->screen->display->xdisplay, + tracker->screen->xroot); + } +} + +void +meta_cursor_tracker_force_update (MetaCursorTracker *tracker) +{ + g_assert (meta_is_wayland_compositor ()); + + update_hw_cursor (tracker); + sync_cursor (tracker); +} diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c new file mode 100644 index 000000000..2a78328ef --- /dev/null +++ b/src/backends/meta-cursor.c @@ -0,0 +1,412 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Author: Giovanni Campagna + */ + +#include "config.h" + +#include "meta-cursor-private.h" + +#include + +#include "display-private.h" +#include "screen-private.h" +#include "meta-cursor-tracker-private.h" /* for tracker->gbm */ + +#include + +#include +#include +#include + +#include + +MetaCursorReference * +meta_cursor_reference_ref (MetaCursorReference *self) +{ + g_assert (self->ref_count > 0); + self->ref_count++; + + return self; +} + +static void +meta_cursor_image_free (MetaCursorImage *image) +{ + cogl_object_unref (image->texture); + if (image->bo) + gbm_bo_destroy (image->bo); +} + +static void +meta_cursor_reference_free (MetaCursorReference *self) +{ + meta_cursor_image_free (&self->image); + g_slice_free (MetaCursorReference, self); +} + +void +meta_cursor_reference_unref (MetaCursorReference *self) +{ + self->ref_count--; + + if (self->ref_count == 0) + meta_cursor_reference_free (self); +} + +static void +translate_meta_cursor (MetaCursor cursor, + guint *glyph_out, + const char **name_out) +{ + guint glyph = XC_num_glyphs; + const char *name = NULL; + + switch (cursor) + { + case META_CURSOR_DEFAULT: + glyph = XC_left_ptr; + break; + case META_CURSOR_NORTH_RESIZE: + glyph = XC_top_side; + break; + case META_CURSOR_SOUTH_RESIZE: + glyph = XC_bottom_side; + break; + case META_CURSOR_WEST_RESIZE: + glyph = XC_left_side; + break; + case META_CURSOR_EAST_RESIZE: + glyph = XC_right_side; + break; + case META_CURSOR_SE_RESIZE: + glyph = XC_bottom_right_corner; + break; + case META_CURSOR_SW_RESIZE: + glyph = XC_bottom_left_corner; + break; + case META_CURSOR_NE_RESIZE: + glyph = XC_top_right_corner; + break; + case META_CURSOR_NW_RESIZE: + glyph = XC_top_left_corner; + break; + case META_CURSOR_MOVE_OR_RESIZE_WINDOW: + glyph = XC_fleur; + break; + case META_CURSOR_BUSY: + glyph = XC_watch; + break; + case META_CURSOR_DND_IN_DRAG: + name = "dnd-none"; + break; + case META_CURSOR_DND_MOVE: + name = "dnd-move"; + break; + case META_CURSOR_DND_COPY: + name = "dnd-copy"; + break; + case META_CURSOR_DND_UNSUPPORTED_TARGET: + name = "dnd-none"; + break; + case META_CURSOR_POINTING_HAND: + glyph = XC_hand2; + break; + case META_CURSOR_CROSSHAIR: + glyph = XC_crosshair; + break; + case META_CURSOR_IBEAM: + glyph = XC_xterm; + break; + + default: + g_assert_not_reached (); + glyph = 0; /* silence compiler */ + break; + } + + *glyph_out = glyph; + *name_out = name; +} + +static Cursor +load_cursor_on_server (MetaDisplay *display, + MetaCursor cursor) +{ + Cursor xcursor; + guint glyph; + const char *name; + + translate_meta_cursor (cursor, &glyph, &name); + + if (name != NULL) + xcursor = XcursorLibraryLoadCursor (display->xdisplay, name); + else + xcursor = XCreateFontCursor (display->xdisplay, glyph); + + return xcursor; +} + +Cursor +meta_display_create_x_cursor (MetaDisplay *display, + MetaCursor cursor) +{ + return load_cursor_on_server (display, cursor); +} + +static XcursorImage * +load_cursor_on_client (MetaDisplay *display, + MetaCursor cursor) +{ + XcursorImage *image; + guint glyph; + const char *name; + const char *theme = XcursorGetTheme (display->xdisplay); + int size = XcursorGetDefaultSize (display->xdisplay); + + translate_meta_cursor (cursor, &glyph, &name); + + if (name != NULL) + image = XcursorLibraryLoadImage (name, theme, size); + else + image = XcursorShapeLoadImage (glyph, theme, size); + + return image; +} + +static void +meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm, + MetaCursorImage *image, + uint8_t *pixels, + int width, + int height, + int rowstride, + uint32_t gbm_format) +{ + if (width > 64 || height > 64) + { + meta_warning ("Invalid theme cursor size (must be at most 64x64)\n"); + return; + } + + if (gbm_device_is_format_supported (gbm, gbm_format, + GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE)) + { + uint8_t buf[4 * 64 * 64]; + int i; + + image->bo = gbm_bo_create (gbm, 64, 64, + gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); + + memset (buf, 0, sizeof(buf)); + for (i = 0; i < height; i++) + memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4); + + gbm_bo_write (image->bo, buf, 64 * 64 * 4); + } + else + meta_warning ("HW cursor for format %d not supported\n", gbm_format); +} + +static void +meta_cursor_image_load_from_xcursor_image (MetaCursorTracker *tracker, + MetaCursorImage *image, + XcursorImage *xc_image) +{ + int width, height, rowstride; + CoglPixelFormat cogl_format; + uint32_t gbm_format; + ClutterBackend *clutter_backend; + CoglContext *cogl_context; + + width = xc_image->width; + height = xc_image->height; + rowstride = width * 4; + + gbm_format = GBM_FORMAT_ARGB8888; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + cogl_format = COGL_PIXEL_FORMAT_BGRA_8888; +#else + cogl_format = COGL_PIXEL_FORMAT_ARGB_8888; +#endif + + image->hot_x = xc_image->xhot; + image->hot_y = xc_image->yhot; + + clutter_backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (clutter_backend); + image->texture = cogl_texture_2d_new_from_data (cogl_context, + width, height, + cogl_format, + rowstride, + (uint8_t *) xc_image->pixels, + NULL); + + if (tracker->gbm) + meta_cursor_image_load_gbm_buffer (tracker->gbm, + image, + (uint8_t *) xc_image->pixels, + width, height, rowstride, + gbm_format); +} + +MetaCursorReference * +meta_cursor_reference_from_theme (MetaCursorTracker *tracker, + MetaCursor cursor) +{ + MetaCursorReference *self; + XcursorImage *image; + + if (tracker->theme_cursors[cursor]) + return meta_cursor_reference_ref (tracker->theme_cursors[cursor]); + + image = load_cursor_on_client (tracker->screen->display, cursor); + if (!image) + return NULL; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + meta_cursor_image_load_from_xcursor_image (tracker, &self->image, image); + + XcursorImageDestroy (image); + return self; +} + +static void +meta_cursor_image_load_from_buffer (MetaCursorTracker *tracker, + MetaCursorImage *image, + struct wl_resource *buffer, + int hot_x, + int hot_y) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + struct wl_shm_buffer *shm_buffer; + uint32_t gbm_format; + int width, height; + + image->hot_x = hot_x; + image->hot_y = hot_y; + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + + image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL); + + width = cogl_texture_get_width (COGL_TEXTURE (image->texture)); + height = cogl_texture_get_height (COGL_TEXTURE (image->texture)); + + shm_buffer = wl_shm_buffer_get (buffer); + if (shm_buffer) + { + if (tracker->gbm) + { + int rowstride = wl_shm_buffer_get_stride (shm_buffer); + + switch (wl_shm_buffer_get_format (shm_buffer)) + { +#if G_BYTE_ORDER == G_BIG_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + gbm_format = GBM_FORMAT_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + gbm_format = GBM_FORMAT_XRGB8888; + break; +#else + case WL_SHM_FORMAT_ARGB8888: + gbm_format = GBM_FORMAT_ARGB8888; + break; + case WL_SHM_FORMAT_XRGB8888: + gbm_format = GBM_FORMAT_XRGB8888; + break; +#endif + default: + g_warn_if_reached (); + gbm_format = GBM_FORMAT_ARGB8888; + } + + meta_cursor_image_load_gbm_buffer (tracker->gbm, + image, + (uint8_t *) wl_shm_buffer_get_data (shm_buffer), + width, height, rowstride, + gbm_format); + } + } + else + { + /* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses + that, so themed cursors must be padded with transparent pixels to fill the + overlay. This is trivial if we have CPU access to the data, but it's not + possible if the buffer is in GPU memory (and possibly tiled too), so if we + don't get the right size, we fallback to GL. + */ + if (width != 64 || height != 64) + { + meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n"); + return; + } + + if (tracker->gbm) + { + image->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER, + buffer, GBM_BO_USE_CURSOR_64X64); + if (!image->bo) + meta_warning ("Importing HW cursor from wl_buffer failed\n"); + } + } +} + +MetaCursorReference * +meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y) +{ + MetaCursorReference *self; + + self = g_slice_new0 (MetaCursorReference); + self->ref_count = 1; + meta_cursor_image_load_from_buffer (tracker, &self->image, buffer, hot_x, hot_y); + + return self; +} + +CoglTexture * +meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor, + int *hot_x, + int *hot_y) +{ + if (hot_x) + *hot_x = cursor->image.hot_x; + if (hot_y) + *hot_y = cursor->image.hot_y; + return COGL_TEXTURE (cursor->image.texture); +} + +struct gbm_bo * +meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor, + int *hot_x, + int *hot_y) +{ + if (hot_x) + *hot_x = cursor->image.hot_x; + if (hot_y) + *hot_y = cursor->image.hot_y; + return cursor->image.bo; +} diff --git a/src/backends/meta-cursor.h b/src/backends/meta-cursor.h new file mode 100644 index 000000000..50ad086e7 --- /dev/null +++ b/src/backends/meta-cursor.h @@ -0,0 +1,42 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Author: Giovanni Campagna + */ + +#ifndef META_CURSOR_H +#define META_CURSOR_H + +typedef struct _MetaCursorReference MetaCursorReference; + +MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor); +void meta_cursor_reference_unref (MetaCursorReference *cursor); + +#include +#include +#include + +MetaCursorReference * meta_cursor_reference_from_theme (MetaCursorTracker *tracker, + MetaCursor cursor); + +MetaCursorReference * meta_cursor_reference_from_buffer (MetaCursorTracker *tracker, + struct wl_resource *buffer, + int hot_x, + int hot_y); + +#endif /* META_CURSOR_H */ diff --git a/src/core/meta-xrandr-shared.h b/src/backends/meta-display-config-shared.h similarity index 84% rename from src/core/meta-xrandr-shared.h rename to src/backends/meta-display-config-shared.h index 99e3d9825..92665cc00 100644 --- a/src/core/meta-xrandr-shared.h +++ b/src/backends/meta-display-config-shared.h @@ -16,7 +16,7 @@ * along with this program; if not, see . */ -/* This file is shared between mutter (src/core/meta-xrandr-shared.h) +/* This file is shared between mutter (src/core/meta-display-config-shared.h) and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h). The canonical place for all changes is mutter. @@ -24,8 +24,8 @@ There should be no includes in this file. */ -#ifndef META_XRANDR_SHARED_H -#define META_XRANDR_SHARED_H +#ifndef META_DISPLAY_CONFIG_SHARED_H +#define META_DISPLAY_CONFIG_SHARED_H typedef enum { META_POWER_SAVE_UNSUPPORTED = -1, @@ -35,4 +35,4 @@ typedef enum { META_POWER_SAVE_OFF, } MetaPowerSave; -#endif +#endif /* META_DISPLAY_CONFIG_SHARED_H */ diff --git a/src/backends/meta-idle-monitor-dbus.c b/src/backends/meta-idle-monitor-dbus.c new file mode 100644 index 000000000..811b46ada --- /dev/null +++ b/src/backends/meta-idle-monitor-dbus.c @@ -0,0 +1,286 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-dbus.h" +#include +#include "meta-dbus-idle-monitor.h" + +#include +#include +#include /* for meta_get_replace_current_wm () */ + +static gboolean +handle_get_idletime (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + MetaIdleMonitor *monitor) +{ + guint64 idletime; + + idletime = meta_idle_monitor_get_idletime (monitor); + meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime); + + return TRUE; +} + +typedef struct { + MetaDBusIdleMonitor *dbus_monitor; + MetaIdleMonitor *monitor; + char *dbus_name; + guint watch_id; + guint name_watcher_id; +} DBusWatch; + +static void +destroy_dbus_watch (gpointer data) +{ + DBusWatch *watch = data; + + g_object_unref (watch->dbus_monitor); + g_object_unref (watch->monitor); + g_free (watch->dbus_name); + g_bus_unwatch_name (watch->name_watcher_id); + + g_slice_free (DBusWatch, watch); +} + +static void +dbus_idle_callback (MetaIdleMonitor *monitor, + guint watch_id, + gpointer user_data) +{ + DBusWatch *watch = user_data; + GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor); + + g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), + watch->dbus_name, + g_dbus_interface_skeleton_get_object_path (skeleton), + "org.gnome.Mutter.IdleMonitor", + "WatchFired", + g_variant_new ("(u)", watch_id), + NULL); +} + +static void +name_vanished_callback (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + DBusWatch *watch = user_data; + + meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id); +} + +static DBusWatch * +make_dbus_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + MetaIdleMonitor *monitor) +{ + DBusWatch *watch; + + watch = g_slice_new (DBusWatch); + watch->dbus_monitor = g_object_ref (skeleton); + watch->monitor = g_object_ref (monitor); + watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation)); + watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation), + watch->dbus_name, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, /* appeared */ + name_vanished_callback, + watch, NULL); + + return watch; +} + +static gboolean +handle_add_idle_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + guint64 interval, + MetaIdleMonitor *monitor) +{ + DBusWatch *watch; + + watch = make_dbus_watch (skeleton, invocation, monitor); + watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval, + dbus_idle_callback, watch, destroy_dbus_watch); + + meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id); + + return TRUE; +} + +static gboolean +handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + MetaIdleMonitor *monitor) +{ + DBusWatch *watch; + + watch = make_dbus_watch (skeleton, invocation, monitor); + watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor, + dbus_idle_callback, watch, + destroy_dbus_watch); + + meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id); + + return TRUE; +} + +static gboolean +handle_remove_watch (MetaDBusIdleMonitor *skeleton, + GDBusMethodInvocation *invocation, + guint id, + MetaIdleMonitor *monitor) +{ + meta_idle_monitor_remove_watch (monitor, id); + meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation); + + return TRUE; +} + +static void +create_monitor_skeleton (GDBusObjectManagerServer *manager, + MetaIdleMonitor *monitor, + const char *path) +{ + MetaDBusIdleMonitor *skeleton; + MetaDBusObjectSkeleton *object; + + skeleton = meta_dbus_idle_monitor_skeleton_new (); + g_signal_connect_object (skeleton, "handle-add-idle-watch", + G_CALLBACK (handle_add_idle_watch), monitor, 0); + g_signal_connect_object (skeleton, "handle-add-user-active-watch", + G_CALLBACK (handle_add_user_active_watch), monitor, 0); + g_signal_connect_object (skeleton, "handle-remove-watch", + G_CALLBACK (handle_remove_watch), monitor, 0); + g_signal_connect_object (skeleton, "handle-get-idletime", + G_CALLBACK (handle_get_idletime), monitor, 0); + + object = meta_dbus_object_skeleton_new (path); + meta_dbus_object_skeleton_set_idle_monitor (object, skeleton); + + g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); +} + +static void +on_device_added (ClutterDeviceManager *device_manager, + ClutterInputDevice *device, + GDBusObjectManagerServer *manager) +{ + + MetaIdleMonitor *monitor; + int device_id; + char *path; + + device_id = clutter_input_device_get_device_id (device); + monitor = meta_idle_monitor_get_for_device (device_id); + path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); + + create_monitor_skeleton (manager, monitor, path); + g_free (path); +} + +static void +on_device_removed (ClutterDeviceManager *device_manager, + ClutterInputDevice *device, + GDBusObjectManagerServer *manager) +{ + int device_id; + char *path; + + device_id = clutter_input_device_get_device_id (device); + path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); + g_dbus_object_manager_server_unexport (manager, path); + g_free (path); +} + +static void +on_bus_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + GDBusObjectManagerServer *manager; + ClutterDeviceManager *device_manager; + MetaIdleMonitor *monitor; + GSList *devices, *iter; + char *path; + + manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor"); + + /* We never clear the core monitor, as that's supposed to cumulate idle times from + all devices */ + monitor = meta_idle_monitor_get_core (); + path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core"); + create_monitor_skeleton (manager, monitor, path); + g_free (path); + + device_manager = clutter_device_manager_get_default (); + devices = clutter_device_manager_list_devices (device_manager); + + for (iter = devices; iter; iter = iter->next) + on_device_added (device_manager, iter->data, manager); + + g_slist_free (devices); + + g_signal_connect_object (device_manager, "device-added", + G_CALLBACK (on_device_added), manager, 0); + g_signal_connect_object (device_manager, "device-removed", + G_CALLBACK (on_device_removed), manager, 0); + + g_dbus_object_manager_server_set_connection (manager, connection); +} + +static void +on_name_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + meta_verbose ("Acquired name %s\n", name); +} + +static void +on_name_lost (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + meta_verbose ("Lost or failed to acquire name %s\n", name); +} + +void +meta_idle_monitor_init_dbus (void) +{ + static int dbus_name_id; + + if (dbus_name_id > 0) + return; + + dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, + "org.gnome.Mutter.IdleMonitor", + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + (meta_get_replace_current_wm () ? + G_BUS_NAME_OWNER_FLAGS_REPLACE : 0), + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, NULL); +} diff --git a/src/core/meta-idle-monitor-private.h b/src/backends/meta-idle-monitor-dbus.h similarity index 89% rename from src/core/meta-idle-monitor-private.h rename to src/backends/meta-idle-monitor-dbus.h index 6854ebe4c..a0d703f0e 100644 --- a/src/core/meta-idle-monitor-private.h +++ b/src/backends/meta-idle-monitor-dbus.h @@ -1,8 +1,8 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* +/* * Copyright 2013 Red Hat, Inc. - * + * * 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 @@ -12,7 +12,7 @@ * 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, see . * @@ -20,9 +20,9 @@ * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c */ -#include - -void meta_idle_monitor_handle_xevent_all (XEvent *xevent); - +#ifndef META_IDLE_MONITOR_DBUS_H +#define META_IDLE_MONITOR_DBUS_H void meta_idle_monitor_init_dbus (void); + +#endif diff --git a/src/backends/meta-idle-monitor-private.h b/src/backends/meta-idle-monitor-private.h new file mode 100644 index 000000000..ea414e162 --- /dev/null +++ b/src/backends/meta-idle-monitor-private.h @@ -0,0 +1,65 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_PRIVATE_H +#define META_IDLE_MONITOR_PRIVATE_H + +#include +#include "display-private.h" + +#include +#include + +typedef struct +{ + MetaIdleMonitor *monitor; + guint id; + MetaIdleMonitorWatchFunc callback; + gpointer user_data; + GDestroyNotify notify; + guint64 timeout_msec; + int idle_source_id; +} MetaIdleMonitorWatch; + +struct _MetaIdleMonitor +{ + GObject parent_instance; + + GHashTable *watches; + int device_id; +}; + +struct _MetaIdleMonitorClass +{ + GObjectClass parent_class; + + gint64 (*get_idletime) (MetaIdleMonitor *monitor); + MetaIdleMonitorWatch * (*make_watch) (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify); +}; + +void _meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch); + +#endif /* META_IDLE_MONITOR_PRIVATE_H */ diff --git a/src/backends/meta-idle-monitor.c b/src/backends/meta-idle-monitor.c new file mode 100644 index 000000000..4c4357af6 --- /dev/null +++ b/src/backends/meta-idle-monitor.c @@ -0,0 +1,367 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +/** + * SECTION:idle-monitor + * @title: MetaIdleMonitor + * @short_description: Mutter idle counter (similar to X's IDLETIME) + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include "meta-idle-monitor-private.h" +#include "meta-idle-monitor-dbus.h" +#include "backends/x11/meta-idle-monitor-xsync.h" +#include "backends/native/meta-idle-monitor-native.h" + +G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer)); + +enum +{ + PROP_0, + PROP_DEVICE_ID, + PROP_LAST, +}; + +static GParamSpec *obj_props[PROP_LAST]; + +G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT) + +static MetaIdleMonitor *device_monitors[256]; +static int device_id_max; + +void +_meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch) +{ + MetaIdleMonitor *monitor; + guint id; + gboolean is_user_active_watch; + + monitor = watch->monitor; + g_object_ref (monitor); + + if (watch->idle_source_id) + { + g_source_remove (watch->idle_source_id); + watch->idle_source_id = 0; + } + + id = watch->id; + is_user_active_watch = (watch->timeout_msec == 0); + + if (watch->callback) + watch->callback (monitor, id, watch->user_data); + + if (is_user_active_watch) + meta_idle_monitor_remove_watch (monitor, id); + + g_object_unref (monitor); +} + +static void +meta_idle_monitor_dispose (GObject *object) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + + g_clear_pointer (&monitor->watches, g_hash_table_destroy); + + G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object); +} + +static void +meta_idle_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + + switch (prop_id) + { + case PROP_DEVICE_ID: + g_value_set_int (value, monitor->device_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_idle_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); + switch (prop_id) + { + case PROP_DEVICE_ID: + monitor->device_id = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_idle_monitor_class_init (MetaIdleMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = meta_idle_monitor_dispose; + object_class->get_property = meta_idle_monitor_get_property; + object_class->set_property = meta_idle_monitor_set_property; + + /** + * MetaIdleMonitor:device_id: + * + * The device to listen to idletime on. + */ + obj_props[PROP_DEVICE_ID] = + g_param_spec_int ("device-id", + "Device ID", + "The device to listen to idletime on", + 0, 255, 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]); +} + +static void +meta_idle_monitor_init (MetaIdleMonitor *monitor) +{ +} + +static GType +get_idle_monitor_type (void) +{ + if (meta_is_wayland_compositor ()) + return META_TYPE_IDLE_MONITOR_NATIVE; + else + return META_TYPE_IDLE_MONITOR_XSYNC; +} + +static void +ensure_device_monitor (int device_id) +{ + if (device_monitors[device_id]) + return; + + device_monitors[device_id] = g_object_new (get_idle_monitor_type (), + "device-id", device_id, + NULL); + device_id_max = MAX (device_id_max, device_id); +} + +/* FIXME -- destroy device monitors at some point */ +G_GNUC_UNUSED static void +destroy_device_monitor (int device_id) +{ + g_clear_object (&device_monitors[device_id]); + if (device_id == device_id_max) + device_id_max--; +} + +/** + * meta_idle_monitor_get_core: + * + * Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global + * idletime for all devices. To track device-specific idletime, + * use meta_idle_monitor_get_for_device(). + */ +MetaIdleMonitor * +meta_idle_monitor_get_core (void) +{ + ensure_device_monitor (0); + return device_monitors[0]; +} + +/** + * meta_idle_monitor_get_for_device: + * @device_id: the device to get the idle time for. + * + * Returns: (transfer none): a new #MetaIdleMonitor that tracks the + * device-specific idletime for @device. To track server-global idletime + * for all devices, use meta_idle_monitor_get_core(). + */ +MetaIdleMonitor * +meta_idle_monitor_get_for_device (int device_id) +{ + g_return_val_if_fail (device_id > 0 && device_id < 256, NULL); + + ensure_device_monitor (device_id); + return device_monitors[device_id]; +} + +static MetaIdleMonitorWatch * +make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + watch = META_IDLE_MONITOR_GET_CLASS (monitor)->make_watch (monitor, + timeout_msec, + callback, + user_data, + notify); + + g_hash_table_insert (monitor->watches, + GUINT_TO_POINTER (watch->id), + watch); + return watch; +} + +/** + * meta_idle_monitor_add_idle_watch: + * @monitor: A #MetaIdleMonitor + * @interval_msec: The idletime interval, in milliseconds + * @callback: (allow-none): The callback to call when the user has + * accumulated @interval_msec milliseconds of idle time. + * @user_data: (allow-none): The user data to pass to the callback + * @notify: A #GDestroyNotify + * + * Returns: a watch id + * + * Adds a watch for a specific idle time. The callback will be called + * when the user has accumulated @interval_msec milliseconds of idle time. + * This function will return an ID that can either be passed to + * meta_idle_monitor_remove_watch(), or can be used to tell idle time + * watches apart if you have more than one. + * + * Also note that this function will only care about positive transitions + * (user's idle time exceeding a certain time). If you want to know about + * when the user has become active, use + * meta_idle_monitor_add_user_active_watch(). + */ +guint +meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor, + guint64 interval_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); + g_return_val_if_fail (interval_msec > 0, 0); + + watch = make_watch (monitor, + interval_msec, + callback, + user_data, + notify); + + return watch->id; +} + +/** + * meta_idle_monitor_add_user_active_watch: + * @monitor: A #MetaIdleMonitor + * @callback: (allow-none): The callback to call when the user is + * active again. + * @user_data: (allow-none): The user data to pass to the callback + * @notify: A #GDestroyNotify + * + * Returns: a watch id + * + * Add a one-time watch to know when the user is active again. + * Note that this watch is one-time and will de-activate after the + * function is called, for efficiency purposes. It's most convenient + * to call this when an idle watch, as added by + * meta_idle_monitor_add_idle_watch(), has triggered. + */ +guint +meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatch *watch; + + g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); + + watch = make_watch (monitor, + 0, + callback, + user_data, + notify); + + return watch->id; +} + +/** + * meta_idle_monitor_remove_watch: + * @monitor: A #MetaIdleMonitor + * @id: A watch ID + * + * Removes an idle time watcher, previously added by + * meta_idle_monitor_add_idle_watch() or + * meta_idle_monitor_add_user_active_watch(). + */ +void +meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor, + guint id) +{ + g_return_if_fail (META_IS_IDLE_MONITOR (monitor)); + + g_object_ref (monitor); + g_hash_table_remove (monitor->watches, + GUINT_TO_POINTER (id)); + g_object_unref (monitor); +} + +/** + * meta_idle_monitor_get_idletime: + * @monitor: A #MetaIdleMonitor + * + * Returns: The current idle time, in milliseconds, or -1 for not supported + */ +gint64 +meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor) +{ + return META_IDLE_MONITOR_GET_CLASS (monitor)->get_idletime (monitor); +} + +void +meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent) +{ + int i; + + if (meta_is_wayland_compositor ()) + return; + + for (i = 0; i <= device_id_max; i++) + if (device_monitors[i]) + meta_idle_monitor_xsync_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); +} diff --git a/src/core/monitor-config.c b/src/backends/meta-monitor-config.c similarity index 99% rename from src/core/monitor-config.c rename to src/backends/meta-monitor-config.c index a7e4ed546..f7ddce527 100644 --- a/src/core/monitor-config.c +++ b/src/backends/meta-monitor-config.c @@ -34,13 +34,14 @@ #include "config.h" +#include "meta-monitor-config.h" + #include #include #include #include #include -#include "monitor-private.h" /* These structures represent the intended/persistent configuration, as stored in the monitors.xml file. diff --git a/src/backends/meta-monitor-config.h b/src/backends/meta-monitor-config.h new file mode 100644 index 000000000..840156925 --- /dev/null +++ b/src/backends/meta-monitor-config.h @@ -0,0 +1,55 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * 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, see . + */ + +#ifndef META_MONITOR_CONFIG_H +#define META_MONITOR_CONFIG_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ()) +#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig)) +#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) +#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG)) +#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG)) +#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) + +GType meta_monitor_config_get_type (void) G_GNUC_CONST; + +MetaMonitorConfig *meta_monitor_config_new (void); + +gboolean meta_monitor_config_match_current (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +void meta_monitor_config_make_default (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +void meta_monitor_config_update_current (MetaMonitorConfig *config, + MetaMonitorManager *manager); +void meta_monitor_config_make_persistent (MetaMonitorConfig *config); + +void meta_monitor_config_restore_previous (MetaMonitorConfig *config, + MetaMonitorManager *manager); + +#endif /* META_MONITOR_CONFIG_H */ diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c new file mode 100644 index 000000000..46cea9396 --- /dev/null +++ b/src/backends/meta-monitor-manager-dummy.c @@ -0,0 +1,227 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001, 2002 Havoc Pennington + * Copyright (C) 2002, 2003 Red Hat Inc. + * Some ICCCM manager selection code derived from fvwm2, + * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * 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, see . + */ + +#include "config.h" + +#include "meta-monitor-manager-dummy.h" + +#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) + +struct _MetaMonitorManagerDummy +{ + MetaMonitorManager parent_instance; +}; + +struct _MetaMonitorManagerDummyClass +{ + MetaMonitorManagerClass parent_class; +}; + +G_DEFINE_TYPE (MetaMonitorManagerDummy, meta_monitor_manager_dummy, META_TYPE_MONITOR_MANAGER); + +static void +meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager) +{ + manager->max_screen_width = 65535; + manager->max_screen_height = 65535; + manager->screen_width = 1024; + manager->screen_height = 768; + + manager->modes = g_new0 (MetaMonitorMode, 1); + manager->n_modes = 1; + + manager->modes[0].mode_id = 0; + manager->modes[0].width = 1024; + manager->modes[0].height = 768; + manager->modes[0].refresh_rate = 60.0; + + manager->crtcs = g_new0 (MetaCRTC, 1); + manager->n_crtcs = 1; + + manager->crtcs[0].crtc_id = 1; + manager->crtcs[0].rect.x = 0; + manager->crtcs[0].rect.y = 0; + manager->crtcs[0].rect.width = manager->modes[0].width; + manager->crtcs[0].rect.height = manager->modes[0].height; + manager->crtcs[0].current_mode = &manager->modes[0]; + manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL; + manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS; + manager->crtcs[0].is_dirty = FALSE; + manager->crtcs[0].logical_monitor = NULL; + + manager->outputs = g_new0 (MetaOutput, 1); + manager->n_outputs = 1; + + manager->outputs[0].crtc = &manager->crtcs[0]; + manager->outputs[0].output_id = 1; + manager->outputs[0].name = g_strdup ("LVDS"); + manager->outputs[0].vendor = g_strdup ("MetaProducts Inc."); + manager->outputs[0].product = g_strdup ("unknown"); + manager->outputs[0].serial = g_strdup ("0xC0FFEE"); + manager->outputs[0].width_mm = 222; + manager->outputs[0].height_mm = 125; + manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + manager->outputs[0].preferred_mode = &manager->modes[0]; + manager->outputs[0].n_modes = 1; + manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 1); + manager->outputs[0].modes[0] = &manager->modes[0]; + manager->outputs[0].n_possible_crtcs = 1; + manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 1); + manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0]; + manager->outputs[0].n_possible_clones = 0; + manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0); + manager->outputs[0].backlight = -1; + manager->outputs[0].backlight_min = 0; + manager->outputs[0].backlight_max = 0; +} + +static void +meta_monitor_manager_dummy_apply_config (MetaMonitorManager *manager, + MetaCRTCInfo **crtcs, + unsigned int n_crtcs, + MetaOutputInfo **outputs, + unsigned int n_outputs) +{ + unsigned i; + int screen_width = 0, screen_height = 0; + + for (i = 0; i < n_crtcs; i++) + { + MetaCRTCInfo *crtc_info = crtcs[i]; + MetaCRTC *crtc = crtc_info->crtc; + crtc->is_dirty = TRUE; + + if (crtc_info->mode == NULL) + { + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + else + { + MetaMonitorMode *mode; + MetaOutput *output; + int i, n_outputs; + int width, height; + + mode = crtc_info->mode; + + if (meta_monitor_transform_is_rotated (crtc_info->transform)) + { + width = mode->height; + height = mode->width; + } + else + { + width = mode->width; + height = mode->height; + } + + crtc->rect.x = crtc_info->x; + crtc->rect.y = crtc_info->y; + crtc->rect.width = width; + crtc->rect.height = height; + crtc->current_mode = mode; + crtc->transform = crtc_info->transform; + + screen_width = MAX (screen_width, crtc_info->x + width); + screen_height = MAX (screen_height, crtc_info->y + height); + + n_outputs = crtc_info->outputs->len; + for (i = 0; i < n_outputs; i++) + { + output = ((MetaOutput**)crtc_info->outputs->pdata)[i]; + + output->is_dirty = TRUE; + output->crtc = crtc; + } + } + } + + for (i = 0; i < n_outputs; i++) + { + MetaOutputInfo *output_info = outputs[i]; + MetaOutput *output = output_info->output; + + output->is_primary = output_info->is_primary; + output->is_presentation = output_info->is_presentation; + } + + /* Disable CRTCs not mentioned in the list */ + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + + crtc->logical_monitor = NULL; + + if (crtc->is_dirty) + { + crtc->is_dirty = FALSE; + continue; + } + + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + + /* Disable outputs not mentioned in the list */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output = &manager->outputs[i]; + + if (output->is_dirty) + { + output->is_dirty = FALSE; + continue; + } + + output->crtc = NULL; + output->is_primary = FALSE; + } + + manager->screen_width = screen_width; + manager->screen_height = screen_height; + + meta_monitor_manager_rebuild_derived (manager); +} + +static void +meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass) +{ + MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); + + manager_class->read_current = meta_monitor_manager_dummy_read_current; + manager_class->apply_configuration = meta_monitor_manager_dummy_apply_config; +} + +static void +meta_monitor_manager_dummy_init (MetaMonitorManagerDummy *manager) +{ +} diff --git a/src/backends/meta-monitor-manager-dummy.h b/src/backends/meta-monitor-manager-dummy.h new file mode 100644 index 000000000..4f1fb349c --- /dev/null +++ b/src/backends/meta-monitor-manager-dummy.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * 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, see . + */ + +#ifndef META_MONITOR_MANAGER_DUMMY_H +#define META_MONITOR_MANAGER_DUMMY_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_MANAGER_DUMMY (meta_monitor_manager_dummy_get_type ()) +#define META_MONITOR_MANAGER_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummy)) +#define META_MONITOR_MANAGER_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummyClass)) +#define META_IS_MONITOR_MANAGER_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_DUMMY)) +#define META_IS_MONITOR_MANAGER_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_DUMMY)) +#define META_MONITOR_MANAGER_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummyClass)) + +typedef struct _MetaMonitorManagerDummyClass MetaMonitorManagerDummyClass; +typedef struct _MetaMonitorManagerDummy MetaMonitorManagerDummy; + +GType meta_monitor_manager_dummy_get_type (void); + +#endif /* META_MONITOR_MANAGER_DUMMY_H */ diff --git a/src/core/monitor.c b/src/backends/meta-monitor-manager.c similarity index 78% rename from src/core/monitor.c rename to src/backends/meta-monitor-manager.c index f006052f4..a437c5fa6 100644 --- a/src/core/monitor.c +++ b/src/backends/meta-monitor-manager.c @@ -25,6 +25,8 @@ #include "config.h" +#include "meta-monitor-manager.h" + #include #include #include @@ -33,11 +35,10 @@ #include #include "util-private.h" #include -#include "monitor-private.h" - -#include "meta-dbus-xrandr.h" - -#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) +#include "meta-monitor-config.h" +#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/x11/meta-monitor-manager-xrandr.h" +#include "meta-monitor-manager-dummy.h" enum { CONFIRM_DISPLAY_CHANGE, @@ -54,313 +55,11 @@ static int signals[SIGNALS_LAST]; static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface); -G_DEFINE_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON, - G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init)); +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON, + G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init)); static void initialize_dbus_interface (MetaMonitorManager *manager); -static void -read_current_dummy (MetaMonitorManager *manager) -{ - /* The dummy monitor config has: - - one enabled output, LVDS, primary, at 0x0 and 1024x768 - - one free CRTC - - two disabled outputs - - three modes, 1024x768, 800x600 and 640x480 - - no clones are possible (use different CRTCs) - - Low-level IDs should be assigned sequentially, to - mimick what XRandR and KMS do - */ - - manager->max_screen_width = 65535; - manager->max_screen_height = 65535; - manager->screen_width = 1024; - manager->screen_height = 768; - - manager->modes = g_new0 (MetaMonitorMode, 6); - manager->n_modes = 6; - - manager->modes[0].mode_id = 1; - manager->modes[0].width = 1024; - manager->modes[0].height = 768; - manager->modes[0].refresh_rate = 60.0; - - manager->modes[1].mode_id = 2; - manager->modes[1].width = 800; - manager->modes[1].height = 600; - manager->modes[1].refresh_rate = 60.0; - - manager->modes[2].mode_id = 3; - manager->modes[2].width = 640; - manager->modes[2].height = 480; - manager->modes[2].refresh_rate = 60.0; - - manager->modes[3].mode_id = 4; - manager->modes[3].width = 1920; - manager->modes[3].height = 1080; - manager->modes[3].refresh_rate = 60.0; - - manager->modes[4].mode_id = 5; - manager->modes[4].width = 1920; - manager->modes[4].height = 1080; - manager->modes[4].refresh_rate = 55.0; - - manager->modes[5].mode_id = 6; - manager->modes[5].width = 1600; - manager->modes[5].height = 900; - manager->modes[5].refresh_rate = 60.0; - - manager->crtcs = g_new0 (MetaCRTC, 3); - manager->n_crtcs = 3; - - manager->crtcs[0].crtc_id = 4; - manager->crtcs[0].rect.x = 0; - manager->crtcs[0].rect.y = 0; - manager->crtcs[0].rect.width = manager->modes[0].width; - manager->crtcs[0].rect.height = manager->modes[0].height; - manager->crtcs[0].current_mode = &manager->modes[0]; - manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL; - manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS; - manager->crtcs[0].is_dirty = FALSE; - manager->crtcs[0].logical_monitor = NULL; - - manager->crtcs[1].crtc_id = 5; - manager->crtcs[1].rect.x = 0; - manager->crtcs[1].rect.y = 0; - manager->crtcs[1].rect.width = 0; - manager->crtcs[1].rect.height = 0; - manager->crtcs[1].current_mode = NULL; - manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL; - manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS; - manager->crtcs[1].is_dirty = FALSE; - manager->crtcs[1].logical_monitor = NULL; - - manager->crtcs[2].crtc_id = 5; - manager->crtcs[2].rect.x = 0; - manager->crtcs[2].rect.y = 0; - manager->crtcs[2].rect.width = 0; - manager->crtcs[2].rect.height = 0; - manager->crtcs[2].current_mode = NULL; - manager->crtcs[2].transform = WL_OUTPUT_TRANSFORM_NORMAL; - manager->crtcs[2].all_transforms = ALL_WL_TRANSFORMS; - manager->crtcs[2].is_dirty = FALSE; - manager->crtcs[2].logical_monitor = NULL; - - manager->outputs = g_new0 (MetaOutput, 3); - manager->n_outputs = 3; - - manager->outputs[0].crtc = NULL; - manager->outputs[0].output_id = 6; - manager->outputs[0].name = g_strdup ("HDMI"); - manager->outputs[0].vendor = g_strdup ("MetaProducts Inc."); - manager->outputs[0].product = g_strdup ("unknown"); - manager->outputs[0].serial = g_strdup ("0xC0F01A"); - manager->outputs[0].width_mm = 510; - manager->outputs[0].height_mm = 287; - manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - manager->outputs[0].preferred_mode = &manager->modes[3]; - manager->outputs[0].n_modes = 5; - manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 5); - manager->outputs[0].modes[0] = &manager->modes[0]; - manager->outputs[0].modes[1] = &manager->modes[1]; - manager->outputs[0].modes[2] = &manager->modes[2]; - manager->outputs[0].modes[3] = &manager->modes[3]; - manager->outputs[0].modes[4] = &manager->modes[4]; - manager->outputs[0].n_possible_crtcs = 3; - manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 3); - manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0]; - manager->outputs[0].possible_crtcs[1] = &manager->crtcs[1]; - manager->outputs[0].possible_crtcs[2] = &manager->crtcs[2]; - manager->outputs[0].n_possible_clones = 0; - manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0); - manager->outputs[0].backlight = -1; - manager->outputs[0].backlight_min = 0; - manager->outputs[0].backlight_max = 0; - - manager->outputs[1].crtc = &manager->crtcs[0]; - manager->outputs[1].output_id = 7; - manager->outputs[1].name = g_strdup ("LVDS"); - manager->outputs[1].vendor = g_strdup ("MetaProducts Inc."); - manager->outputs[1].product = g_strdup ("unknown"); - manager->outputs[1].serial = g_strdup ("0xC0FFEE"); - manager->outputs[1].width_mm = 222; - manager->outputs[1].height_mm = 125; - manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - manager->outputs[1].preferred_mode = &manager->modes[5]; - manager->outputs[1].n_modes = 4; - manager->outputs[1].modes = g_new0 (MetaMonitorMode *, 4); - manager->outputs[1].modes[0] = &manager->modes[0]; - manager->outputs[1].modes[1] = &manager->modes[1]; - manager->outputs[1].modes[2] = &manager->modes[2]; - manager->outputs[1].modes[3] = &manager->modes[5]; - manager->outputs[1].n_possible_crtcs = 3; - manager->outputs[1].possible_crtcs = g_new0 (MetaCRTC *, 3); - manager->outputs[1].possible_crtcs[0] = &manager->crtcs[0]; - manager->outputs[1].possible_crtcs[1] = &manager->crtcs[1]; - manager->outputs[1].possible_crtcs[2] = &manager->crtcs[2]; - manager->outputs[1].n_possible_clones = 0; - manager->outputs[1].possible_clones = g_new0 (MetaOutput *, 0); - manager->outputs[1].backlight = -1; - manager->outputs[1].backlight_min = 0; - manager->outputs[1].backlight_max = 0; - - manager->outputs[2].crtc = NULL; - manager->outputs[2].output_id = 8; - manager->outputs[2].name = g_strdup ("VGA"); - manager->outputs[2].vendor = g_strdup ("MetaProducts Inc."); - manager->outputs[2].product = g_strdup ("unknown"); - manager->outputs[2].serial = g_strdup ("0xC4FE"); - manager->outputs[2].width_mm = 309; - manager->outputs[2].height_mm = 174; - manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - manager->outputs[2].preferred_mode = &manager->modes[0]; - manager->outputs[2].n_modes = 3; - manager->outputs[2].modes = g_new0 (MetaMonitorMode *, 3); - manager->outputs[2].modes[0] = &manager->modes[0]; - manager->outputs[2].modes[1] = &manager->modes[1]; - manager->outputs[2].modes[2] = &manager->modes[2]; - manager->outputs[2].n_possible_crtcs = 3; - manager->outputs[2].possible_crtcs = g_new0 (MetaCRTC *, 3); - manager->outputs[2].possible_crtcs[0] = &manager->crtcs[0]; - manager->outputs[2].possible_crtcs[1] = &manager->crtcs[1]; - manager->outputs[2].possible_crtcs[2] = &manager->crtcs[2]; - manager->outputs[2].n_possible_clones = 0; - manager->outputs[2].possible_clones = g_new0 (MetaOutput *, 0); - manager->outputs[2].backlight = -1; - manager->outputs[2].backlight_min = 0; - manager->outputs[2].backlight_max = 0; -} - -static void -apply_config_dummy (MetaMonitorManager *manager, - MetaCRTCInfo **crtcs, - unsigned int n_crtcs, - MetaOutputInfo **outputs, - unsigned int n_outputs) -{ - unsigned i; - int screen_width = 0, screen_height = 0; - - for (i = 0; i < n_crtcs; i++) - { - MetaCRTCInfo *crtc_info = crtcs[i]; - MetaCRTC *crtc = crtc_info->crtc; - crtc->is_dirty = TRUE; - - if (crtc_info->mode == NULL) - { - crtc->rect.x = 0; - crtc->rect.y = 0; - crtc->rect.width = 0; - crtc->rect.height = 0; - crtc->current_mode = NULL; - } - else - { - MetaMonitorMode *mode; - MetaOutput *output; - int i, n_outputs; - int width, height; - - mode = crtc_info->mode; - - if (meta_monitor_transform_is_rotated (crtc_info->transform)) - { - width = mode->height; - height = mode->width; - } - else - { - width = mode->width; - height = mode->height; - } - - crtc->rect.x = crtc_info->x; - crtc->rect.y = crtc_info->y; - crtc->rect.width = width; - crtc->rect.height = height; - crtc->current_mode = mode; - crtc->transform = crtc_info->transform; - - screen_width = MAX (screen_width, crtc_info->x + width); - screen_height = MAX (screen_height, crtc_info->y + height); - - n_outputs = crtc_info->outputs->len; - for (i = 0; i < n_outputs; i++) - { - output = ((MetaOutput**)crtc_info->outputs->pdata)[i]; - - output->is_dirty = TRUE; - output->crtc = crtc; - } - } - } - - for (i = 0; i < n_outputs; i++) - { - MetaOutputInfo *output_info = outputs[i]; - MetaOutput *output = output_info->output; - - output->is_primary = output_info->is_primary; - output->is_presentation = output_info->is_presentation; - } - - /* Disable CRTCs not mentioned in the list */ - for (i = 0; i < manager->n_crtcs; i++) - { - MetaCRTC *crtc = &manager->crtcs[i]; - - crtc->logical_monitor = NULL; - - if (crtc->is_dirty) - { - crtc->is_dirty = FALSE; - continue; - } - - crtc->rect.x = 0; - crtc->rect.y = 0; - crtc->rect.width = 0; - crtc->rect.height = 0; - crtc->current_mode = NULL; - } - - /* Disable outputs not mentioned in the list */ - for (i = 0; i < manager->n_outputs; i++) - { - MetaOutput *output = &manager->outputs[i]; - - if (output->is_dirty) - { - output->is_dirty = FALSE; - continue; - } - - output->crtc = NULL; - output->is_primary = FALSE; - } - - manager->screen_width = screen_width; - manager->screen_height = screen_height; - - meta_monitor_manager_rebuild_derived (manager); -} - -static GBytes * -read_edid_dummy (MetaMonitorManager *manager, - MetaOutput *output) -{ - return NULL; -} - -static char * -get_edid_file_dummy (MetaMonitorManager *manager, - MetaOutput *output) -{ - return NULL; -} - static void meta_monitor_manager_init (MetaMonitorManager *manager) { @@ -469,6 +168,40 @@ make_logical_config (MetaMonitorManager *manager) manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE); } +static GType +get_default_backend (void) +{ +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + return META_TYPE_MONITOR_MANAGER_KMS; +#endif + +#if defined(CLUTTER_WINDOWING_X11) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11)) + { + /* If we're a Wayland compositor using the X11 backend, + * we're a nested configuration, so return the dummy + * monitor setup. */ + if (meta_is_wayland_compositor ()) + return META_TYPE_MONITOR_MANAGER_DUMMY; + else + return META_TYPE_MONITOR_MANAGER_XRANDR; + } +#endif + +#if defined(CLUTTER_WINDOWING_WAYLAND) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND)) + { + /* Use the dummy implementation on Wayland for now. + * In the future, we should support wl_fullscreen_output + * which will have CRTC management in the protocol. */ + return META_TYPE_MONITOR_MANAGER_DUMMY; + } +#endif + + g_assert_not_reached (); +} + static MetaMonitorManager * meta_monitor_manager_new (void) { @@ -478,7 +211,7 @@ meta_monitor_manager_new (void) env = g_getenv ("META_DEBUG_MULTIMONITOR"); if (env == NULL) - type = META_TYPE_MONITOR_MANAGER_XRANDR; + type = get_default_backend (); else if (strcmp (env, "xrandr") == 0) type = META_TYPE_MONITOR_MANAGER_XRANDR; else @@ -513,17 +246,18 @@ meta_monitor_manager_constructed (GObject *object) MetaOutput *old_outputs; MetaCRTC *old_crtcs; MetaMonitorMode *old_modes; - int n_old_outputs; + unsigned int n_old_outputs, n_old_modes; old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; old_modes = manager->modes; + n_old_modes = manager->n_modes; old_crtcs = manager->crtcs; read_current_config (manager); meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); - g_free (old_modes); + meta_monitor_manager_free_mode_array (old_modes, n_old_modes); g_free (old_crtcs); } @@ -565,19 +299,39 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs, g_free (old_outputs[i].modes); g_free (old_outputs[i].possible_crtcs); g_free (old_outputs[i].possible_clones); + + if (old_outputs[i].driver_notify) + old_outputs[i].driver_notify (&old_outputs[i]); } g_free (old_outputs); } +void +meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes, + int n_old_modes) +{ + int i; + + for (i = 0; i < n_old_modes; i++) + { + g_free (old_modes[i].name); + + if (old_modes[i].driver_notify) + old_modes[i].driver_notify (&old_modes[i]); + } + + g_free (old_modes); +} + static void meta_monitor_manager_finalize (GObject *object) { MetaMonitorManager *manager = META_MONITOR_MANAGER (object); meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs); + meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes); g_free (manager->monitor_infos); - g_free (manager->modes); g_free (manager->crtcs); G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object); @@ -635,6 +389,20 @@ meta_monitor_manager_get_property (GObject *object, } } +static GBytes * +meta_monitor_manager_real_read_edid (MetaMonitorManager *manager, + MetaOutput *output) +{ + return NULL; +} + +static char * +meta_monitor_manager_real_get_edid_file (MetaMonitorManager *manager, + MetaOutput *output) +{ + return NULL; +} + static void meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) { @@ -646,10 +414,8 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) object_class->dispose = meta_monitor_manager_dispose; object_class->finalize = meta_monitor_manager_finalize; - klass->read_current = read_current_dummy; - klass->apply_configuration = apply_config_dummy; - klass->get_edid_file = get_edid_file_dummy; - klass->read_edid = read_edid_dummy; + klass->get_edid_file = meta_monitor_manager_real_get_edid_file; + klass->read_edid = meta_monitor_manager_real_read_edid; signals[CONFIRM_DISPLAY_CHANGE] = g_signal_new ("confirm-display-change", @@ -1453,12 +1219,21 @@ meta_monitor_manager_get_resources (MetaMonitorManager *manager, MetaOutput **outputs, unsigned int *n_outputs) { - *modes = manager->modes; - *n_modes = manager->n_modes; - *crtcs = manager->crtcs; - *n_crtcs = manager->n_crtcs; - *outputs = manager->outputs; - *n_outputs = manager->n_outputs; + if (modes) + { + *modes = manager->modes; + *n_modes = manager->n_modes; + } + if (crtcs) + { + *crtcs = manager->crtcs; + *n_crtcs = manager->n_crtcs; + } + if (outputs) + { + *outputs = manager->outputs; + *n_outputs = manager->n_outputs; + } } int diff --git a/src/core/monitor-private.h b/src/backends/meta-monitor-manager.h similarity index 78% rename from src/core/monitor-private.h rename to src/backends/meta-monitor-manager.h index 48cad40d1..0feb73d25 100644 --- a/src/core/monitor-private.h +++ b/src/backends/meta-monitor-manager.h @@ -42,31 +42,16 @@ #include #include "stack-tracker.h" #include "ui.h" -#ifdef HAVE_WAYLAND #include -#endif -#include "meta-xrandr-shared.h" -#include "meta-dbus-xrandr.h" +#include "meta-display-config-shared.h" +#include "meta-dbus-display-config.h" typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass; typedef struct _MetaMonitorManager MetaMonitorManager; typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass; typedef struct _MetaMonitorConfig MetaMonitorConfig; -#ifndef HAVE_WAYLAND -enum wl_output_transform { - WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_90, - WL_OUTPUT_TRANSFORM_180, - WL_OUTPUT_TRANSFORM_270, - WL_OUTPUT_TRANSFORM_FLIPPED, - WL_OUTPUT_TRANSFORM_FLIPPED_90, - WL_OUTPUT_TRANSFORM_FLIPPED_180, - WL_OUTPUT_TRANSFORM_FLIPPED_270 -}; -#endif - typedef struct _MetaOutput MetaOutput; typedef struct _MetaCRTC MetaCRTC; typedef struct _MetaMonitorMode MetaMonitorMode; @@ -115,6 +100,9 @@ struct _MetaOutput gboolean is_primary; gboolean is_presentation; + gpointer driver_private; + GDestroyNotify driver_notify; + /* get a new preferred mode on hotplug events, to handle dynamic guest resizing */ gboolean hotplug_mode_update; }; @@ -134,16 +122,23 @@ struct _MetaCRTC /* Used when changing configuration */ gboolean is_dirty; + + /* Updated by MetaCursorTracker */ + gboolean has_hw_cursor; }; struct _MetaMonitorMode { /* The low-level ID of this mode, used to apply back configuration */ glong mode_id; + char *name; int width; int height; float refresh_rate; + + gpointer driver_private; + GDestroyNotify driver_notify; }; /** @@ -232,8 +227,6 @@ struct _MetaMonitorManager CRTCs refer to stuff that can drive outputs (like encoders, but less tied to the HW), while monitor_infos refer to logical ones. - - See also the comment in monitor-private.h */ MetaOutput *outputs; unsigned int n_outputs; @@ -340,50 +333,13 @@ void meta_monitor_manager_apply_configuration (MetaMonitorManager void meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager, gboolean ok); -#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ()) -#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr)) -#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) -#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR)) -#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR)) -#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) - -typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass; -typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr; - -GType meta_monitor_manager_xrandr_get_type (void); - -#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ()) -#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig)) -#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) -#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG)) -#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG)) -#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass)) - -GType meta_monitor_config_get_type (void) G_GNUC_CONST; - -MetaMonitorConfig *meta_monitor_config_new (void); - -gboolean meta_monitor_config_match_current (MetaMonitorConfig *config, - MetaMonitorManager *manager); - -gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config, - MetaMonitorManager *manager); - -void meta_monitor_config_make_default (MetaMonitorConfig *config, - MetaMonitorManager *manager); - -void meta_monitor_config_update_current (MetaMonitorConfig *config, - MetaMonitorManager *manager); -void meta_monitor_config_make_persistent (MetaMonitorConfig *config); - -void meta_monitor_config_restore_previous (MetaMonitorConfig *config, - MetaMonitorManager *manager); - void meta_crtc_info_free (MetaCRTCInfo *info); void meta_output_info_free (MetaOutputInfo *info); void meta_monitor_manager_free_output_array (MetaOutput *old_outputs, int n_old_outputs); +void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes, + int n_old_modes); gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager); /* Returns true if transform causes width and height to be inverted diff --git a/src/backends/native/meta-idle-monitor-native.c b/src/backends/native/meta-idle-monitor-native.c new file mode 100644 index 000000000..13d8d516f --- /dev/null +++ b/src/backends/native/meta-idle-monitor-native.c @@ -0,0 +1,219 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-native.h" +#include "meta-idle-monitor-private.h" + +#include +#include "display-private.h" + +#include + +struct _MetaIdleMonitorNative +{ + MetaIdleMonitor parent; + + guint64 last_event_time; +}; + +struct _MetaIdleMonitorNativeClass +{ + MetaIdleMonitorClass parent_class; +}; + +typedef struct { + MetaIdleMonitorWatch base; + + GSource *timeout_source; +} MetaIdleMonitorWatchNative; + +G_DEFINE_TYPE (MetaIdleMonitorNative, meta_idle_monitor_native, META_TYPE_IDLE_MONITOR) + +static gint64 +meta_idle_monitor_native_get_idletime (MetaIdleMonitor *monitor) +{ + MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); + + return (g_get_monotonic_time () - monitor_native->last_event_time) / 1000; +} + +static guint32 +get_next_watch_serial (void) +{ + static guint32 serial = 0; + g_atomic_int_inc (&serial); + return serial; +} + +static gboolean +native_dispatch_timeout (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + MetaIdleMonitorWatchNative *watch_native = user_data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; + + _meta_idle_monitor_watch_fire (watch); + g_source_set_ready_time (watch_native->timeout_source, -1); + return TRUE; +} + +static GSourceFuncs native_source_funcs = { + NULL, /* prepare */ + NULL, /* check */ + native_dispatch_timeout, + NULL, /* finalize */ +}; + +static void +free_watch (gpointer data) +{ + MetaIdleMonitorWatchNative *watch_native = data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; + MetaIdleMonitor *monitor = watch->monitor; + + g_object_ref (monitor); + + if (watch->idle_source_id) + { + g_source_remove (watch->idle_source_id); + watch->idle_source_id = 0; + } + + if (watch->notify != NULL) + watch->notify (watch->user_data); + + if (watch_native->timeout_source != NULL) + g_source_destroy (watch_native->timeout_source); + + g_object_unref (monitor); + g_slice_free (MetaIdleMonitorWatchNative, watch_native); +} + +static MetaIdleMonitorWatch * +meta_idle_monitor_native_make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorWatchNative *watch_native; + MetaIdleMonitorWatch *watch; + MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); + + watch_native = g_slice_new0 (MetaIdleMonitorWatchNative); + watch = (MetaIdleMonitorWatch *) watch_native; + + watch->monitor = monitor; + watch->id = get_next_watch_serial (); + watch->callback = callback; + watch->user_data = user_data; + watch->notify = notify; + watch->timeout_msec = timeout_msec; + + if (timeout_msec != 0) + { + GSource *source = g_source_new (&native_source_funcs, sizeof (GSource)); + + g_source_set_callback (source, NULL, watch, NULL); + g_source_set_ready_time (source, monitor_native->last_event_time + timeout_msec * 1000); + g_source_attach (source, NULL); + g_source_unref (source); + + watch_native->timeout_source = source; + } + + return watch; +} + +static void +meta_idle_monitor_native_class_init (MetaIdleMonitorNativeClass *klass) +{ + MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass); + + idle_monitor_class->get_idletime = meta_idle_monitor_native_get_idletime; + idle_monitor_class->make_watch = meta_idle_monitor_native_make_watch; +} + +static void +meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor_native) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_native); + + monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch); +} + +typedef struct { + MetaIdleMonitorNative *monitor_native; + GList *fired_watches; +} CheckNativeClosure; + +static gboolean +check_native_watch (gpointer key, + gpointer value, + gpointer user_data) +{ + MetaIdleMonitorWatchNative *watch_native = value; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; + CheckNativeClosure *closure = user_data; + gboolean steal; + + if (watch->timeout_msec == 0) + { + closure->fired_watches = g_list_prepend (closure->fired_watches, watch); + steal = TRUE; + } + else + { + g_source_set_ready_time (watch_native->timeout_source, + closure->monitor_native->last_event_time + + watch->timeout_msec * 1000); + steal = FALSE; + } + + return steal; +} + +static void +fire_native_watch (gpointer watch, + gpointer data) +{ + _meta_idle_monitor_watch_fire (watch); +} + +void +meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor) +{ + MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); + CheckNativeClosure closure; + + monitor_native->last_event_time = g_get_monotonic_time (); + + closure.monitor_native = monitor_native; + closure.fired_watches = NULL; + g_hash_table_foreach_steal (monitor->watches, check_native_watch, &closure); + + g_list_foreach (closure.fired_watches, fire_native_watch, NULL); + g_list_free (closure.fired_watches); +} diff --git a/src/backends/native/meta-idle-monitor-native.h b/src/backends/native/meta-idle-monitor-native.h new file mode 100644 index 000000000..37745c489 --- /dev/null +++ b/src/backends/native/meta-idle-monitor-native.h @@ -0,0 +1,43 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_NATIVE_H +#define META_IDLE_MONITOR_NATIVE_H + +#include +#include + +#define META_TYPE_IDLE_MONITOR_NATIVE (meta_idle_monitor_native_get_type ()) +#define META_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNative)) +#define META_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass)) +#define META_IS_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_NATIVE)) +#define META_IS_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_NATIVE)) +#define META_IDLE_MONITOR_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass)) + +typedef struct _MetaIdleMonitorNative MetaIdleMonitorNative; +typedef struct _MetaIdleMonitorNativeClass MetaIdleMonitorNativeClass; + +GType meta_idle_monitor_native_get_type (void); + +void meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor); + +#endif /* META_IDLE_MONITOR_NATIVE_H */ diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c new file mode 100644 index 000000000..698c60608 --- /dev/null +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -0,0 +1,939 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat Inc. + * + * 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. + * + * Author: Giovanni Campagna + */ + +#include "config.h" + +#include "meta-monitor-manager-kms.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "edid.h" + +#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) + +typedef struct { + drmModeConnector *connector; + + unsigned n_encoders; + drmModeEncoderPtr *encoders; + drmModeEncoderPtr current_encoder; + + /* bitmasks of encoder position in the resources array */ + uint32_t encoder_mask; + uint32_t enc_clone_mask; + + uint32_t dpms_prop_id; + uint32_t edid_blob_id; +} MetaOutputKms; + +struct _MetaMonitorManagerKms +{ + MetaMonitorManager parent_instance; + + int fd; + + drmModeConnector **connectors; + unsigned int n_connectors; + + drmModeEncoder **encoders; + unsigned int n_encoders; + + drmModeEncoder *current_encoder; +}; + +struct _MetaMonitorManagerKmsClass +{ + MetaMonitorManagerClass parent_class; +}; + +G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER); + +static void +free_resources (MetaMonitorManagerKms *manager_kms) +{ + unsigned i; + + for (i = 0; i < manager_kms->n_encoders; i++) + drmModeFreeEncoder (manager_kms->encoders[i]); + for (i = 0; i < manager_kms->n_connectors; i++) + drmModeFreeConnector (manager_kms->connectors[i]); + + g_free (manager_kms->encoders); + g_free (manager_kms->connectors); +} + +static int +compare_outputs (const void *one, + const void *two) +{ + const MetaOutput *o_one = one, *o_two = two; + + return strcmp (o_one->name, o_two->name); +} + +static char * +make_output_name (drmModeConnector *connector) +{ + static const char * const connector_type_names[] = { + "unknown", "VGA", "DVII", "DVID", "DVID", "Composite", + "SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort", + "HDMIA", "HDMIB", "TV", "eDP" + }; + const char *connector_type_name; + + if (connector->connector_type < G_N_ELEMENTS (connector_type_names)) + connector_type_name = connector_type_names[connector->connector_type]; + else + connector_type_name = "unknown"; + + return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id); +} + +static void +meta_output_destroy_notify (MetaOutput *output) +{ + MetaOutputKms *output_kms; + unsigned i; + + output_kms = output->driver_private; + + for (i = 0; i < output_kms->n_encoders; i++) + drmModeFreeEncoder (output_kms->encoders[i]); + g_free (output_kms->encoders); + + g_slice_free (MetaOutputKms, output_kms); +} + +static void +meta_monitor_mode_destroy_notify (MetaMonitorMode *output) +{ + g_slice_free (drmModeModeInfo, output->driver_private); +} + +static gboolean +drm_mode_equal (gconstpointer one, + gconstpointer two) +{ + const drmModeModeInfo *m_one = one; + const drmModeModeInfo *m_two = two; + + return m_one->clock == m_two->clock && + m_one->hdisplay == m_two->hdisplay && + m_one->hsync_start == m_two->hsync_start && + m_one->hsync_end == m_two->hsync_end && + m_one->htotal == m_two->htotal && + m_one->hskew == m_two->hskew && + m_one->vdisplay == m_two->vdisplay && + m_one->vsync_start == m_two->vsync_start && + m_one->vsync_end == m_two->vsync_end && + m_one->vtotal == m_two->vtotal && + m_one->vscan == m_two->vscan && + m_one->vrefresh == m_two->vrefresh && + m_one->flags == m_two->flags && + m_one->type == m_two->type && + strncmp (m_one->name, m_two->name, DRM_DISPLAY_MODE_LEN) == 0; +} + +static guint +drm_mode_hash (gconstpointer ptr) +{ + const drmModeModeInfo *mode = ptr; + guint hash = 0; + + /* We don't include the name in the hash because it's generally + derived from the other fields (hdisplay, vdisplay and flags) + */ + + hash ^= mode->clock; + hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end; + hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end; + hash ^= mode->vrefresh; + hash ^= mode->flags ^ mode->type; + + return hash; +} + +static void +find_properties (MetaMonitorManagerKms *manager_kms, + MetaOutputKms *output_kms) +{ + drmModePropertyPtr prop; + int i; + + for (i = 0; i < output_kms->connector->count_props; i++) + { + prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]); + if (!prop) + continue; + + if ((prop->flags & DRM_MODE_PROP_ENUM) && + strcmp(prop->name, "DPMS") == 0) + output_kms->dpms_prop_id = prop->prop_id; + else if ((prop->flags & DRM_MODE_PROP_BLOB) && + strcmp (prop->name, "EDID") == 0) + output_kms->edid_blob_id = output_kms->connector->prop_values[i]; + + drmModeFreeProperty(prop); + } +} + +static GBytes * +read_output_edid (MetaMonitorManagerKms *manager_kms, + MetaOutput *output) +{ + MetaOutputKms *output_kms = output->driver_private; + drmModePropertyBlobPtr edid_blob = NULL; + + if (output_kms->edid_blob_id == 0) + return NULL; + + edid_blob = drmModeGetPropertyBlob (manager_kms->fd, output_kms->edid_blob_id); + if (!edid_blob) + { + meta_warning ("Failed to read EDID of output %s: %s\n", output->name, strerror(errno)); + return NULL; + } + + if (edid_blob->length > 0) + return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length, + (GDestroyNotify)drmModeFreePropertyBlob, edid_blob); + else + { + drmModeFreePropertyBlob (edid_blob); + return NULL; + } +} + +static MetaMonitorMode * +find_meta_mode (MetaMonitorManager *manager, + const drmModeModeInfo *drm_mode) +{ + unsigned k; + + for (k = 0; k < manager->n_modes; k++) + { + if (drm_mode_equal (drm_mode, manager->modes[k].driver_private)) + return &manager->modes[k]; + } + + g_assert_not_reached (); + return NULL; +} + +static MetaOutput * +find_output_by_id (MetaOutput *outputs, + unsigned n_outputs, + glong id) +{ + unsigned i; + + for (i = 0; i < n_outputs; i++) + if (outputs[i].output_id == id) + return &outputs[i]; + + return NULL; +} + +static void +meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + drmModeRes *resources; + GHashTable *modes; + GHashTableIter iter; + drmModeModeInfo *mode; + unsigned int i, j, k; + unsigned int n_actual_outputs; + int width, height; + MetaOutput *old_outputs; + unsigned int n_old_outputs; + + resources = drmModeGetResources(manager_kms->fd); + modes = g_hash_table_new (drm_mode_hash, drm_mode_equal); + + manager->max_screen_width = resources->max_width; + manager->max_screen_height = resources->max_height; + + manager->power_save_mode = META_POWER_SAVE_ON; + + old_outputs = manager->outputs; + n_old_outputs = manager->n_outputs; + + /* Note: we must not free the public structures (output, crtc, monitor + mode and monitor info) here, they must be kept alive until the API + users are done with them after we emit monitors-changed, and thus + are freed by the platform-independent layer. */ + free_resources (manager_kms); + + manager_kms->n_connectors = resources->count_connectors; + manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors); + for (i = 0; i < manager_kms->n_connectors; i++) + { + drmModeConnector *connector; + + connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]); + manager_kms->connectors[i] = connector; + + if (connector->connection == DRM_MODE_CONNECTED) + { + /* Collect all modes for this connector */ + for (j = 0; j < (unsigned)connector->count_modes; j++) + g_hash_table_add (modes, &connector->modes[j]); + } + } + + manager_kms->n_encoders = resources->count_encoders; + manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders); + for (i = 0; i < manager_kms->n_encoders; i++) + { + manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd, + resources->encoders[i]); + } + + manager->n_modes = g_hash_table_size (modes); + manager->modes = g_new0 (MetaMonitorMode, manager->n_modes); + g_hash_table_iter_init (&iter, modes); + i = 0; + while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode)) + { + MetaMonitorMode *meta_mode; + + meta_mode = &manager->modes[i]; + + meta_mode->mode_id = i; + meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN); + meta_mode->width = mode->hdisplay; + meta_mode->height = mode->vdisplay; + meta_mode->refresh_rate = (1000 * mode->clock / + ((float)mode->htotal * mode->vtotal)); + + meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode); + meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify; + + i++; + } + g_hash_table_destroy (modes); + + manager->n_crtcs = resources->count_crtcs; + manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs); + width = 0; height = 0; + for (i = 0; i < (unsigned)resources->count_crtcs; i++) + { + drmModeCrtc *crtc; + MetaCRTC *meta_crtc; + + crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]); + + meta_crtc = &manager->crtcs[i]; + + meta_crtc->crtc_id = crtc->crtc_id; + meta_crtc->rect.x = crtc->x; + meta_crtc->rect.y = crtc->y; + meta_crtc->rect.width = crtc->width; + meta_crtc->rect.height = crtc->height; + meta_crtc->is_dirty = FALSE; + meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + /* FIXME: implement! */ + meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL; + + if (crtc->mode_valid) + { + for (j = 0; j < manager->n_modes; j++) + { + if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private)) + { + meta_crtc->current_mode = &manager->modes[j]; + break; + } + } + + width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width); + height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height); + } + + drmModeFreeCrtc (crtc); + } + + manager->screen_width = width; + manager->screen_height = height; + + manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors); + n_actual_outputs = 0; + + for (i = 0; i < manager_kms->n_connectors; i++) + { + MetaOutput *meta_output, *old_output; + MetaOutputKms *output_kms; + drmModeConnector *connector; + GArray *crtcs; + unsigned int crtc_mask; + GBytes *edid; + + connector = manager_kms->connectors[i]; + meta_output = &manager->outputs[n_actual_outputs]; + + if (connector->connection == DRM_MODE_CONNECTED) + { + meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms); + meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify; + + meta_output->output_id = connector->connector_id; + meta_output->name = make_output_name (connector); + meta_output->width_mm = connector->mmWidth; + meta_output->height_mm = connector->mmHeight; + + switch (connector->subpixel) + { + case DRM_MODE_SUBPIXEL_NONE: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE; + break; + case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB; + break; + case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR; + break; + case DRM_MODE_SUBPIXEL_VERTICAL_RGB: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB; + break; + case DRM_MODE_SUBPIXEL_VERTICAL_BGR: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR; + break; + case DRM_MODE_SUBPIXEL_UNKNOWN: + default: + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + break; + } + + meta_output->n_modes = connector->count_modes; + meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes); + for (j = 0; j < meta_output->n_modes; j++) + meta_output->modes[j] = find_meta_mode (manager, &connector->modes[j]); + meta_output->preferred_mode = meta_output->modes[0]; + + output_kms->connector = connector; + output_kms->n_encoders = connector->count_encoders; + output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders); + + crtc_mask = ~(unsigned int)0; + for (j = 0; j < output_kms->n_encoders; j++) + { + output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]); + + /* We only list CRTCs as supported if they are supported by all encoders + for this connectors. + + This is what xf86-video-modesetting does (see drmmode_output_init()) + */ + crtc_mask &= output_kms->encoders[j]->possible_crtcs; + + if (output_kms->encoders[j]->encoder_id == connector->encoder_id) + output_kms->current_encoder = output_kms->encoders[j]; + } + + crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*)); + + for (j = 0; j < manager->n_crtcs; j++) + { + if (crtc_mask & (1 << j)) + { + MetaCRTC *crtc = &manager->crtcs[j]; + g_array_append_val (crtcs, crtc); + } + } + + meta_output->n_possible_crtcs = crtcs->len; + meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE); + + if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0) + { + for (j = 0; j < manager->n_crtcs; j++) + { + if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id) + { + meta_output->crtc = &manager->crtcs[j]; + break; + } + } + } + else + meta_output->crtc = NULL; + + old_output = find_output_by_id (old_outputs, n_old_outputs, + meta_output->output_id); + if (old_output) + { + meta_output->is_primary = old_output->is_primary; + meta_output->is_presentation = old_output->is_presentation; + } + else + { + meta_output->is_primary = FALSE; + meta_output->is_presentation = FALSE; + } + + find_properties (manager_kms, output_kms); + + edid = read_output_edid (manager_kms, meta_output); + if (edid) + { + MonitorInfo *parsed_edid; + gsize len; + + parsed_edid = decode_edid (g_bytes_get_data (edid, &len)); + if (parsed_edid) + { + meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4); + meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14); + meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14); + + g_free (parsed_edid); + } + + g_bytes_unref (edid); + } + if (!meta_output->vendor) + { + meta_output->vendor = g_strdup ("unknown"); + meta_output->product = g_strdup ("unknown"); + meta_output->serial = g_strdup ("unknown"); + } + + /* FIXME: backlight is a very driver specific thing unfortunately, + every DDX does its own thing, and the dumb KMS API does not include it. + + For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight + (one for each major HW maker, and then some). + We can't do the same because we're not root. + It might be best to leave backlight out of the story and rely on the setuid + helper in gnome-settings-daemon. + */ + meta_output->backlight_min = 0; + meta_output->backlight_max = 0; + meta_output->backlight = -1; + + n_actual_outputs++; + } + } + + manager->n_outputs = n_actual_outputs; + manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs); + + /* Sort the outputs for easier handling in MetaMonitorConfig */ + qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs); + + /* Now fix the clones. + Code mostly inspired by xf86-video-modesetting. */ + + /* XXX: intel hardware doesn't usually have clones, but I only have laptops with + intel cards, so this code was never tested! */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + MetaOutputKms *output_kms; + + meta_output = &manager->outputs[i]; + output_kms = meta_output->driver_private; + + output_kms->enc_clone_mask = 0xff; + output_kms->encoder_mask = 0; + + for (j = 0; j < output_kms->n_encoders; j++) + { + for (k = 0; k < manager_kms->n_encoders; k++) + { + if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id) + { + output_kms->encoder_mask |= (1 << k); + break; + } + } + + output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones; + } + } + + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + MetaOutputKms *output_kms; + + meta_output = &manager->outputs[i]; + output_kms = meta_output->driver_private; + + if (output_kms->enc_clone_mask == 0) + continue; + + for (j = 0; j < manager->n_outputs; j++) + { + MetaOutput *meta_clone; + MetaOutputKms *clone_kms; + + meta_clone = &manager->outputs[i]; + clone_kms = meta_clone->driver_private; + + if (meta_clone == meta_output) + continue; + + if (clone_kms->encoder_mask == 0) + continue; + + if (clone_kms->encoder_mask == output_kms->enc_clone_mask) + { + meta_output->n_possible_clones++; + meta_output->possible_clones = g_renew (MetaOutput *, + meta_output->possible_clones, + meta_output->n_possible_clones); + meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone; + } + } + } + + drmModeFreeResources (resources); +} + +static GBytes * +meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager, + MetaOutput *output) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + + return read_output_edid (manager_kms, output); +} + +static void +meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, + MetaPowerSave mode) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + uint64_t state; + unsigned i; + + switch (mode) { + case META_POWER_SAVE_ON: + state = DRM_MODE_DPMS_ON; + break; + case META_POWER_SAVE_STANDBY: + state = DRM_MODE_DPMS_STANDBY; + break; + case META_POWER_SAVE_SUSPEND: + state = DRM_MODE_DPMS_SUSPEND; + break; + case META_POWER_SAVE_OFF: + state = DRM_MODE_DPMS_OFF; + break; + default: + return; + } + + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + MetaOutputKms *output_kms; + + meta_output = &manager->outputs[i]; + output_kms = meta_output->driver_private; + + if (output_kms->dpms_prop_id != 0) + { + int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id, + output_kms->dpms_prop_id, state); + + if (ok < 0) + meta_warning ("Failed to set power save mode for output %s: %s\n", + meta_output->name, strerror (errno)); + } + } +} + +static void +crtc_free (CoglKmsCrtc *crtc) +{ + g_free (crtc->connectors); + g_slice_free (CoglKmsCrtc, crtc); +} + +static void +meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager, + MetaCRTCInfo **crtcs, + unsigned int n_crtcs, + MetaOutputInfo **outputs, + unsigned int n_outputs) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + CoglDisplay *cogl_display; + unsigned i; + GPtrArray *cogl_crtcs; + int screen_width, screen_height; + gboolean ok; + GError *error; + + cogl_crtcs = g_ptr_array_new_full (manager->n_crtcs, (GDestroyNotify)crtc_free); + screen_width = 0; screen_height = 0; + for (i = 0; i < n_crtcs; i++) + { + MetaCRTCInfo *crtc_info = crtcs[i]; + MetaCRTC *crtc = crtc_info->crtc; + CoglKmsCrtc *cogl_crtc; + + crtc->is_dirty = TRUE; + + cogl_crtc = g_slice_new0 (CoglKmsCrtc); + g_ptr_array_add (cogl_crtcs, cogl_crtc); + + if (crtc_info->mode == NULL) + { + cogl_crtc->id = crtc->crtc_id; + cogl_crtc->x = 0; + cogl_crtc->y = 0; + cogl_crtc->count = 0; + memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo)); + cogl_crtc->connectors = NULL; + cogl_crtc->count = 0; + + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + else + { + MetaMonitorMode *mode; + uint32_t *connectors; + unsigned int j, n_connectors; + int width, height; + + mode = crtc_info->mode; + + cogl_crtc->id = crtc->crtc_id; + cogl_crtc->x = crtc_info->x; + cogl_crtc->y = crtc_info->y; + cogl_crtc->count = n_connectors = crtc_info->outputs->len; + cogl_crtc->connectors = connectors = g_new (uint32_t, n_connectors); + + for (j = 0; j < n_connectors; j++) + { + MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j); + + connectors[j] = output->output_id; + + output->is_dirty = TRUE; + output->crtc = crtc; + } + + memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private, + sizeof (drmModeModeInfo)); + + if (meta_monitor_transform_is_rotated (crtc_info->transform)) + { + width = mode->height; + height = mode->width; + } + else + { + width = mode->width; + height = mode->height; + } + + screen_width = MAX (screen_width, crtc_info->x + width); + screen_height = MAX (screen_height, crtc_info->y + height); + + crtc->rect.x = crtc_info->x; + crtc->rect.y = crtc_info->y; + crtc->rect.width = width; + crtc->rect.height = height; + crtc->current_mode = mode; + crtc->transform = crtc_info->transform; + } + } + + /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE, + because they weren't seen in the first loop) */ + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + CoglKmsCrtc *cogl_crtc; + + crtc->logical_monitor = NULL; + + if (crtc->is_dirty) + { + crtc->is_dirty = FALSE; + continue; + } + + cogl_crtc = g_slice_new0 (CoglKmsCrtc); + g_ptr_array_add (cogl_crtcs, cogl_crtc); + + cogl_crtc->id = crtc->crtc_id; + cogl_crtc->x = 0; + cogl_crtc->y = 0; + cogl_crtc->count = 0; + memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo)); + cogl_crtc->connectors = NULL; + cogl_crtc->count = 0; + + crtc->rect.x = 0; + crtc->rect.y = 0; + crtc->rect.width = 0; + crtc->rect.height = 0; + crtc->current_mode = NULL; + } + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + cogl_display = cogl_context_get_display (cogl_context); + + error = NULL; + ok = cogl_kms_display_set_layout (cogl_display, screen_width, screen_height, + (CoglKmsCrtc**)cogl_crtcs->pdata, cogl_crtcs->len, &error); + g_ptr_array_unref (cogl_crtcs); + + if (!ok) + { + meta_warning ("Applying display configuration failed: %s\n", error->message); + g_error_free (error); + return; + } + + for (i = 0; i < n_outputs; i++) + { + MetaOutputInfo *output_info = outputs[i]; + MetaOutput *output = output_info->output; + + output->is_primary = output_info->is_primary; + output->is_presentation = output_info->is_presentation; + } + + /* Disable outputs not mentioned in the list */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output = &manager->outputs[i]; + + if (output->is_dirty) + { + output->is_dirty = FALSE; + continue; + } + + output->crtc = NULL; + output->is_primary = FALSE; + } + + manager->screen_width = screen_width; + manager->screen_height = screen_height; + + meta_monitor_manager_rebuild_derived (manager); +} + +static void +meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager, + MetaCRTC *crtc, + gsize *size, + unsigned short **red, + unsigned short **green, + unsigned short **blue) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + drmModeCrtc *kms_crtc; + + kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id); + + *size = kms_crtc->gamma_size; + *red = g_new (unsigned short, *size); + *green = g_new (unsigned short, *size); + *blue = g_new (unsigned short, *size); + + drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue); + + drmModeFreeCrtc (kms_crtc); +} + +static void +meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager, + MetaCRTC *crtc, + gsize size, + unsigned short *red, + unsigned short *green, + unsigned short *blue) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); + + drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue); +} + +static void +meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + CoglDisplay *cogl_display; + CoglRenderer *cogl_renderer; + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + cogl_display = cogl_context_get_display (cogl_context); + cogl_renderer = cogl_display_get_renderer (cogl_display); + + manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); +} + +static void +meta_monitor_manager_kms_finalize (GObject *object) +{ + MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object); + + free_resources (manager_kms); + + G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object); +} + +static void +meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass) +{ + MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_monitor_manager_kms_finalize; + + manager_class->read_current = meta_monitor_manager_kms_read_current; + manager_class->read_edid = meta_monitor_manager_kms_read_edid; + manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration; + manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode; + manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma; + manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma; +} + diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-kms.h new file mode 100644 index 000000000..4794e313d --- /dev/null +++ b/src/backends/native/meta-monitor-manager-kms.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * 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, see . + */ + +#ifndef META_MONITOR_MANAGER_KMS_H +#define META_MONITOR_MANAGER_KMS_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ()) +#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms)) +#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass)) +#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS)) +#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS)) +#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass)) + +typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass; +typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms; + +GType meta_monitor_manager_kms_get_type (void); + +#endif /* META_MONITOR_MANAGER_KMS_H */ diff --git a/src/backends/native/meta-weston-launch.c b/src/backends/native/meta-weston-launch.c new file mode 100644 index 000000000..a77b2eaf7 --- /dev/null +++ b/src/backends/native/meta-weston-launch.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * 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 + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wayland/meta-wayland-private.h" +#include "meta-cursor-tracker-private.h" +#include "meta-weston-launch.h" + +struct _MetaLauncher +{ + GSocket *weston_launch; + + gboolean vt_switched; + + GMainContext *nested_context; + GMainLoop *nested_loop; + + GSource *inner_source; + GSource *outer_source; +}; + +static void handle_request_vt_switch (MetaLauncher *self); + +static gboolean +request_vt_switch_idle (gpointer user_data) +{ + handle_request_vt_switch (user_data); + + return FALSE; +} + +static gboolean +send_message_to_wl (MetaLauncher *self, + void *message, + gsize size, + GSocketControlMessage *out_cmsg, + GSocketControlMessage **in_cmsg, + GError **error) +{ + struct weston_launcher_reply reply; + GInputVector in_iov = { &reply, sizeof (reply) }; + GOutputVector out_iov = { message, size }; + GSocketControlMessage *out_all_cmsg[2]; + GSocketControlMessage **in_all_cmsg; + int flags = 0; + int i; + + out_all_cmsg[0] = out_cmsg; + out_all_cmsg[1] = NULL; + if (g_socket_send_message (self->weston_launch, NULL, + &out_iov, 1, + out_all_cmsg, -1, + flags, NULL, error) != (gssize)size) + return FALSE; + + if (g_socket_receive_message (self->weston_launch, NULL, + &in_iov, 1, + &in_all_cmsg, NULL, + &flags, NULL, error) != sizeof (reply)) + return FALSE; + + while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode) + { + /* There were events queued */ + g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT); + + /* This can never happen, because the only time mutter-launch can queue + this event is after confirming a VT switch, and we don't make requests + during that time. + + Note that getting this event would be really bad, because we would be + in the wrong loop/context. + */ + g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER); + + switch (reply.header.opcode) + { + case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH: + g_idle_add (request_vt_switch_idle, self); + break; + + default: + g_assert_not_reached (); + } + + if (g_socket_receive_message (self->weston_launch, NULL, + &in_iov, 1, + NULL, NULL, + &flags, NULL, error) != sizeof (reply)) + return FALSE; + } + + if (reply.ret != 0) + { + if (reply.ret == -1) + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Got failure from weston-launch"); + else + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret), + "Got failure from weston-launch: %s", strerror (-reply.ret)); + + for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++) + g_object_unref (in_all_cmsg[i]); + g_free (in_all_cmsg); + + return FALSE; + } + + if (in_all_cmsg && in_all_cmsg[0]) + { + for (i = 1; in_all_cmsg[i]; i++) + g_object_unref (in_all_cmsg[i]); + *in_cmsg = in_all_cmsg[0]; + } + + g_free (in_all_cmsg); + return TRUE; +} + +static int +meta_launcher_open_device (MetaLauncher *self, + const char *name, + int flags, + GError **error) +{ + struct weston_launcher_open *message; + GSocketControlMessage *cmsg; + gboolean ok; + gsize size; + int *fds, n_fd; + int ret; + + size = sizeof (struct weston_launcher_open) + strlen (name) + 1; + message = g_malloc (size); + message->header.opcode = WESTON_LAUNCHER_OPEN; + message->flags = flags; + strcpy (message->path, name); + message->path[strlen(name)] = 0; + + ok = send_message_to_wl (self, message, size, NULL, &cmsg, error); + + if (ok) + { + g_assert (G_IS_UNIX_FD_MESSAGE (cmsg)); + + fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd); + g_assert (n_fd == 1); + + ret = fds[0]; + g_free (fds); + g_object_unref (cmsg); + } + else + ret = -1; + + g_free (message); + return ret; +} + +static void +meta_launcher_enter (MetaLauncher *launcher) +{ + ClutterBackend *backend; + CoglContext *cogl_context; + CoglDisplay *cogl_display; + + backend = clutter_get_default_backend (); + cogl_context = clutter_backend_get_cogl_context (backend); + cogl_display = cogl_context_get_display (cogl_context); + cogl_kms_display_queue_modes_reset (cogl_display); + + clutter_evdev_reclaim_devices (); + + { + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + + /* When we mode-switch back, we need to immediately queue a redraw + * in case nothing else queued one for us, and force the cursor to + * update. */ + + clutter_actor_queue_redraw (compositor->stage); + meta_cursor_tracker_force_update (compositor->seat->cursor_tracker); + } +} + +static void +meta_launcher_leave (MetaLauncher *launcher) +{ + clutter_evdev_release_devices (); +} + +static int +on_evdev_device_open (const char *path, + int flags, + gpointer user_data, + GError **error) +{ + MetaLauncher *launcher = user_data; + + return meta_launcher_open_device (launcher, path, flags, error); +} + +static void +on_evdev_device_close (int fd, + gpointer user_data) +{ + close (fd); +} + +static void +handle_vt_enter (MetaLauncher *launcher) +{ + g_assert (launcher->vt_switched); + + g_main_loop_quit (launcher->nested_loop); +} + +static void +handle_request_vt_switch (MetaLauncher *launcher) +{ + struct weston_launcher_message message; + GError *error; + gboolean ok; + + meta_launcher_leave (launcher); + + message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH; + + error = NULL; + ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error); + if (!ok) { + g_warning ("Failed to acknowledge VT switch: %s", error->message); + g_error_free (error); + + return; + } + + g_assert (!launcher->vt_switched); + launcher->vt_switched = TRUE; + + /* We can't do anything at this point, because we don't + have input devices and we don't have the DRM master, + so let's run a nested busy loop until the VT is reentered */ + g_main_loop_run (launcher->nested_loop); + + g_assert (launcher->vt_switched); + launcher->vt_switched = FALSE; + + meta_launcher_enter (launcher); +} + +static gboolean +on_socket_readable (GSocket *socket, + GIOCondition condition, + gpointer user_data) +{ + MetaLauncher *launcher = user_data; + struct weston_launcher_event event; + gssize read; + GError *error; + + if ((condition & G_IO_IN) == 0) + return TRUE; + + error = NULL; + read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error); + if (read < (gssize)sizeof(event)) + { + g_warning ("Error reading from weston-launcher socket: %s", error->message); + g_error_free (error); + return TRUE; + } + + switch (event.header.opcode) + { + case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH: + handle_request_vt_switch (launcher); + break; + + case WESTON_LAUNCHER_SERVER_VT_ENTER: + handle_vt_enter (launcher); + break; + } + + return TRUE; +} + +static int +env_get_fd (const char *env) +{ + const char *value; + + value = g_getenv (env); + + if (value == NULL) + return -1; + else + return g_ascii_strtoll (value, NULL, 10); +} + +MetaLauncher * +meta_launcher_new (void) +{ + MetaLauncher *self = g_slice_new0 (MetaLauncher); + int launch_fd; + + launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK"); + if (launch_fd < 0) + g_error ("Invalid mutter-launch socket"); + + self->weston_launch = g_socket_new_from_fd (launch_fd, NULL); + + self->nested_context = g_main_context_new (); + self->nested_loop = g_main_loop_new (self->nested_context, FALSE); + + self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL); + g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL); + g_source_attach (self->outer_source, NULL); + g_source_unref (self->outer_source); + + self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL); + g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL); + g_source_attach (self->inner_source, self->nested_context); + g_source_unref (self->inner_source); + + clutter_evdev_set_device_callbacks (on_evdev_device_open, + on_evdev_device_close, + self); + +#if defined(CLUTTER_WINDOWING_EGL) + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + GError *error = NULL; + int fd = meta_launcher_open_device (self, "/dev/dri/card0", O_RDWR, &error); + if (error) + g_error ("Failed to open /dev/dri/card0: %s", error->message); + + clutter_egl_set_kms_fd (fd); + } +#endif + + return self; +} + +void +meta_launcher_free (MetaLauncher *launcher) +{ + g_source_destroy (launcher->outer_source); + g_source_destroy (launcher->inner_source); + + g_main_loop_unref (launcher->nested_loop); + g_main_context_unref (launcher->nested_context); + + g_object_unref (launcher->weston_launch); + + g_slice_free (MetaLauncher, launcher); +} + +gboolean +meta_launcher_activate_vt (MetaLauncher *launcher, + signed char vt, + GError **error) +{ + struct weston_launcher_activate_vt message; + + message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT; + message.vt = vt; + + return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error); +} + diff --git a/src/backends/native/meta-weston-launch.h b/src/backends/native/meta-weston-launch.h new file mode 100644 index 000000000..b70faf88e --- /dev/null +++ b/src/backends/native/meta-weston-launch.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * 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. + */ + +#ifndef META_WESTON_LAUNCH_H +#define META_WESTON_LAUNCH_H + +#include +#include "weston-launch.h" + +typedef struct _MetaLauncher MetaLauncher; + +MetaLauncher *meta_launcher_new (void); +void meta_launcher_free (MetaLauncher *self); + +gboolean meta_launcher_activate_vt (MetaLauncher *self, + signed char vt, + GError **error); +#endif diff --git a/src/backends/native/weston-launch.c b/src/backends/native/weston-launch.c new file mode 100644 index 000000000..ba1ed7476 --- /dev/null +++ b/src/backends/native/weston-launch.c @@ -0,0 +1,711 @@ +/* + * Copyright © 2012 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include "weston-launch.h" + +#define MAX_ARGV_SIZE 256 +#define DRM_MAJOR 226 + +enum vt_state { + VT_HAS_VT, + VT_PENDING_CONFIRM, + VT_NOT_HAVE_VT, +}; + +struct weston_launch { + int tty; + int ttynr; + int sock[2]; + struct passwd *pw; + + int signalfd; + + pid_t child; + int verbose; + + struct termios terminal_attributes; + int kb_mode; + enum vt_state vt_state; + unsigned vt; + + int drm_fd; +}; + +union cmsg_data { unsigned char b[4]; int fd; }; + +static void quit (struct weston_launch *wl, int status); + +static int +weston_launch_allowed(struct weston_launch *wl) +{ + char *session, *seat; + int err; + + if (getuid() == 0) + return 1; + + err = sd_pid_get_session(getpid(), &session); + if (err == 0 && session) { + if (sd_session_is_active(session) && + sd_session_get_seat(session, &seat) == 0) { + free(seat); + free(session); + return 1; + } + free(session); + } + + return 0; +} + +static int +setup_launcher_socket(struct weston_launch *wl) +{ + if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0) + error(1, errno, "socketpair failed"); + + fcntl(wl->sock[0], F_SETFD, O_CLOEXEC); + + return 0; +} + +static int +setup_signals(struct weston_launch *wl) +{ + int ret; + sigset_t mask; + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + ret = sigaction(SIGCHLD, &sa, NULL); + assert(ret == 0); + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigaction(SIGHUP, &sa, NULL); + + ret = sigemptyset(&mask); + assert(ret == 0); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGUSR1); + ret = sigprocmask(SIG_BLOCK, &mask, NULL); + assert(ret == 0); + + wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); + if (wl->signalfd < 0) + return -errno; + + return 0; +} + +static void +setenv_fd(const char *env, int fd) +{ + char buf[32]; + + snprintf(buf, sizeof buf, "%d", fd); + setenv(env, buf, 1); +} + +static int +handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len) +{ + struct weston_launcher_reply reply; + + reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH; + reply.ret = -1; + + if (wl->vt_state != VT_PENDING_CONFIRM) { + error(0, 0, "unexpected CONFIRM_VT_SWITCH"); + goto out; + } + + if (wl->drm_fd != -1) { + int ret; + + ret = drmDropMaster(wl->drm_fd); + if (ret < 0) { + fprintf(stderr, "failed to drop DRM master: %m\n"); + } else if (wl->verbose) { + fprintf(stderr, "dropped DRM master for VT switch\n"); + } + } + + wl->vt_state = VT_NOT_HAVE_VT; + ioctl(wl->tty, VT_RELDISP, 1); + + if (wl->verbose) + fprintf(stderr, "mutter-launcher: confirmed VT switch\n"); + + reply.ret = 0; + +out: + do { + len = send(wl->sock[0], &reply, sizeof reply, 0); + } while (len < 0 && errno == EINTR); + if (len < 0) + return -1; + + return 0; +} + +static int +handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len) +{ + struct weston_launcher_reply reply; + struct weston_launcher_activate_vt *message; + unsigned vt; + + reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT; + reply.ret = -1; + + if (len != sizeof(*message)) { + error(0, 0, "missing value in activate_vt request"); + goto out; + } + + message = msg->msg_iov->iov_base; + + /* Negative values mean that we're activating our own VT */ + if (message->vt > 0) + vt = message->vt; + else + vt = wl->vt; + + reply.ret = ioctl(wl->tty, VT_ACTIVATE, vt); + if (reply.ret < 0) + reply.ret = -errno; + + if (wl->verbose) + fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret); + +out: + do { + len = send(wl->sock[0], &reply, sizeof reply, 0); + } while (len < 0 && errno == EINTR); + if (len < 0) + return -1; + + return 0; +} + + +static int +handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len) +{ + struct weston_launcher_reply reply; + int fd = -1; + char control[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr *cmsg; + struct stat s; + struct msghdr nmsg; + struct iovec iov; + struct weston_launcher_open *message; + union cmsg_data *data; + int dev_major; + + reply.header.opcode = WESTON_LAUNCHER_OPEN; + reply.ret = -1; + + message = msg->msg_iov->iov_base; + if ((size_t)len < sizeof(*message)) + goto err0; + + /* Ensure path is null-terminated */ + ((char *) message)[len-1] = '\0'; + + if (stat(message->path, &s) < 0) { + reply.ret = -errno; + goto err0; + } + + dev_major = major(s.st_rdev); + + if (dev_major != INPUT_MAJOR && + dev_major != DRM_MAJOR) { + fprintf(stderr, "Device %s is not an input or DRM device\n", + message->path); + reply.ret = -EPERM; + goto err0; + } + + if (dev_major == DRM_MAJOR && wl->drm_fd != -1) { + fprintf(stderr, "Already have a DRM device open\n"); + reply.ret = -EPERM; + goto err0; + } + + fd = open(message->path, message->flags); + if (fd < 0) { + fprintf(stderr, "Error opening device %s: %m\n", + message->path); + reply.ret = -errno; + goto err0; + } + + if (dev_major == DRM_MAJOR) { + wl->drm_fd = fd; + } + +err0: + memset(&nmsg, 0, sizeof nmsg); + nmsg.msg_iov = &iov; + nmsg.msg_iovlen = 1; + if (fd != -1) { + nmsg.msg_control = control; + nmsg.msg_controllen = sizeof control; + cmsg = CMSG_FIRSTHDR(&nmsg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + data = (union cmsg_data *) CMSG_DATA(cmsg); + data->fd = fd; + nmsg.msg_controllen = cmsg->cmsg_len; + reply.ret = 0; + } + iov.iov_base = &reply; + iov.iov_len = sizeof reply; + + if (wl->verbose) + fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n", + message->path, reply.ret, fd); + do { + len = sendmsg(wl->sock[0], &nmsg, 0); + } while (len < 0 && errno == EINTR); + + close(fd); + + if (len < 0) + return -1; + + return 0; +} + +static int +handle_socket_msg(struct weston_launch *wl) +{ + char control[CMSG_SPACE(sizeof(int))]; + char buf[BUFSIZ]; + struct msghdr msg; + struct iovec iov; + int ret = -1; + ssize_t len; + struct weston_launcher_message *message; + + memset(&msg, 0, sizeof(msg)); + iov.iov_base = buf; + iov.iov_len = sizeof buf; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof control; + + do { + len = recvmsg(wl->sock[0], &msg, 0); + } while (len < 0 && errno == EINTR); + + if (len < 1) + return -1; + + message = (void *) buf; + switch (message->opcode) { + case WESTON_LAUNCHER_OPEN: + ret = handle_open(wl, &msg, len); + break; + case WESTON_LAUNCHER_CONFIRM_VT_SWITCH: + ret = handle_confirm_vt_switch(wl, &msg, len); + break; + case WESTON_LAUNCHER_ACTIVATE_VT: + ret = handle_activate_vt(wl, &msg, len); + break; + } + + return ret; +} + +static void +tty_reset(struct weston_launch *wl) +{ + struct vt_mode mode = { 0 }; + + if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode)) + fprintf(stderr, "failed to restore keyboard mode: %m\n"); + + if (ioctl(wl->tty, KDSETMODE, KD_TEXT)) + fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n"); + + if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0) + fprintf(stderr, "could not restore terminal to canonical mode\n"); + + mode.mode = VT_AUTO; + if (ioctl(wl->tty, VT_SETMODE, &mode) < 0) + fprintf(stderr, "could not reset vt handling\n"); +} + +static void +quit(struct weston_launch *wl, int status) +{ + if (wl->child > 0) + kill(wl->child, SIGKILL); + + close(wl->signalfd); + close(wl->sock[0]); + + if (wl->drm_fd > 0) + close(wl->drm_fd); + + tty_reset(wl); + + exit(status); +} + +static int +handle_vt_switch(struct weston_launch *wl) +{ + struct weston_launcher_event message; + ssize_t len; + + if (wl->vt_state == VT_HAS_VT) { + wl->vt_state = VT_PENDING_CONFIRM; + message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH; + } else if (wl->vt_state == VT_NOT_HAVE_VT) { + wl->vt_state = VT_HAS_VT; + ioctl(wl->tty, VT_RELDISP, VT_ACKACQ); + + if (wl->drm_fd != -1) { + int ret; + + ret = drmSetMaster(wl->drm_fd); + if (ret < 0) { + fprintf(stderr, "failed to become DRM master: %m\n"); + /* This is very, very bad, and the compositor will crash soon, + but oh well... */ + } else if (wl->verbose) { + fprintf(stderr, "became DRM master after VT switch\n"); + } + } + + message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER; + } else + return -1; + + message.detail = 0; + + do { + len = send(wl->sock[0], &message, sizeof(message), 0); + } while (len < 0 && errno == EINTR); + + return 0; +} + + +static int +handle_signal(struct weston_launch *wl) +{ + struct signalfd_siginfo sig; + int pid, status, ret; + + if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) { + error(0, errno, "reading signalfd failed"); + return -1; + } + + switch (sig.ssi_signo) { + case SIGCHLD: + pid = waitpid(-1, &status, 0); + if (pid == wl->child) { + wl->child = 0; + if (WIFEXITED(status)) + ret = WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + /* + * If weston dies because of signal N, we + * return 10+N. This is distinct from + * weston-launch dying because of a signal + * (128+N). + */ + ret = 10 + WTERMSIG(status); + else + ret = 0; + quit(wl, ret); + } + break; + case SIGTERM: + case SIGINT: + if (wl->child) + kill(wl->child, sig.ssi_signo); + break; + case SIGUSR1: + return handle_vt_switch(wl); + default: + return -1; + } + + return 0; +} + +static int +setup_tty(struct weston_launch *wl) +{ + struct stat buf; + struct termios raw_attributes; + struct vt_mode mode = { 0 }; + char *session; + char path[PATH_MAX]; + int ok; + + ok = sd_pid_get_session(getpid(), &session); + if (ok < 0) + error(1, -ok, "could not determine current session"); + + ok = sd_session_get_vt(session, &wl->vt); + if (ok < 0) + error(1, -ok, "could not determine current TTY"); + + snprintf(path, PATH_MAX, "/dev/tty%u", wl->vt); + wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC); + + if (wl->tty < 0) + error(1, errno, "failed to open tty"); + + if (fstat(wl->tty, &buf) < 0) + error(1, errno, "stat %s failed", path); + + if (major(buf.st_rdev) != TTY_MAJOR) + error(1, 0, "invalid tty device: %s", path); + + wl->ttynr = minor(buf.st_rdev); + + if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0) + error(1, errno, "could not get terminal attributes"); + + /* Ignore control characters and disable echo */ + raw_attributes = wl->terminal_attributes; + cfmakeraw(&raw_attributes); + + /* Fix up line endings to be normal (cfmakeraw hoses them) */ + raw_attributes.c_oflag |= OPOST | OCRNL; + /* Don't generate ttou signals */ + raw_attributes.c_oflag &= ~TOSTOP; + + if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0) + error(1, errno, "could not put terminal into raw mode"); + + ioctl(wl->tty, KDGKBMODE, &wl->kb_mode); + ok = ioctl(wl->tty, KDSKBMODE, K_OFF); + if (ok < 0) { + ok = ioctl(wl->tty, KDSKBMODE, K_RAW); + if (ok < 0) + error(1, errno, "failed to set keyboard mode on tty"); + } + + ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS); + if (ok < 0) + error(1, errno, "failed to set KD_GRAPHICS mode on tty"); + + wl->vt_state = VT_HAS_VT; + mode.mode = VT_PROCESS; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR1; + ok = ioctl(wl->tty, VT_SETMODE, &mode); + if (ok < 0) + error(1, errno, "failed to take control of vt handling"); + + return 0; +} + +static void +drop_privileges(struct weston_launch *wl) +{ + if (setgid(wl->pw->pw_gid) < 0 || +#ifdef HAVE_INITGROUPS + initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 || +#endif + setuid(wl->pw->pw_uid) < 0) + error(1, errno, "dropping privileges failed"); +} + +static void +launch_compositor(struct weston_launch *wl, int argc, char *argv[]) +{ + char command[PATH_MAX]; + char *child_argv[MAX_ARGV_SIZE]; + sigset_t mask; + int i; + + if (wl->verbose) + printf("weston-launch: spawned weston with pid: %d\n", getpid()); + + drop_privileges(wl); + + setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]); + setenv("LD_LIBRARY_PATH", LIBDIR, 1); + unsetenv("DISPLAY"); + + /* Do not give our signal mask to the new process. */ + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + + snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]); + + child_argv[0] = wl->pw->pw_shell; + child_argv[1] = "-l"; + child_argv[2] = "-c"; + child_argv[3] = command; + for (i = 0; i < argc; ++i) + child_argv[4 + i] = argv[i]; + child_argv[4 + i] = NULL; + + execv(child_argv[0], child_argv); + error(1, errno, "exec failed"); +} + +static void +help(const char *name) +{ + fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name); + fprintf(stderr, " -u, --user Start session as specified username\n"); + fprintf(stderr, " -v, --verbose Be verbose\n"); + fprintf(stderr, " -h, --help Display this help message\n"); +} + +int +main(int argc, char *argv[]) +{ + struct weston_launch wl; + int i, c; + struct option opts[] = { + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, NULL, 0 } + }; + + memset(&wl, 0, sizeof wl); + wl.drm_fd = -1; + + while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) { + switch (c) { + case 'v': + wl.verbose = 1; + break; + case 'h': + help("mutter-launch"); + exit(EXIT_FAILURE); + } + } + + if ((argc - optind) > (MAX_ARGV_SIZE - 6)) + error(1, E2BIG, "Too many arguments to pass to weston"); + + if (optind >= argc) + error(1, 0, "Expected program argument"); + + wl.pw = getpwuid(getuid()); + if (wl.pw == NULL) + error(1, errno, "failed to get username"); + + if (!weston_launch_allowed(&wl)) + error(1, 0, "Permission denied. You must run from an active and local (systemd) session."); + + if (setup_tty(&wl) < 0) + exit(EXIT_FAILURE); + + if (setup_launcher_socket(&wl) < 0) + exit(EXIT_FAILURE); + + if (setup_signals(&wl) < 0) + exit(EXIT_FAILURE); + + wl.child = fork(); + if (wl.child == -1) { + error(1, errno, "fork failed"); + exit(EXIT_FAILURE); + } + + if (wl.child == 0) + launch_compositor(&wl, argc - optind, argv + optind); + + close(wl.sock[1]); + + while (1) { + struct pollfd fds[2]; + int n; + + fds[0].fd = wl.sock[0]; + fds[0].events = POLLIN; + fds[1].fd = wl.signalfd; + fds[1].events = POLLIN; + + n = poll(fds, 2, -1); + if (n < 0) + error(0, errno, "poll failed"); + if (fds[0].revents & POLLIN) + handle_socket_msg(&wl); + if (fds[1].revents) + handle_signal(&wl); + } + + return 0; +} diff --git a/src/backends/native/weston-launch.h b/src/backends/native/weston-launch.h new file mode 100644 index 000000000..1e716c5ac --- /dev/null +++ b/src/backends/native/weston-launch.h @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 Benjamin Franzke + * 2013 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WESTON_LAUNCH_H_ +#define _WESTON_LAUNCH_H_ + +enum weston_launcher_message_type { + WESTON_LAUNCHER_REQUEST, + WESTON_LAUNCHER_EVENT, +}; + +enum weston_launcher_opcode { + WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST), + WESTON_LAUNCHER_ACTIVATE_VT = (2 << 1 | WESTON_LAUNCHER_REQUEST), + WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (3 << 1 | WESTON_LAUNCHER_REQUEST), +}; + +enum weston_launcher_server_opcode { + WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT), + WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT), +}; + +struct weston_launcher_message { + int opcode; +}; + +struct weston_launcher_open { + struct weston_launcher_message header; + int flags; + char path[0]; +}; + +struct weston_launcher_activate_vt { + struct weston_launcher_message header; + signed char vt; +}; + +struct weston_launcher_reply { + struct weston_launcher_message header; + int ret; +}; + +struct weston_launcher_event { + struct weston_launcher_message header; + int detail; /* unused, but makes sure replies and events are serialized the same */ +}; + +#endif diff --git a/src/backends/x11/meta-idle-monitor-xsync.c b/src/backends/x11/meta-idle-monitor-xsync.c new file mode 100644 index 000000000..25338a775 --- /dev/null +++ b/src/backends/x11/meta-idle-monitor-xsync.c @@ -0,0 +1,366 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#include "config.h" + +#include "meta-idle-monitor-xsync.h" +#include "meta-idle-monitor-private.h" + +#include +#include "display-private.h" + +#include + +struct _MetaIdleMonitorXSync +{ + MetaIdleMonitor parent; + + GHashTable *alarms; + Display *display; + XSyncCounter counter; + XSyncAlarm user_active_alarm; +}; + +struct _MetaIdleMonitorXSyncClass +{ + MetaIdleMonitorClass parent_class; +}; + +typedef struct { + MetaIdleMonitorWatch base; + + XSyncAlarm xalarm; +} MetaIdleMonitorWatchXSync; + +G_DEFINE_TYPE (MetaIdleMonitorXSync, meta_idle_monitor_xsync, META_TYPE_IDLE_MONITOR) + +static gint64 +_xsyncvalue_to_int64 (XSyncValue value) +{ + return ((guint64) XSyncValueHigh32 (value)) << 32 + | (guint64) XSyncValueLow32 (value); +} + +#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32) + +static XSyncAlarm +_xsync_alarm_set (MetaIdleMonitorXSync *monitor_xsync, + XSyncTestType test_type, + guint64 interval, + gboolean want_events) +{ + XSyncAlarmAttributes attr; + XSyncValue delta; + guint flags; + + flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | + XSyncCAValue | XSyncCADelta | XSyncCAEvents; + + XSyncIntToValue (&delta, 0); + attr.trigger.counter = monitor_xsync->counter; + attr.trigger.value_type = XSyncAbsolute; + attr.delta = delta; + attr.events = want_events; + + GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value); + attr.trigger.test_type = test_type; + return XSyncCreateAlarm (monitor_xsync->display, flags, &attr); +} + +static void +ensure_alarm_rescheduled (Display *dpy, + XSyncAlarm alarm) +{ + XSyncAlarmAttributes attr; + + /* Some versions of Xorg have an issue where alarms aren't + * always rescheduled. Calling XSyncChangeAlarm, even + * without any attributes, will reschedule the alarm. */ + XSyncChangeAlarm (dpy, alarm, 0, &attr); +} + +static void +set_alarm_enabled (Display *dpy, + XSyncAlarm alarm, + gboolean enabled) +{ + XSyncAlarmAttributes attr; + attr.events = enabled; + XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr); +} + +static void +check_x11_watch (gpointer data, + gpointer user_data) +{ + MetaIdleMonitorWatchXSync *watch_xsync = data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync; + XSyncAlarm alarm = (XSyncAlarm) user_data; + + if (watch_xsync->xalarm != alarm) + return; + + _meta_idle_monitor_watch_fire (watch); +} + +static char * +counter_name_for_device (int device_id) +{ + if (device_id > 0) + return g_strdup_printf ("DEVICEIDLETIME %d", device_id); + + return g_strdup ("IDLETIME"); +} + +static XSyncCounter +find_idletime_counter (MetaIdleMonitorXSync *monitor_xsync) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync); + int i; + int ncounters; + XSyncSystemCounter *counters; + XSyncCounter counter = None; + char *counter_name; + + counter_name = counter_name_for_device (monitor->device_id); + counters = XSyncListSystemCounters (monitor_xsync->display, &ncounters); + for (i = 0; i < ncounters; i++) + { + if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) + { + counter = counters[i].counter; + break; + } + } + XSyncFreeSystemCounterList (counters); + g_free (counter_name); + + return counter; +} + +static void +init_xsync (MetaIdleMonitorXSync *monitor_xsync) +{ + monitor_xsync->counter = find_idletime_counter (monitor_xsync); + /* IDLETIME counter not found? */ + if (monitor_xsync->counter == None) + { + g_warning ("IDLETIME counter not found\n"); + return; + } + + monitor_xsync->user_active_alarm = _xsync_alarm_set (monitor_xsync, XSyncNegativeTransition, 1, FALSE); +} + +static void +meta_idle_monitor_xsync_dispose (GObject *object) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object); + + if (monitor_xsync->user_active_alarm != None) + { + XSyncDestroyAlarm (monitor_xsync->display, monitor_xsync->user_active_alarm); + monitor_xsync->user_active_alarm = None; + } + + g_clear_pointer (&monitor_xsync->alarms, g_hash_table_destroy); + + G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->dispose (object); +} + +static void +meta_idle_monitor_xsync_constructed (GObject *object) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object); + + g_assert (!meta_is_wayland_compositor ()); + + monitor_xsync->display = meta_get_display ()->xdisplay; + init_xsync (monitor_xsync); + + G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->constructed (object); +} + +static gint64 +meta_idle_monitor_xsync_get_idletime (MetaIdleMonitor *monitor) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + XSyncValue value; + + if (!XSyncQueryCounter (monitor_xsync->display, monitor_xsync->counter, &value)) + return -1; + + return _xsyncvalue_to_int64 (value); +} + +static gboolean +fire_watch_idle (gpointer data) +{ + MetaIdleMonitorWatch *watch = data; + + watch->idle_source_id = 0; + _meta_idle_monitor_watch_fire (watch); + + return FALSE; +} + +static guint32 +get_next_watch_serial (void) +{ + static guint32 serial = 0; + g_atomic_int_inc (&serial); + return serial; +} + +static void +free_watch (gpointer data) +{ + MetaIdleMonitorWatchXSync *watch_xsync = data; + MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync; + MetaIdleMonitor *monitor = watch->monitor; + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + + g_object_ref (monitor); + + if (watch->idle_source_id) + { + g_source_remove (watch->idle_source_id); + watch->idle_source_id = 0; + } + + if (watch->notify != NULL) + watch->notify (watch->user_data); + + if (watch_xsync->xalarm != monitor_xsync->user_active_alarm && + watch_xsync->xalarm != None) + { + XSyncDestroyAlarm (monitor_xsync->display, watch_xsync->xalarm); + g_hash_table_remove (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm); + } + + g_object_unref (monitor); + g_slice_free (MetaIdleMonitorWatchXSync, watch_xsync); +} + +static MetaIdleMonitorWatch * +meta_idle_monitor_xsync_make_watch (MetaIdleMonitor *monitor, + guint64 timeout_msec, + MetaIdleMonitorWatchFunc callback, + gpointer user_data, + GDestroyNotify notify) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + MetaIdleMonitorWatchXSync *watch_xsync; + MetaIdleMonitorWatch *watch; + + watch_xsync = g_slice_new0 (MetaIdleMonitorWatchXSync); + watch = (MetaIdleMonitorWatch *) watch_xsync; + + watch->monitor = monitor; + watch->id = get_next_watch_serial (); + watch->callback = callback; + watch->user_data = user_data; + watch->notify = notify; + watch->timeout_msec = timeout_msec; + + if (monitor_xsync->user_active_alarm != None) + { + if (timeout_msec != 0) + { + watch_xsync->xalarm = _xsync_alarm_set (monitor_xsync, XSyncPositiveTransition, timeout_msec, TRUE); + + g_hash_table_add (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm); + + if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) + watch->idle_source_id = g_idle_add (fire_watch_idle, watch); + } + else + { + watch_xsync->xalarm = monitor_xsync->user_active_alarm; + + set_alarm_enabled (monitor_xsync->display, monitor_xsync->user_active_alarm, TRUE); + } + } + + return watch; +} + +static void +meta_idle_monitor_xsync_class_init (MetaIdleMonitorXSyncClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass); + + object_class->dispose = meta_idle_monitor_xsync_dispose; + object_class->constructed = meta_idle_monitor_xsync_constructed; + + idle_monitor_class->get_idletime = meta_idle_monitor_xsync_get_idletime; + idle_monitor_class->make_watch = meta_idle_monitor_xsync_make_watch; +} + +static void +meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor_xsync) +{ + MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync); + + monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch); + monitor_xsync->alarms = g_hash_table_new (NULL, NULL); +} + +void +meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor, + XSyncAlarmNotifyEvent *alarm_event) +{ + MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor); + XSyncAlarm alarm; + GList *watches; + gboolean has_alarm; + + if (alarm_event->state != XSyncAlarmActive) + return; + + alarm = alarm_event->alarm; + + has_alarm = FALSE; + + if (alarm == monitor_xsync->user_active_alarm) + { + set_alarm_enabled (monitor_xsync->display, + alarm, + FALSE); + has_alarm = TRUE; + } + else if (g_hash_table_contains (monitor_xsync->alarms, (gpointer) alarm)) + { + ensure_alarm_rescheduled (monitor_xsync->display, + alarm); + has_alarm = TRUE; + } + + if (has_alarm) + { + watches = g_hash_table_get_values (monitor->watches); + + g_list_foreach (watches, check_x11_watch, (gpointer) alarm); + g_list_free (watches); + } +} diff --git a/src/backends/x11/meta-idle-monitor-xsync.h b/src/backends/x11/meta-idle-monitor-xsync.h new file mode 100644 index 000000000..f8e88f09e --- /dev/null +++ b/src/backends/x11/meta-idle-monitor-xsync.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright 2013 Red Hat, Inc. + * + * 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, see . + * + * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and + * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c + */ + +#ifndef META_IDLE_MONITOR_XSYNC_H +#define META_IDLE_MONITOR_XSYNC_H + +#include +#include + +#include +#include + +#define META_TYPE_IDLE_MONITOR_XSYNC (meta_idle_monitor_xsync_get_type ()) +#define META_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSync)) +#define META_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass)) +#define META_IS_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_XSYNC)) +#define META_IS_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_XSYNC)) +#define META_IDLE_MONITOR_XSYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass)) + +typedef struct _MetaIdleMonitorXSync MetaIdleMonitorXSync; +typedef struct _MetaIdleMonitorXSyncClass MetaIdleMonitorXSyncClass; + +GType meta_idle_monitor_xsync_get_type (void); + +void meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor, + XSyncAlarmNotifyEvent *xevent); + +void meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent); + +#endif /* META_IDLE_MONITOR_XSYNC_H */ diff --git a/src/core/monitor-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c similarity index 99% rename from src/core/monitor-xrandr.c rename to src/backends/x11/meta-monitor-manager-xrandr.c index 857c3d339..5fbddd48d 100644 --- a/src/core/monitor-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -25,6 +25,8 @@ #include "config.h" +#include "meta-monitor-manager-xrandr.h" + #include #include #include @@ -36,9 +38,8 @@ #include #include -#include "monitor-private.h" - #include "edid.h" +#include "meta-monitor-config.h" #define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) @@ -1017,7 +1018,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, MetaOutput *old_outputs; MetaCRTC *old_crtcs; MetaMonitorMode *old_modes; - int n_old_outputs; + unsigned int n_old_outputs, n_old_modes; gboolean new_config; if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) @@ -1029,6 +1030,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; old_modes = manager->modes; + n_old_modes = manager->n_modes; old_crtcs = manager->crtcs; manager->serial++; @@ -1068,7 +1070,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, } meta_monitor_manager_free_output_array (old_outputs, n_old_outputs); - g_free (old_modes); + meta_monitor_manager_free_mode_array (old_modes, n_old_modes); g_free (old_crtcs); return TRUE; diff --git a/src/backends/x11/meta-monitor-manager-xrandr.h b/src/backends/x11/meta-monitor-manager-xrandr.h new file mode 100644 index 000000000..245a42e43 --- /dev/null +++ b/src/backends/x11/meta-monitor-manager-xrandr.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * 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, see . + */ + +#ifndef META_MONITOR_MANAGER_XRANDR_H +#define META_MONITOR_MANAGER_XRANDR_H + +#include "meta-monitor-manager.h" + +#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ()) +#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr)) +#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) +#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR)) +#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR)) +#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass)) + +typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass; +typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr; + +GType meta_monitor_manager_xrandr_get_type (void); + +#endif /* META_MONITOR_MANAGER_XRANDR_H */ diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 18bcff6f9..ef0a53457 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -11,35 +11,21 @@ #include "meta-window-actor-private.h" #include -typedef struct _MetaCompScreen MetaCompScreen; - struct _MetaCompositor { MetaDisplay *display; guint repaint_func_id; - ClutterActor *shadow_src; - - MetaPlugin *modal_plugin; - gint64 server_time_query_time; gint64 server_time_offset; guint server_time_is_monotonic_time : 1; - guint show_redraw : 1; - guint debug : 1; guint no_mipmaps : 1; -}; -struct _MetaCompScreen -{ - MetaScreen *screen; - - ClutterActor *stage, *window_group, *top_window_group, *overlay_group; + ClutterActor *stage, *window_group, *top_window_group; ClutterActor *background_actor; GList *windows; - GHashTable *windows_by_xid; Window output; CoglOnscreen *onscreen; @@ -57,19 +43,17 @@ struct _MetaCompScreen /* Wait 2ms after vblank before starting to draw next frame */ #define META_SYNC_DELAY 2 -void meta_switch_workspace_completed (MetaScreen *screen); +void meta_switch_workspace_completed (MetaCompositor *compositor); -gboolean meta_begin_modal_for_plugin (MetaScreen *screen, +gboolean meta_begin_modal_for_plugin (MetaCompositor *compositor, MetaPlugin *plugin, MetaModalOptions options, guint32 timestamp); -void meta_end_modal_for_plugin (MetaScreen *screen, +void meta_end_modal_for_plugin (MetaCompositor *compositor, MetaPlugin *plugin, guint32 timestamp); gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, gint64 monotonic_time); -void meta_check_end_modal (MetaScreen *screen); - #endif /* META_COMPOSITOR_PRIVATE_H */ diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 51e27f3b6..acb0599df 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -65,7 +65,6 @@ #include #include "compositor-private.h" #include -#include "xprops.h" #include #include #include @@ -76,11 +75,17 @@ #include "window-private.h" /* to check window->hidden */ #include "display-private.h" /* for meta_display_lookup_x_window() */ #include "util-private.h" +#include "frame.h" #include #include -/* #define DEBUG_TRACE g_print */ -#define DEBUG_TRACE(X) +#include "wayland/meta-wayland-private.h" + +static gboolean +is_modal (MetaDisplay *display) +{ + return display->grab_op == META_GRAB_OP_COMPOSITOR; +} static inline gboolean composite_at_least_version (MetaDisplay *display, int maj, int min) @@ -94,41 +99,34 @@ composite_at_least_version (MetaDisplay *display, int maj, int min) return (major > maj || (major == maj && minor >= min)); } -static void sync_actor_stacking (MetaCompScreen *info); +static void sync_actor_stacking (MetaCompositor *compositor); static void -meta_finish_workspace_switch (MetaCompScreen *info) +meta_finish_workspace_switch (MetaCompositor *compositor) { GList *l; /* Finish hiding and showing actors for the new workspace */ - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_sync_visibility (l->data); - /* - * Fix up stacking order in case the plugin messed it up. - */ - sync_actor_stacking (info); - -/* printf ("... FINISHED DESKTOP SWITCH\n"); */ - + /* Fix up stacking order. */ + sync_actor_stacking (compositor); } void -meta_switch_workspace_completed (MetaScreen *screen) +meta_switch_workspace_completed (MetaCompositor *compositor) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - /* FIXME -- must redo stacking order */ - info->switch_workspace_in_progress--; - if (info->switch_workspace_in_progress < 0) + compositor->switch_workspace_in_progress--; + if (compositor->switch_workspace_in_progress < 0) { g_warning ("Error in workspace_switch accounting!"); - info->switch_workspace_in_progress = 0; + compositor->switch_workspace_in_progress = 0; } - if (!info->switch_workspace_in_progress) - meta_finish_workspace_switch (info); + if (!compositor->switch_workspace_in_progress) + meta_finish_workspace_switch (compositor); } void @@ -137,48 +135,27 @@ meta_compositor_destroy (MetaCompositor *compositor) clutter_threads_remove_repaint_func (compositor->repaint_func_id); } -static void -add_win (MetaWindow *window) -{ - MetaScreen *screen = meta_window_get_screen (window); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - g_return_if_fail (info != NULL); - - meta_window_actor_new (window); - - sync_actor_stacking (info); -} - static void process_damage (MetaCompositor *compositor, XDamageNotifyEvent *event, MetaWindow *window) { - MetaWindowActor *window_actor; - - if (window == NULL) - return; - - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (window_actor == NULL) - return; - - meta_window_actor_process_damage (window_actor, event); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + meta_window_actor_process_x11_damage (window_actor, event); } static Window -get_output_window (MetaScreen *screen) +get_output_window (MetaCompositor *compositor) { - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window output, xroot; + MetaDisplay *display = compositor->display; + Display *xdisplay = display->xdisplay; + Window output, xroot; XWindowAttributes attr; - long event_mask; + long event_mask; unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - xroot = meta_screen_get_xroot (screen); + xroot = display->screen->xroot; output = XCompositeGetOverlayWindow (xdisplay, xroot); meta_core_add_old_event_mask (xdisplay, output, &mask); @@ -203,6 +180,13 @@ get_output_window (MetaScreen *screen) return output; } +/* compat helper */ +static MetaCompositor * +get_compositor_for_screen (MetaScreen *screen) +{ + return screen->display->compositor; +} + /** * meta_get_stage_for_screen: * @screen: a #MetaScreen @@ -212,12 +196,8 @@ get_output_window (MetaScreen *screen) ClutterActor * meta_get_stage_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->stage; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->stage; } /** @@ -229,12 +209,8 @@ meta_get_stage_for_screen (MetaScreen *screen) ClutterActor * meta_get_window_group_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->window_group; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->window_group; } /** @@ -246,12 +222,8 @@ meta_get_window_group_for_screen (MetaScreen *screen) ClutterActor * meta_get_top_window_group_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->top_window_group; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->top_window_group; } /** @@ -263,31 +235,35 @@ meta_get_top_window_group_for_screen (MetaScreen *screen) GList * meta_get_window_actors (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->windows; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->windows; } void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); - - XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); - - /* It's generally a good heuristic that when a crossing event is generated because - * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - - * it's not the user doing something, it's the environment changing under the user. + /* As a wayland compositor we can simply ignore all this trickery + * for setting an input region on the stage for capturing events in + * clutter since all input comes to us first and we get to choose + * who else sees them. */ - meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); - XFixesSetWindowShapeRegion (xdpy, info->output, ShapeInput, 0, 0, region); + if (!meta_is_wayland_compositor ()) + { + MetaDisplay *display = screen->display; + MetaCompositor *compositor = display->compositor; + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); + + XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); + + /* It's generally a good heuristic that when a crossing event is generated because + * we reshape the overlay, we don't want it to affect focus-follows-mouse focus - + * it's not the user doing something, it's the environment changing under the user. + */ + meta_display_add_ignored_crossing_serial (display, XNextRequest (xdpy)); + XFixesSetWindowShapeRegion (xdpy, compositor->output, ShapeInput, 0, 0, region); + } } void @@ -335,6 +311,9 @@ meta_stage_is_focused (MetaScreen *screen) ClutterStage *stage; Window window; + if (meta_is_wayland_compositor ()) + return TRUE; + stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); if (!stage) return FALSE; @@ -347,34 +326,18 @@ meta_stage_is_focused (MetaScreen *screen) return (screen->display->focus_xwindow == window); } -gboolean -meta_begin_modal_for_plugin (MetaScreen *screen, - MetaPlugin *plugin, - MetaModalOptions options, - guint32 timestamp) +static gboolean +begin_modal_x11 (MetaCompositor *compositor, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) { - /* To some extent this duplicates code in meta_display_begin_grab_op(), but there - * are significant differences in how we handle grabs that make it difficult to - * merge the two. - */ - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - MetaCompositor *compositor = display->compositor; - ClutterStage *stage; - Window grab_window; - Cursor cursor = None; - gboolean pointer_grabbed = FALSE; - gboolean keyboard_grabbed = FALSE; - int result; - - stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); - if (!stage) - return FALSE; - - grab_window = clutter_x11_get_stage_window (stage); - - if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE) - return FALSE; + MetaDisplay *display = compositor->display; + Display *xdpy = meta_display_get_xdisplay (display); + Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); + int result; + gboolean pointer_grabbed = FALSE; + gboolean keyboard_grabbed = FALSE; if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) { @@ -391,7 +354,7 @@ meta_begin_modal_for_plugin (MetaScreen *screen, META_VIRTUAL_CORE_POINTER_ID, grab_window, timestamp, - cursor, + None, XIGrabModeAsync, XIGrabModeAsync, False, /* owner_events */ &mask); @@ -424,14 +387,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen, keyboard_grabbed = TRUE; } - display->grab_op = META_GRAB_OP_COMPOSITOR; - display->grab_window = NULL; - display->grab_screen = screen; - display->grab_have_pointer = TRUE; - display->grab_have_keyboard = TRUE; - - compositor->modal_plugin = plugin; - return TRUE; fail: @@ -443,45 +398,59 @@ meta_begin_modal_for_plugin (MetaScreen *screen, return FALSE; } +gboolean +meta_begin_modal_for_plugin (MetaCompositor *compositor, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) +{ + /* To some extent this duplicates code in meta_display_begin_grab_op(), but there + * are significant differences in how we handle grabs that make it difficult to + * merge the two. + */ + MetaDisplay *display = compositor->display; + + if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE) + return FALSE; + + if (!meta_is_wayland_compositor ()) + if (!begin_modal_x11 (compositor, plugin, options, timestamp)) + return FALSE; + + display->grab_op = META_GRAB_OP_COMPOSITOR; + display->grab_window = NULL; + display->grab_have_pointer = TRUE; + display->grab_have_keyboard = TRUE; + + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); + + return TRUE; +} + void -meta_end_modal_for_plugin (MetaScreen *screen, +meta_end_modal_for_plugin (MetaCompositor *compositor, MetaPlugin *plugin, guint32 timestamp) { - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - MetaCompositor *compositor = display->compositor; + MetaDisplay *display = compositor->display; + Display *xdpy = meta_display_get_xdisplay (display); - g_return_if_fail (compositor->modal_plugin == plugin); - - XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); - XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); + g_return_if_fail (is_modal (display)); display->grab_op = META_GRAB_OP_NONE; display->grab_window = NULL; - display->grab_screen = NULL; display->grab_have_pointer = FALSE; display->grab_have_keyboard = FALSE; - compositor->modal_plugin = NULL; -} - -/* This is used when reloading plugins to make sure we don't have - * a left-over modal grab for this screen. - */ -void -meta_check_end_modal (MetaScreen *screen) -{ - MetaDisplay *display = meta_screen_get_display (screen); - MetaCompositor *compositor = display->compositor; - - if (compositor->modal_plugin && - meta_plugin_get_screen (compositor->modal_plugin) == screen) + if (meta_is_wayland_compositor ()) { - meta_end_modal_for_plugin (screen, - compositor->modal_plugin, - - CurrentTime); + meta_display_sync_wayland_input_focus (display); + } + else + { + XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); + XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); } } @@ -489,16 +458,18 @@ static void after_stage_paint (ClutterStage *stage, gpointer data) { - MetaCompScreen *info = (MetaCompScreen*) data; + MetaCompositor *compositor = data; GList *l; - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_post_paint (l->data); + + if (meta_is_wayland_compositor ()) + meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ()); } static void -redirect_windows (MetaCompositor *compositor, - MetaScreen *screen) +redirect_windows (MetaScreen *screen) { MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); @@ -520,7 +491,7 @@ redirect_windows (MetaCompositor *compositor, */ while (TRUE) { - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual); XSync (xdisplay, FALSE); @@ -541,145 +512,152 @@ redirect_windows (MetaCompositor *compositor, } void -meta_compositor_manage_screen (MetaCompositor *compositor, - MetaScreen *screen) +meta_compositor_manage (MetaCompositor *compositor) { - MetaCompScreen *info; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xwin; - gint width, height; + MetaDisplay *display = compositor->display; + Display *xdisplay = display->xdisplay; + MetaScreen *screen = display->screen; + Window xwin = 0; + gint width, height; + MetaWaylandCompositor *wayland_compositor; - /* Check if the screen is already managed */ - if (meta_screen_get_compositor_data (screen)) - return; + meta_screen_set_cm_selection (display->screen); - info = g_new0 (MetaCompScreen, 1); - info->screen = screen; + /* We will have already created a stage if running as a wayland + * compositor... */ + if (meta_is_wayland_compositor ()) + { + wayland_compositor = meta_wayland_compositor_get_default (); + compositor->stage = wayland_compositor->stage; - meta_screen_set_compositor_data (screen, info); + meta_screen_get_size (screen, &width, &height); + clutter_actor_set_size (compositor->stage, width, height); + } + else + { + compositor->stage = clutter_stage_new (); - info->output = None; - info->windows = NULL; + meta_screen_get_size (screen, &width, &height); + clutter_actor_realize (compositor->stage); - meta_screen_set_cm_selection (screen); + xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); - info->stage = clutter_stage_new (); + XResizeWindow (xdisplay, xwin, width, height); - clutter_stage_set_paint_callback (CLUTTER_STAGE (info->stage), + { + long event_mask; + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + XWindowAttributes attr; + + meta_core_add_old_event_mask (xdisplay, xwin, &mask); + + XISetMask (mask.mask, XI_KeyPress); + XISetMask (mask.mask, XI_KeyRelease); + XISetMask (mask.mask, XI_ButtonPress); + XISetMask (mask.mask, XI_ButtonRelease); + XISetMask (mask.mask, XI_Enter); + XISetMask (mask.mask, XI_Leave); + XISetMask (mask.mask, XI_FocusIn); + XISetMask (mask.mask, XI_FocusOut); + XISetMask (mask.mask, XI_Motion); + XIClearMask (mask.mask, XI_TouchBegin); + XIClearMask (mask.mask, XI_TouchEnd); + XIClearMask (mask.mask, XI_TouchUpdate); + XISelectEvents (xdisplay, xwin, &mask, 1); + + event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask; + if (XGetWindowAttributes (xdisplay, xwin, &attr)) + event_mask |= attr.your_event_mask; + + XSelectInput (xdisplay, xwin, event_mask); + } + } + + clutter_stage_set_paint_callback (CLUTTER_STAGE (compositor->stage), after_stage_paint, - info, + compositor, NULL); - clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY); + clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY); - meta_screen_get_size (screen, &width, &height); - clutter_actor_realize (info->stage); + compositor->window_group = meta_window_group_new (screen); + compositor->top_window_group = meta_window_group_new (screen); - xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + clutter_actor_add_child (compositor->stage, compositor->window_group); + clutter_actor_add_child (compositor->stage, compositor->top_window_group); - XResizeWindow (xdisplay, xwin, width, height); + if (meta_is_wayland_compositor ()) + { + /* NB: When running as a wayland compositor we don't need an X + * composite overlay window, and we don't need to play any input + * region tricks to redirect events into clutter. */ + compositor->output = None; + } + else + { + compositor->output = get_output_window (compositor); + XReparentWindow (xdisplay, xwin, compositor->output, 0, 0); - { - long event_mask; - unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; - XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - XWindowAttributes attr; + meta_empty_stage_input_region (screen); - meta_core_add_old_event_mask (xdisplay, xwin, &mask); + /* Make sure there isn't any left-over output shape on the + * overlay window by setting the whole screen to be an + * output region. + * + * Note: there doesn't seem to be any real chance of that + * because the X server will destroy the overlay window + * when the last client using it exits. + */ + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); - XISetMask (mask.mask, XI_KeyPress); - XISetMask (mask.mask, XI_KeyRelease); - XISetMask (mask.mask, XI_ButtonPress); - XISetMask (mask.mask, XI_ButtonRelease); - XISetMask (mask.mask, XI_Enter); - XISetMask (mask.mask, XI_Leave); - XISetMask (mask.mask, XI_FocusIn); - XISetMask (mask.mask, XI_FocusOut); - XISetMask (mask.mask, XI_Motion); - XIClearMask (mask.mask, XI_TouchBegin); - XIClearMask (mask.mask, XI_TouchEnd); - XIClearMask (mask.mask, XI_TouchUpdate); - XISelectEvents (xdisplay, xwin, &mask, 1); + /* Map overlay window before redirecting windows offscreen so we catch their + * contents until we show the stage. + */ + XMapWindow (xdisplay, compositor->output); + } - event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask; - if (XGetWindowAttributes (xdisplay, xwin, &attr)) - event_mask |= attr.your_event_mask; + redirect_windows (display->screen); - XSelectInput (xdisplay, xwin, event_mask); - } - - info->window_group = meta_window_group_new (screen); - info->top_window_group = meta_window_group_new (screen); - - clutter_actor_add_child (info->stage, info->window_group); - clutter_actor_add_child (info->stage, info->top_window_group); - - info->output = get_output_window (screen); - XReparentWindow (xdisplay, xwin, info->output, 0, 0); - - /* Make sure there isn't any left-over output shape on the - * overlay window by setting the whole screen to be an - * output region. - * - * Note: there doesn't seem to be any real chance of that - * because the X server will destroy the overlay window - * when the last client using it exits. - */ - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); - - info->output = get_output_window (screen); - XReparentWindow (xdisplay, xwin, info->output, 0, 0); - - meta_empty_stage_input_region (screen); - - /* Make sure there isn't any left-over output shape on the - * overlay window by setting the whole screen to be an - * output region. - * - * Note: there doesn't seem to be any real chance of that - * because the X server will destroy the overlay window - * when the last client using it exits. - */ - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); - - /* Map overlay window before redirecting windows offscreen so we catch their - * contents until we show the stage. - */ - XMapWindow (xdisplay, info->output); - - redirect_windows (compositor, screen); - - info->plugin_mgr = meta_plugin_manager_new (screen); + compositor->plugin_mgr = meta_plugin_manager_new (compositor); } void -meta_compositor_unmanage_screen (MetaCompositor *compositor, - MetaScreen *screen) +meta_compositor_unmanage (MetaCompositor *compositor) { - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xroot = meta_screen_get_xroot (screen); + if (!meta_is_wayland_compositor ()) + { + MetaDisplay *display = compositor->display; + Display *xdisplay = meta_display_get_xdisplay (display); + Window xroot = display->screen->xroot; - /* This is the most important part of cleanup - we have to do this - * before giving up the window manager selection or the next - * window manager won't be able to redirect subwindows */ - XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); + /* This is the most important part of cleanup - we have to do this + * before giving up the window manager selection or the next + * window manager won't be able to redirect subwindows */ + XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual); + } } -/* - * Shapes the cow so that the given window is exposed, - * when metaWindow is NULL it clears the shape again +/** + * meta_shape_cow_for_window: + * @compositor: A #MetaCompositor + * @window: (allow-none): A #MetaWindow to shape the COW for + * + * Sets an bounding shape on the COW so that the given window + * is exposed. If @window is %NULL it clears the shape again. + * + * Used so we can unredirect windows, by shaping away the part + * of the COW, letting the raw window be seen through below. */ static void -meta_shape_cow_for_window (MetaScreen *screen, - MetaWindow *metaWindow) +meta_shape_cow_for_window (MetaCompositor *compositor, + MetaWindow *window) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen)); + MetaDisplay *display = compositor->display; + Display *xdisplay = meta_display_get_xdisplay (display); - if (metaWindow == NULL) - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None); + if (window == NULL) + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, None); else { XserverRegion output_region; @@ -687,14 +665,14 @@ meta_shape_cow_for_window (MetaScreen *screen, int width, height; MetaRectangle rect; - meta_window_get_frame_rect (metaWindow, &rect); + meta_window_get_frame_rect (window, &rect); window_bounds.x = rect.x; window_bounds.y = rect.y; window_bounds.width = rect.width; window_bounds.height = rect.height; - meta_screen_get_size (screen, &width, &height); + meta_screen_get_size (display->screen, &width, &height); screen_rect.x = 0; screen_rect.y = 0; screen_rect.width = width; @@ -703,46 +681,45 @@ meta_shape_cow_for_window (MetaScreen *screen, output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); - XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, output_region); + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region); XFixesDestroyRegion (xdisplay, output_region); } } static void -set_unredirected_window (MetaCompScreen *info, +set_unredirected_window (MetaCompositor *compositor, MetaWindow *window) { - if (info->unredirected_window == window) + if (compositor->unredirected_window == window) return; - if (info->unredirected_window != NULL) + if (compositor->unredirected_window != NULL) { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window)); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window)); meta_window_actor_set_unredirected (window_actor, FALSE); } - info->unredirected_window = window; + compositor->unredirected_window = window; - if (info->unredirected_window != NULL) + if (compositor->unredirected_window != NULL) { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (info->unredirected_window)); + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window)); meta_window_actor_set_unredirected (window_actor, TRUE); } - meta_shape_cow_for_window (info->screen, info->unredirected_window); + meta_shape_cow_for_window (compositor, compositor->unredirected_window); } void meta_compositor_add_window (MetaCompositor *compositor, MetaWindow *window) { - MetaScreen *screen = meta_window_get_screen (window); - MetaDisplay *display = meta_screen_get_display (screen); + MetaDisplay *display = compositor->display; - DEBUG_TRACE ("meta_compositor_add_window\n"); meta_error_trap_push (display); - add_win (window); + meta_window_actor_new (window); + sync_actor_stacking (compositor); meta_error_trap_pop (display); } @@ -751,20 +728,10 @@ void meta_compositor_remove_window (MetaCompositor *compositor, MetaWindow *window) { - MetaWindowActor *window_actor = NULL; - MetaScreen *screen; - MetaCompScreen *info; + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_remove_window\n"); - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (!window_actor) - return; - - screen = meta_window_get_screen (window); - info = meta_screen_get_compositor_data (screen); - - if (info->unredirected_window == window) - set_unredirected_window (info, NULL); + if (compositor->unredirected_window == window) + set_unredirected_window (compositor, NULL); meta_window_actor_destroy (window_actor); } @@ -774,13 +741,7 @@ meta_compositor_set_updates_frozen (MetaCompositor *compositor, MetaWindow *window, gboolean updates_frozen) { - MetaWindowActor *window_actor; - - DEBUG_TRACE ("meta_compositor_set_updates_frozen\n"); - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (!window_actor) - return; - + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); meta_window_actor_set_updates_frozen (window_actor, updates_frozen); } @@ -789,13 +750,7 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor, MetaWindow *window, gboolean no_delay_frame) { - MetaWindowActor *window_actor; - - DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n"); - window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - if (!window_actor) - return; - + MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame); } @@ -846,45 +801,87 @@ meta_compositor_window_opacity_changed (MetaCompositor *compositor, meta_window_actor_update_opacity (window_actor); } +void +meta_compositor_window_surface_changed (MetaCompositor *compositor, + MetaWindow *window) +{ + MetaWindowActor *window_actor; + window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + if (!window_actor) + return; + + meta_window_actor_update_surface (window_actor); +} + +static gboolean +event_is_passive_button_grab (MetaDisplay *display, + XIDeviceEvent *device_event) +{ + /* see display.c for which events are passive button + grabs (meta_display_grab_window_buttons() and + meta_display_handle_events()) + we need to filter them here because normally they + would be sent to gtk+ (they are on gtk+ frame xwindow), + but we want to redirect them to clutter + */ + + if (device_event->evtype != XI_ButtonPress) + return FALSE; + + if (display->window_grab_modifiers == 0) + return FALSE; + + if ((device_event->mods.effective & display->window_grab_modifiers) != + display->window_grab_modifiers) + return FALSE; + + return device_event->detail < 4; +} + /* Clutter makes the assumption that there is only one X window * per stage, which is a valid assumption to make for a generic * application toolkit. As such, it will ignore any events sent * to the a stage that isn't its X window. * - * When a user clicks on what she thinks is the wallpaper, she - * is actually clicking on the guard window, which is an entirely - * separate top-level override-redirect window in the hierarchy. - * We want to recieve events on this guard window so that users - * can right-click on the background actor. We do this by telling - * Clutter a little white lie, by transforming clicks on the guard - * window to become clicks on the stage window, allowing Clutter - * to process the event normally. + * When running as an X window manager, we need to respond to + * events from lots of windows. Trick Clutter into translating + * these events by pretending we got an event on the stage window. */ static void -maybe_spoof_guard_window_event_as_stage_event (MetaCompScreen *info, - XEvent *event) +maybe_spoof_event_as_stage_event (MetaCompositor *compositor, + MetaWindow *window, + XEvent *event) { - MetaDisplay *display = meta_screen_get_display (info->screen); + MetaDisplay *display = compositor->display; if (event->type == GenericEvent && event->xcookie.extension == display->xinput_opcode) { XIEvent *input_event = (XIEvent *) event->xcookie.data; + XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event); - /* Only care about pointer events for now. */ switch (input_event->evtype) { case XI_Motion: case XI_ButtonPress: case XI_ButtonRelease: - { - XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event); - if (device_event->event == info->screen->guard_window) - { - Window xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); - device_event->event = xwin; - } - } + /* If this is a window frame, and we think GTK+ needs to handle the event, + let GTK+ handle it without mangling */ + if (window && window->frame && device_event->event == window->frame->xwindow && + (meta_grab_op_is_clicking (display->grab_op) || + (display->grab_op == META_GRAB_OP_NONE && !event_is_passive_button_grab (display, device_event)))) + break; + + case XI_KeyPress: + case XI_KeyRelease: + /* If this is a GTK+ widget, like a window menu, let GTK+ handle + * it as-is without mangling. */ + if (meta_ui_window_is_widget (display->screen->ui, device_event->event)) + break; + + device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); + device_event->event_x = device_event->root_x; + device_event->event_y = device_event->root_y; break; default: break; @@ -904,55 +901,25 @@ meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window) { - if (compositor->modal_plugin && is_grabbed_event (compositor->display, event)) + MetaDisplay *display = compositor->display; + + if (is_modal (display) && is_grabbed_event (display, event)) { - _meta_plugin_xevent_filter (compositor->modal_plugin, event); + meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event); /* We always consume events even if the plugin says it didn't handle them; * exclusive is exclusive */ return TRUE; } - if (window) - { - MetaCompScreen *info; - MetaScreen *screen; + if (!meta_is_wayland_compositor ()) + maybe_spoof_event_as_stage_event (compositor, window, event); - screen = meta_window_get_screen (window); - info = meta_screen_get_compositor_data (screen); + if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event)) + return TRUE; - if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event)) - { - DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n"); - return TRUE; - } - } - else - { - GSList *l; - - l = meta_display_get_screens (compositor->display); - - while (l) - { - MetaScreen *screen = l->data; - MetaCompScreen *info; - - info = meta_screen_get_compositor_data (screen); - - maybe_spoof_guard_window_event_as_stage_event (info, event); - - if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event)) - { - DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n"); - return TRUE; - } - - l = l->next; - } - } - - if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify) + if (!meta_is_wayland_compositor () && + event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify) { /* Core code doesn't handle damage events, so we need to extract the MetaWindow * ourselves @@ -963,13 +930,13 @@ meta_compositor_process_event (MetaCompositor *compositor, window = meta_display_lookup_x_window (compositor->display, xwin); } - DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n"); - process_damage (compositor, (XDamageNotifyEvent *) event, window); + if (window) + process_damage (compositor, (XDamageNotifyEvent *) event, window); } /* Clutter needs to know about MapNotify events otherwise it will think the stage is invisible */ - if (event->type == MapNotify) + if (!meta_is_wayland_compositor () && event->type == MapNotify) clutter_x11_handle_event (event); /* The above handling is basically just "observing" the events, so we return @@ -981,15 +948,9 @@ meta_compositor_process_event (MetaCompositor *compositor, gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, - MetaScreen *screen, MetaKeyBinding *binding) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (info->plugin_mgr) - return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding); - - return FALSE; + return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding); } void @@ -998,11 +959,7 @@ meta_compositor_show_window (MetaCompositor *compositor, MetaCompEffect effect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_show_window\n"); - if (!window_actor) - return; - - meta_window_actor_show (window_actor, effect); + meta_window_actor_show (window_actor, effect); } void @@ -1011,10 +968,6 @@ meta_compositor_hide_window (MetaCompositor *compositor, MetaCompEffect effect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_hide_window\n"); - if (!window_actor) - return; - meta_window_actor_hide (window_actor, effect); } @@ -1025,10 +978,6 @@ meta_compositor_maximize_window (MetaCompositor *compositor, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_maximize_window\n"); - if (!window_actor) - return; - meta_window_actor_maximize (window_actor, old_rect, new_rect); } @@ -1039,53 +988,40 @@ meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaRectangle *new_rect) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - DEBUG_TRACE ("meta_compositor_unmaximize_window\n"); - if (!window_actor) - return; - meta_window_actor_unmaximize (window_actor, old_rect, new_rect); } void meta_compositor_switch_workspace (MetaCompositor *compositor, - MetaScreen *screen, MetaWorkspace *from, MetaWorkspace *to, MetaMotionDirection direction) { - MetaCompScreen *info; - gint to_indx, from_indx; + gint to_indx, from_indx; - info = meta_screen_get_compositor_data (screen); to_indx = meta_workspace_index (to); from_indx = meta_workspace_index (from); - DEBUG_TRACE ("meta_compositor_switch_workspace\n"); + compositor->switch_workspace_in_progress++; - if (!info) /* During startup before manage_screen() */ - return; - - info->switch_workspace_in_progress++; - - if (!info->plugin_mgr || - !meta_plugin_manager_switch_workspace (info->plugin_mgr, - from_indx, - to_indx, - direction)) + if (!meta_plugin_manager_switch_workspace (compositor->plugin_mgr, + from_indx, + to_indx, + direction)) { - info->switch_workspace_in_progress--; + compositor->switch_workspace_in_progress--; /* We have to explicitely call this to fix up stacking order of the * actors; this is because the abs stacking position of actors does not * necessarily change during the window hiding/unhiding, only their * relative position toward the destkop window. */ - meta_finish_workspace_switch (info); + meta_finish_workspace_switch (compositor); } } static void -sync_actor_stacking (MetaCompScreen *info) +sync_actor_stacking (MetaCompositor *compositor) { GList *children; GList *expected_window_node; @@ -1101,7 +1037,7 @@ sync_actor_stacking (MetaCompScreen *info) * little effort to make sure we actually need to restack before * we go ahead and do it */ - children = clutter_actor_get_children (info->window_group); + children = clutter_actor_get_children (compositor->window_group); has_windows = FALSE; reordered = FALSE; @@ -1113,7 +1049,7 @@ sync_actor_stacking (MetaCompScreen *info) /* First we collect a list of all backgrounds, and check if they're at the * bottom. Then we check if the window actors are in the correct sequence */ backgrounds = NULL; - expected_window_node = info->windows; + expected_window_node = compositor->windows; for (old = children; old != NULL; old = old->next) { ClutterActor *actor = old->data; @@ -1151,7 +1087,7 @@ sync_actor_stacking (MetaCompScreen *info) * We reorder the actors even if they're not parented to the window group, * to allow stacking to work with intermediate actors (eg during effects) */ - for (tmp = g_list_last (info->windows); tmp != NULL; tmp = tmp->prev) + for (tmp = g_list_last (compositor->windows); tmp != NULL; tmp = tmp->prev) { ClutterActor *actor = tmp->data, *parent; @@ -1174,13 +1110,9 @@ sync_actor_stacking (MetaCompScreen *info) void meta_compositor_sync_stack (MetaCompositor *compositor, - MetaScreen *screen, GList *stack) { GList *old_stack; - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - DEBUG_TRACE ("meta_compositor_sync_stack\n"); /* This is painful because hidden windows that we are in the process * of animating out of existence. They'll be at the bottom of the @@ -1190,8 +1122,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor, /* Sources: first window is the highest */ stack = g_list_copy (stack); /* The new stack of MetaWindow */ - old_stack = g_list_reverse (info->windows); /* The old stack of MetaWindowActor */ - info->windows = NULL; + old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */ + compositor->windows = NULL; while (TRUE) { @@ -1255,13 +1187,13 @@ meta_compositor_sync_stack (MetaCompositor *compositor, * be at the front of at least one, hopefully it will be * near the front of the other.) */ - info->windows = g_list_prepend (info->windows, actor); + compositor->windows = g_list_prepend (compositor->windows, actor); stack = g_list_remove (stack, window); old_stack = g_list_remove (old_stack, actor); } - sync_actor_stacking (info); + sync_actor_stacking (compositor); } void @@ -1270,40 +1202,44 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor, gboolean did_placement) { MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); - MetaScreen *screen = meta_window_get_screen (window); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - DEBUG_TRACE ("meta_compositor_sync_window_geometry\n"); - g_return_if_fail (info); - - if (!window_actor) - return; - meta_window_actor_sync_actor_geometry (window_actor, did_placement); } void meta_compositor_sync_screen_size (MetaCompositor *compositor, - MetaScreen *screen, guint width, guint height) { - MetaDisplay *display = meta_screen_get_display (screen); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - Display *xdisplay; - Window xwin; + MetaDisplay *display = compositor->display; - DEBUG_TRACE ("meta_compositor_sync_screen_size\n"); - g_return_if_fail (info); + if (meta_is_wayland_compositor ()) + { + /* FIXME: when we support a sliced stage, this is the place to do it + But! This is not the place to apply KMS config, here we only + notify Clutter/Cogl/GL that the framebuffer sizes changed. - xdisplay = meta_display_get_xdisplay (display); - xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + And because for now clutter does not do sliced, we use one + framebuffer the size of the whole screen, and when running on + bare metal MetaMonitorManager will do the necessary tricks to + show the right portions on the right screens. + */ - XResizeWindow (xdisplay, xwin, width, height); + clutter_actor_set_size (compositor->stage, width, height); + } + else + { + Display *xdisplay; + Window xwin; + + xdisplay = meta_display_get_xdisplay (display); + xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage)); + + XResizeWindow (xdisplay, xwin, width, height); + } meta_verbose ("Changed size for stage on screen %d to %dx%d\n", - meta_screen_get_screen_number (screen), - width, height); + meta_screen_get_screen_number (display->screen), + width, height); } static void @@ -1312,7 +1248,7 @@ frame_callback (CoglOnscreen *onscreen, CoglFrameInfo *frame_info, void *user_data) { - MetaCompScreen *info = user_data; + MetaCompositor *compositor = user_data; GList *l; if (event == COGL_FRAME_EVENT_COMPLETE) @@ -1343,38 +1279,38 @@ frame_callback (CoglOnscreen *onscreen, presentation_time = 0; } - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_frame_complete (l->data, frame_info, presentation_time); } } static void -pre_paint_windows (MetaCompScreen *info) +pre_paint_windows (MetaCompositor *compositor) { GList *l; MetaWindowActor *top_window; - if (info->onscreen == NULL) + if (compositor->onscreen == NULL) { - info->onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); - info->frame_closure = cogl_onscreen_add_frame_callback (info->onscreen, - frame_callback, - info, - NULL); + compositor->onscreen = COGL_ONSCREEN (cogl_get_draw_framebuffer ()); + compositor->frame_closure = cogl_onscreen_add_frame_callback (compositor->onscreen, + frame_callback, + compositor, + NULL); } - if (info->windows == NULL) + if (compositor->windows == NULL) return; - top_window = g_list_last (info->windows)->data; + top_window = g_list_last (compositor->windows)->data; if (meta_window_actor_should_unredirect (top_window) && - info->disable_unredirect_count == 0) - set_unredirected_window (info, meta_window_actor_get_meta_window (top_window)); + compositor->disable_unredirect_count == 0) + set_unredirected_window (compositor, meta_window_actor_get_meta_window (top_window)); else - set_unredirected_window (info, NULL); + set_unredirected_window (compositor, NULL); - for (l = info->windows; l; l = l->next) + for (l = compositor->windows; l; l = l->next) meta_window_actor_pre_paint (l->data); } @@ -1382,19 +1318,7 @@ static gboolean meta_repaint_func (gpointer data) { MetaCompositor *compositor = data; - GSList *screens = meta_display_get_screens (compositor->display); - GSList *l; - - for (l = screens; l; l = l->next) - { - MetaScreen *screen = l->data; - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (!info) - continue; - - pre_paint_windows (info); - } - + pre_paint_windows (compositor); return TRUE; } @@ -1402,20 +1326,10 @@ static void on_shadow_factory_changed (MetaShadowFactory *factory, MetaCompositor *compositor) { - GSList *screens = meta_display_get_screens (compositor->display); GList *l; - GSList *sl; - for (sl = screens; sl; sl = sl->next) - { - MetaScreen *screen = sl->data; - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (!info) - continue; - - for (l = info->windows; l; l = l->next) - meta_window_actor_invalidate_shadow (l->data); - } + for (l = compositor->windows; l; l = l->next) + meta_window_actor_invalidate_shadow (l->data); } /** @@ -1458,9 +1372,8 @@ meta_compositor_new (MetaDisplay *display) Window meta_get_overlay_window (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - return info->output; + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->output; } /** @@ -1474,9 +1387,8 @@ meta_get_overlay_window (MetaScreen *screen) void meta_disable_unredirect_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (info != NULL) - info->disable_unredirect_count = info->disable_unredirect_count + 1; + MetaCompositor *compositor = get_compositor_for_screen (screen); + compositor->disable_unredirect_count++; } /** @@ -1489,11 +1401,11 @@ meta_disable_unredirect_for_screen (MetaScreen *screen) void meta_enable_unredirect_for_screen (MetaScreen *screen) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - if (info != NULL && info->disable_unredirect_count == 0) + MetaCompositor *compositor = get_compositor_for_screen (screen); + if (compositor->disable_unredirect_count == 0) g_warning ("Called enable_unredirect_for_screen while unredirection is enabled."); - if (info != NULL && info->disable_unredirect_count > 0) - info->disable_unredirect_count = info->disable_unredirect_count - 1; + if (compositor->disable_unredirect_count > 0) + compositor->disable_unredirect_count--; } #define FLASH_TIME_MS 50 @@ -1590,28 +1502,16 @@ meta_compositor_monotonic_time_to_server_time (MetaDisplay *display, void meta_compositor_show_tile_preview (MetaCompositor *compositor, - MetaScreen *screen, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info->plugin_mgr) - return; - - meta_plugin_manager_show_tile_preview (info->plugin_mgr, + meta_plugin_manager_show_tile_preview (compositor->plugin_mgr, window, tile_rect, tile_monitor_number); } void -meta_compositor_hide_tile_preview (MetaCompositor *compositor, - MetaScreen *screen) +meta_compositor_hide_tile_preview (MetaCompositor *compositor) { - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info->plugin_mgr) - return; - - meta_plugin_manager_hide_tile_preview (info->plugin_mgr); + meta_plugin_manager_hide_tile_preview (compositor->plugin_mgr); } diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c index 4337f7053..825ee90d1 100644 --- a/src/compositor/meta-background.c +++ b/src/compositor/meta-background.c @@ -26,8 +26,6 @@ #include -#include - #include #include "cogl-utils.h" @@ -755,88 +753,6 @@ set_filename (MetaBackground *self, priv->filename = g_strdup (filename); } -static Pixmap -get_still_frame_for_monitor (MetaScreen *screen, - int monitor) -{ - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - Window xroot = meta_screen_get_xroot (screen); - Pixmap pixmap; - GC gc; - XGCValues values; - MetaRectangle geometry; - int depth; - - meta_screen_get_monitor_geometry (screen, monitor, &geometry); - - depth = DefaultDepth (xdisplay, meta_screen_get_screen_number (screen)); - - pixmap = XCreatePixmap (xdisplay, - xroot, - geometry.width, geometry.height, depth); - - values.function = GXcopy; - values.plane_mask = AllPlanes; - values.fill_style = FillSolid; - values.subwindow_mode = IncludeInferiors; - - gc = XCreateGC (xdisplay, - xroot, - GCFunction | GCPlaneMask | GCFillStyle | GCSubwindowMode, - &values); - - XCopyArea (xdisplay, - xroot, pixmap, gc, - geometry.x, geometry.y, - geometry.width, geometry.height, - 0, 0); - - XFreeGC (xdisplay, gc); - - return pixmap; -} - -/** - * meta_background_load_still_frame: - * @self: the #MetaBackground - * - * Takes a screenshot of the desktop and uses it as the background - * source. - */ -void -meta_background_load_still_frame (MetaBackground *self) -{ - MetaBackgroundPrivate *priv = self->priv; - MetaDisplay *display = meta_screen_get_display (priv->screen); - Pixmap still_frame; - CoglTexture *texture; - CoglContext *context = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - GError *error = NULL; - - ensure_pipeline (self); - - unset_texture (self); - set_style (self, G_DESKTOP_BACKGROUND_STYLE_STRETCHED); - - still_frame = get_still_frame_for_monitor (priv->screen, priv->monitor); - XSync (meta_display_get_xdisplay (display), False); - - meta_error_trap_push (display); - texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (context, still_frame, FALSE, &error)); - meta_error_trap_pop (display); - - if (error != NULL) - { - g_warning ("Failed to create background texture from pixmap: %s", - error->message); - g_error_free (error); - return; - } - - set_texture (self, texture); -} - /** * meta_background_load_gradient: * @self: the #MetaBackground diff --git a/src/compositor/meta-plugin-manager.c b/src/compositor/meta-plugin-manager.c index 41589a32c..8987e219d 100644 --- a/src/compositor/meta-plugin-manager.c +++ b/src/compositor/meta-plugin-manager.c @@ -37,7 +37,7 @@ static GType plugin_type = G_TYPE_NONE; struct MetaPluginManager { - MetaScreen *screen; + MetaCompositor *compositor; MetaPlugin *plugin; }; @@ -91,7 +91,7 @@ on_confirm_display_change (MetaMonitorManager *monitors, } MetaPluginManager * -meta_plugin_manager_new (MetaScreen *screen) +meta_plugin_manager_new (MetaCompositor *compositor) { MetaPluginManager *plugin_mgr; MetaPluginClass *klass; @@ -99,8 +99,10 @@ meta_plugin_manager_new (MetaScreen *screen) MetaMonitorManager *monitors; plugin_mgr = g_new0 (MetaPluginManager, 1); - plugin_mgr->screen = screen; - plugin_mgr->plugin = plugin = g_object_new (plugin_type, "screen", screen, NULL); + plugin_mgr->compositor = compositor; + plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL); + + _meta_plugin_set_compositor (plugin, compositor); klass = META_PLUGIN_GET_CLASS (plugin); @@ -151,7 +153,7 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; gboolean retval = FALSE; if (display->display_opening) @@ -165,8 +167,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->minimize (plugin, actor); } break; @@ -176,8 +176,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->map (plugin, actor); } break; @@ -185,7 +183,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr, if (klass->destroy) { retval = TRUE; - _meta_plugin_effect_started (plugin); klass->destroy (plugin, actor); } break; @@ -216,7 +213,7 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; gboolean retval = FALSE; if (display->display_opening) @@ -230,8 +227,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->maximize (plugin, actor, target_x, target_y, target_width, target_height); @@ -243,8 +238,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr, retval = TRUE; meta_plugin_manager_kill_window_effects (plugin_mgr, actor); - - _meta_plugin_effect_started (plugin); klass->unmaximize (plugin, actor, target_x, target_y, target_width, target_height); @@ -273,7 +266,7 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; gboolean retval = FALSE; if (display->display_opening) @@ -283,8 +276,6 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr, { retval = TRUE; meta_plugin_manager_kill_switch_workspace (plugin_mgr); - - _meta_plugin_effect_started (plugin); klass->switch_workspace (plugin, from, to, direction); } @@ -333,7 +324,7 @@ meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr, { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; if (display->display_opening) return FALSE; @@ -352,7 +343,7 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr) { MetaPlugin *plugin = plugin_mgr->plugin; MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); - MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen); + MetaDisplay *display = plugin_mgr->compositor->display; if (display->display_opening) return FALSE; diff --git a/src/compositor/meta-plugin-manager.h b/src/compositor/meta-plugin-manager.h index efc4deb52..d814ee677 100644 --- a/src/compositor/meta-plugin-manager.h +++ b/src/compositor/meta-plugin-manager.h @@ -44,7 +44,7 @@ */ typedef struct MetaPluginManager MetaPluginManager; -MetaPluginManager * meta_plugin_manager_new (MetaScreen *screen); +MetaPluginManager * meta_plugin_manager_new (MetaCompositor *compositor); void meta_plugin_manager_load (const gchar *plugin_name); diff --git a/src/compositor/meta-plugin.c b/src/compositor/meta-plugin.c index d4d49b6f5..d7c4f11d4 100644 --- a/src/compositor/meta-plugin.c +++ b/src/compositor/meta-plugin.c @@ -30,6 +30,7 @@ #include "meta-plugin-manager.h" #include #include +#include #include #include @@ -39,98 +40,22 @@ #include "compositor-private.h" #include "meta-window-actor-private.h" -#include "monitor-private.h" +#include "meta-monitor-manager.h" G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT); #define META_PLUGIN_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate)) -enum -{ - PROP_0, - PROP_SCREEN, - PROP_DEBUG_MODE, -}; - struct _MetaPluginPrivate { - MetaScreen *screen; - - gint running; - gboolean debug : 1; + MetaCompositor *compositor; }; -static void -meta_plugin_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaPluginPrivate *priv = META_PLUGIN (object)->priv; - - switch (prop_id) - { - case PROP_SCREEN: - priv->screen = g_value_get_object (value); - break; - case PROP_DEBUG_MODE: - priv->debug = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_plugin_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaPluginPrivate *priv = META_PLUGIN (object)->priv; - - switch (prop_id) - { - case PROP_SCREEN: - g_value_set_object (value, priv->screen); - break; - case PROP_DEBUG_MODE: - g_value_set_boolean (value, priv->debug); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - static void meta_plugin_class_init (MetaPluginClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->set_property = meta_plugin_set_property; - gobject_class->get_property = meta_plugin_get_property; - - g_object_class_install_property (gobject_class, - PROP_SCREEN, - g_param_spec_object ("screen", - "MetaScreen", - "MetaScreen", - META_TYPE_SCREEN, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_DEBUG_MODE, - g_param_spec_boolean ("debug-mode", - "Debug Mode", - "Debug Mode", - FALSE, - G_PARAM_READABLE)); - - g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate)); + g_type_class_add_private (klass, sizeof (MetaPluginPrivate)); } static void @@ -139,22 +64,6 @@ meta_plugin_init (MetaPlugin *self) self->priv = META_PLUGIN_GET_PRIVATE (self); } -gboolean -meta_plugin_running (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - return (priv->running > 0); -} - -gboolean -meta_plugin_debug_mode (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - return priv->debug; -} - const MetaPluginInfo * meta_plugin_get_info (MetaPlugin *plugin) { @@ -166,31 +75,26 @@ meta_plugin_get_info (MetaPlugin *plugin) return NULL; } -/** - * _meta_plugin_effect_started: - * @plugin: the plugin - * - * Mark that an effect has started for the plugin. This is called - * internally by MetaPluginManager. - */ -void -_meta_plugin_effect_started (MetaPlugin *plugin) -{ - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - priv->running++; -} - gboolean _meta_plugin_xevent_filter (MetaPlugin *plugin, XEvent *xev) { MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); + /* When mutter is running as a wayland compositor, things like input + * events just come directly from clutter so it won't have disabled + * clutter's event retrieval and won't need to forward it events (if + * it did it would lead to recursion). Also when running as a + * wayland compositor we shouldn't be assuming that we're running + * with the clutter x11 backend. + */ + if (klass->xevent_filter && klass->xevent_filter (plugin, xev)) return TRUE; - else + else if (!meta_is_wayland_compositor ()) return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE; + else + return FALSE; } void @@ -198,15 +102,7 @@ meta_plugin_switch_workspace_completed (MetaPlugin *plugin) { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - MetaScreen *screen = priv->screen; - - if (priv->running-- < 0) - { - g_warning ("Error in running effect accounting, adjusting."); - priv->running = 0; - } - - meta_switch_workspace_completed (screen); + meta_switch_workspace_completed (priv->compositor); } static void @@ -214,26 +110,6 @@ meta_plugin_window_effect_completed (MetaPlugin *plugin, MetaWindowActor *actor, unsigned long event) { - MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - - if (priv->running-- < 0) - { - g_warning ("Error in running effect accounting, adjusting."); - priv->running = 0; - } - - if (!actor) - { - const MetaPluginInfo *info; - const gchar *name = NULL; - - if (plugin && (info = meta_plugin_get_info (plugin))) - name = info->name; - - g_warning ("Plugin [%s] passed NULL for actor!", - name ? name : "unknown"); - } - meta_window_actor_effect_completed (actor, event); } @@ -300,7 +176,7 @@ meta_plugin_begin_modal (MetaPlugin *plugin, { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - return meta_begin_modal_for_plugin (priv->screen, plugin, + return meta_begin_modal_for_plugin (priv->compositor, plugin, options, timestamp); } @@ -321,16 +197,14 @@ meta_plugin_end_modal (MetaPlugin *plugin, { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - meta_end_modal_for_plugin (priv->screen, plugin, timestamp); + meta_end_modal_for_plugin (priv->compositor, plugin, timestamp); } /** * meta_plugin_get_screen: * @plugin: a #MetaPlugin * - * Gets the #MetaScreen corresponding to a plugin. Each plugin instance - * is associated with exactly one screen; if Metacity is managing - * multiple screens, multiple plugin instances will be created. + * Gets the #MetaScreen corresponding to a plugin. * * Return value: (transfer none): the #MetaScreen for the plugin */ @@ -339,7 +213,15 @@ meta_plugin_get_screen (MetaPlugin *plugin) { MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; - return priv->screen; + return priv->compositor->display->screen; +} + +void +_meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor) +{ + MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv; + + priv->compositor = compositor; } void diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 082b1b1ae..bbcf0f9ce 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -28,6 +28,7 @@ #include #include +#include #include "clutter-utils.h" #include "meta-texture-tower.h" @@ -42,8 +43,6 @@ static void meta_shaped_texture_dispose (GObject *object); static void meta_shaped_texture_paint (ClutterActor *actor); -static void meta_shaped_texture_pick (ClutterActor *actor, - const ClutterColor *color); static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, @@ -73,8 +72,6 @@ struct _MetaShapedTexturePrivate CoglTexture *texture; CoglTexture *mask_texture; - cairo_region_t *input_shape_region; - /* The region containing only fully opaque pixels */ cairo_region_t *opaque_region; @@ -98,7 +95,6 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass) actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width; actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height; actor_class->paint = meta_shaped_texture_paint; - actor_class->pick = meta_shaped_texture_pick; actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume; g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate)); @@ -232,6 +228,54 @@ paint_clipped_rectangle (CoglFramebuffer *fb, &coords[0], 8); } +static void +set_cogl_texture (MetaShapedTexture *stex, + CoglTexture *cogl_tex) +{ + MetaShapedTexturePrivate *priv; + guint width, height; + + g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); + + priv = stex->priv; + + if (priv->texture) + cogl_object_unref (priv->texture); + + priv->texture = cogl_tex; + + if (cogl_tex != NULL) + { + cogl_object_ref (cogl_tex); + width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); + height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); + + if (width != priv->tex_width || + height != priv->tex_height) + { + priv->tex_width = width; + priv->tex_height = height; + + clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); + } + } + else + { + /* size changed to 0 going to an invalid handle */ + priv->tex_width = 0; + priv->tex_height = 0; + clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); + } + + /* NB: We don't queue a redraw of the actor here because we don't + * know how much of the buffer has changed with respect to the + * previous buffer. We only queue a redraw in response to surface + * damage. */ + + if (priv->create_mipmaps) + meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); +} + static void meta_shaped_texture_paint (ClutterActor *actor) { @@ -415,71 +459,6 @@ meta_shaped_texture_paint (ClutterActor *actor) cairo_region_destroy (blended_region); } -static void -meta_shaped_texture_pick (ClutterActor *actor, - const ClutterColor *color) -{ - MetaShapedTexture *stex = (MetaShapedTexture *) actor; - MetaShapedTexturePrivate *priv = stex->priv; - - if (!clutter_actor_should_pick_paint (actor) || - (priv->clip_region && cairo_region_is_empty (priv->clip_region))) - return; - - /* If there is no region then use the regular pick */ - if (priv->input_shape_region == NULL) - CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color); - else - { - int n_rects; - float *rectangles; - int i; - CoglPipeline *pipeline; - CoglContext *ctx; - CoglFramebuffer *fb; - CoglColor cogl_color; - - /* Note: We don't bother trying to intersect the pick and clip regions - * since needing to copy the region, do the intersection, and probably - * increase the number of rectangles seems more likely to have a negative - * effect. - * - * NB: Most of the time when just using rectangles for picking then - * picking shouldn't involve any rendering, and minimizing the number of - * rectangles has more benefit than reducing the area of the pick - * region. - */ - - n_rects = cairo_region_num_rectangles (priv->input_shape_region); - rectangles = g_alloca (sizeof (float) * 4 * n_rects); - - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - int pos = i * 4; - - cairo_region_get_rectangle (priv->input_shape_region, i, &rect); - - rectangles[pos] = rect.x; - rectangles[pos + 1] = rect.y; - rectangles[pos + 2] = rect.x + rect.width; - rectangles[pos + 3] = rect.y + rect.height; - } - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - fb = cogl_get_draw_framebuffer (); - - cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); - - pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_color (pipeline, &cogl_color); - - cogl_framebuffer_draw_rectangles (fb, pipeline, - rectangles, n_rects); - cogl_object_unref (pipeline); - } -} - static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, @@ -699,53 +678,6 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, } } -static void -set_cogl_texture (MetaShapedTexture *stex, - CoglTexture *cogl_tex) -{ - MetaShapedTexturePrivate *priv; - guint width, height; - - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - priv = stex->priv; - - if (priv->texture != NULL) - cogl_object_unref (priv->texture); - - priv->texture = cogl_tex; - - if (cogl_tex != NULL) - { - width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex)); - height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex)); - - if (width != priv->tex_width || - height != priv->tex_height) - { - priv->tex_width = width; - priv->tex_height = height; - - clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); - } - } - else - { - /* size changed to 0 going to an invalid texture */ - priv->tex_width = 0; - priv->tex_height = 0; - clutter_actor_queue_relayout (CLUTTER_ACTOR (stex)); - } - - /* NB: We don't queue a redraw of the actor here because we don't - * know how much of the buffer has changed with respect to the - * previous buffer. We only queue a redraw in response to surface - * damage. */ - - if (priv->create_mipmaps) - meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex); -} - /** * meta_shaped_texture_set_texture: * @stex: The #MetaShapedTexture @@ -773,41 +705,6 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex) return COGL_TEXTURE (stex->priv->texture); } -/** - * meta_shaped_texture_set_input_shape_region: - * @stex: a #MetaShapedTexture - * @shape_region: the region of the texture that should respond to - * input. - * - * Determines what region of the texture should accept input. For - * X based windows this is defined by the ShapeInput region of the - * window. - */ -void -meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex, - cairo_region_t *shape_region) -{ - MetaShapedTexturePrivate *priv; - - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - priv = stex->priv; - - if (priv->input_shape_region != NULL) - { - cairo_region_destroy (priv->input_shape_region); - priv->input_shape_region = NULL; - } - - if (shape_region != NULL) - { - cairo_region_reference (shape_region); - priv->input_shape_region = shape_region; - } - - clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); -} - /** * meta_shaped_texture_set_opaque_region: * @stex: a #MetaShapedTexture diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c new file mode 100644 index 000000000..e0c6ff7b7 --- /dev/null +++ b/src/compositor/meta-surface-actor-wayland.c @@ -0,0 +1,195 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "meta-surface-actor-wayland.h" + +#include +#include "meta-shaped-texture-private.h" + +#include "wayland/meta-wayland-private.h" + +struct _MetaSurfaceActorWaylandPrivate +{ + MetaWaylandSurface *surface; + MetaWaylandBuffer *buffer; + struct wl_listener buffer_destroy_listener; +}; +typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorWayland, meta_surface_actor_wayland, META_TYPE_SURFACE_ACTOR) + +static void +meta_surface_actor_handle_buffer_destroy (struct wl_listener *listener, void *data) +{ + MetaSurfaceActorWaylandPrivate *priv = wl_container_of (listener, priv, buffer_destroy_listener); + + /* If the buffer is destroyed while we're attached to it, + * we want to unset priv->buffer so we don't access freed + * memory. Keep the texture set however so the user doesn't + * see the window disappear. */ + priv->buffer = NULL; +} + +static void +meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height) +{ + MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + if (priv->buffer) + { + struct wl_resource *resource = priv->buffer->resource; + struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource); + + if (shm_buffer) + { + CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture); + cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL); + } + + meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height); + } +} + +static void +meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor) +{ +} + +static gboolean +meta_surface_actor_wayland_is_visible (MetaSurfaceActor *actor) +{ + /* TODO: ensure that the buffer isn't NULL, implement + * wayland mapping semantics */ + return TRUE; +} + +static gboolean +meta_surface_actor_wayland_should_unredirect (MetaSurfaceActor *actor) +{ + return FALSE; +} + +static void +meta_surface_actor_wayland_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected) +{ + /* Do nothing. In the future, we'll use KMS to set this + * up as a hardware overlay or something. */ +} + +static gboolean +meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor) +{ + return FALSE; +} + +static MetaWindow * +meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (META_SURFACE_ACTOR_WAYLAND (actor)); + + return priv->surface->window; +} + +static void +meta_surface_actor_wayland_dispose (GObject *object) +{ + MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object); + + meta_surface_actor_wayland_set_buffer (self, NULL); + + G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object); +} + +static void +meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) +{ + MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint; + surface_actor_class->is_visible = meta_surface_actor_wayland_is_visible; + + surface_actor_class->should_unredirect = meta_surface_actor_wayland_should_unredirect; + surface_actor_class->set_unredirected = meta_surface_actor_wayland_set_unredirected; + surface_actor_class->is_unredirected = meta_surface_actor_wayland_is_unredirected; + + surface_actor_class->get_window = meta_surface_actor_wayland_get_window; + + object_class->dispose = meta_surface_actor_wayland_dispose; +} + +static void +meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + priv->buffer_destroy_listener.notify = meta_surface_actor_handle_buffer_destroy; +} + +MetaSurfaceActor * +meta_surface_actor_wayland_new (MetaWaylandSurface *surface) +{ + MetaSurfaceActorWayland *self = g_object_new (META_TYPE_SURFACE_ACTOR_WAYLAND, NULL); + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + + g_assert (meta_is_wayland_compositor ()); + + priv->surface = surface; + + return META_SURFACE_ACTOR (self); +} + +void +meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self, + MetaWaylandBuffer *buffer) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + + if (priv->buffer) + wl_list_remove (&priv->buffer_destroy_listener.link); + + priv->buffer = buffer; + + if (priv->buffer) + { + wl_signal_add (&priv->buffer->destroy_signal, &priv->buffer_destroy_listener); + meta_shaped_texture_set_texture (stex, priv->buffer->texture); + } + else + meta_shaped_texture_set_texture (stex, NULL); +} + +MetaWaylandSurface * +meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self) +{ + MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self); + return priv->surface; +} diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h new file mode 100644 index 000000000..35058ccf2 --- /dev/null +++ b/src/compositor/meta-surface-actor-wayland.h @@ -0,0 +1,66 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef __META_SURFACE_ACTOR_WAYLAND_H__ +#define __META_SURFACE_ACTOR_WAYLAND_H__ + +#include + +#include "meta-surface-actor.h" + +#include "wayland/meta-wayland.h" + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR_WAYLAND (meta_surface_actor_wayland_get_type ()) +#define META_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWayland)) +#define META_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass)) +#define META_IS_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND)) +#define META_IS_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND)) +#define META_SURFACE_ACTOR_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass)) + +typedef struct _MetaSurfaceActorWayland MetaSurfaceActorWayland; +typedef struct _MetaSurfaceActorWaylandClass MetaSurfaceActorWaylandClass; + +struct _MetaSurfaceActorWayland +{ + MetaSurfaceActor parent; +}; + +struct _MetaSurfaceActorWaylandClass +{ + MetaSurfaceActorClass parent_class; +}; + +GType meta_surface_actor_wayland_get_type (void); + +MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface); +MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self); + +void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self, + MetaWaylandBuffer *buffer); + +G_END_DECLS + +#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */ diff --git a/src/compositor/meta-surface-actor-x11.c b/src/compositor/meta-surface-actor-x11.c new file mode 100644 index 000000000..f6c9fb185 --- /dev/null +++ b/src/compositor/meta-surface-actor-x11.c @@ -0,0 +1,459 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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. + * + * Written by: + * Owen Taylor + * Jasper St. Pierre + */ + +#include "config.h" + +#include "meta-surface-actor-x11.h" + +#include +#include + +#include +#include "window-private.h" +#include "meta-shaped-texture-private.h" +#include "meta-cullable.h" + +struct _MetaSurfaceActorX11Private +{ + MetaWindow *window; + + MetaDisplay *display; + + CoglTexture *texture; + Pixmap pixmap; + Damage damage; + + int last_width; + int last_height; + + /* This is used to detect fullscreen windows that need to be unredirected */ + guint full_damage_frames_count; + guint does_full_damage : 1; + + /* Other state... */ + guint received_damage : 1; + guint size_changed : 1; + + guint unredirected : 1; +}; +typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorX11, meta_surface_actor_x11, META_TYPE_SURFACE_ACTOR) + +static void +free_damage (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->damage == None) + return; + + meta_error_trap_push (display); + XDamageDestroy (xdisplay, priv->damage); + priv->damage = None; + meta_error_trap_pop (display); +} + +static void +detach_pixmap (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + + if (priv->pixmap == None) + return; + + /* Get rid of all references to the pixmap before freeing it; it's unclear whether + * you are supposed to be able to free a GLXPixmap after freeing the underlying + * pixmap, but it certainly doesn't work with current DRI/Mesa + */ + meta_shaped_texture_set_texture (stex, NULL); + cogl_flush (); + + meta_error_trap_push (display); + XFreePixmap (xdisplay, priv->pixmap); + priv->pixmap = None; + meta_error_trap_pop (display); + + cogl_object_unref (priv->texture); + priv->texture = NULL; +} + +static void +set_pixmap (MetaSurfaceActorX11 *self, + Pixmap pixmap) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self)); + CoglTexture *texture; + + g_assert (priv->pixmap == None); + priv->pixmap = pixmap; + + texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, NULL)); + + if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) + g_warning ("NOTE: Not using GLX TFP!\n"); + + priv->texture = texture; + meta_shaped_texture_set_texture (stex, texture); +} + +static void +update_pixmap (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->size_changed) + { + detach_pixmap (self); + priv->size_changed = FALSE; + } + + if (priv->pixmap == None) + { + Pixmap new_pixmap; + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + meta_error_trap_push (display); + new_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); + + if (meta_error_trap_pop_with_return (display) != Success) + { + /* Probably a BadMatch if the window isn't viewable; we could + * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync + * to avoid this, but there's no reason to take two round trips + * when one will do. (We need that Sync if we want to handle failures + * for any reason other than !viewable. That's unlikely, but maybe + * we'll BadAlloc or something.) + */ + new_pixmap = None; + } + + if (new_pixmap == None) + { + meta_verbose ("Unable to get named pixmap for %s\n", + meta_window_get_description (priv->window)); + return; + } + + set_pixmap (self, new_pixmap); + } +} + +static gboolean +is_visible (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + return (priv->pixmap != None) && !priv->unredirected; +} + +static void +damage_area (MetaSurfaceActorX11 *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (!is_visible (self)) + return; + + cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height); + meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height); +} + +static void +meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + priv->received_damage = TRUE; + + if (meta_window_is_fullscreen (priv->window) && !priv->unredirected && !priv->does_full_damage) + { + MetaRectangle window_rect; + meta_window_get_frame_rect (priv->window, &window_rect); + + if (window_rect.x == x && + window_rect.y == y && + window_rect.width == width && + window_rect.height == height) + priv->full_damage_frames_count++; + else + priv->full_damage_frames_count = 0; + + if (priv->full_damage_frames_count >= 100) + priv->does_full_damage = TRUE; + } + + /* Drop damage event for unredirected windows */ + if (priv->unredirected) + return; + + damage_area (self, x, y, width, height); +} + +static void +meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + + if (priv->received_damage) + { + meta_error_trap_push (display); + XDamageSubtract (xdisplay, priv->damage, None, None); + meta_error_trap_pop (display); + + /* We need to make sure that any X drawing that happens before the + * XDamageSubtract() above is visible to subsequent GL rendering; + * the only standardized way to do this is EXT_x11_sync_object, + * which isn't yet widely available. For now, we count on details + * of Xorg and the open source drivers, and hope for the best + * otherwise. + * + * Xorg and open source driver specifics: + * + * The X server makes sure to flush drawing to the kernel before + * sending out damage events, but since we use DamageReportBoundingBox + * there may be drawing between the last damage event and the + * XDamageSubtract() that needs to be flushed as well. + * + * Xorg always makes sure that drawing is flushed to the kernel + * before writing events or responses to the client, so any round trip + * request at this point is sufficient to flush the GLX buffers. + */ + XSync (xdisplay, False); + + priv->received_damage = FALSE; + } + + update_pixmap (self); +} + +static gboolean +meta_surface_actor_x11_is_visible (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + return is_visible (self); +} + +static gboolean +meta_surface_actor_x11_should_unredirect (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + MetaWindow *window = priv->window; + + if (meta_window_requested_dont_bypass_compositor (window)) + return FALSE; + + if (window->opacity != 0xFF) + return FALSE; + + if (window->shape_region != NULL) + return FALSE; + + if (meta_surface_actor_is_argb32 (actor) && !meta_window_requested_bypass_compositor (window)) + return FALSE; + + if (!meta_window_is_monitor_sized (window)) + return FALSE; + + if (meta_window_requested_bypass_compositor (window)) + return TRUE; + + if (meta_window_is_override_redirect (window)) + return TRUE; + + if (priv->does_full_damage) + return TRUE; + + return FALSE; +} + +static void +sync_unredirected (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = priv->display; + Display *xdisplay = meta_display_get_xdisplay (display); + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + meta_error_trap_push (display); + + if (priv->unredirected) + { + detach_pixmap (self); + XCompositeUnredirectWindow (xdisplay, xwindow, CompositeRedirectManual); + } + else + { + XCompositeRedirectWindow (xdisplay, xwindow, CompositeRedirectManual); + } + + meta_error_trap_pop (display); +} + +static void +meta_surface_actor_x11_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (priv->unredirected == unredirected) + return; + + priv->unredirected = unredirected; + sync_unredirected (self); +} + +static gboolean +meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + return priv->unredirected; +} + +static void +meta_surface_actor_x11_dispose (GObject *object) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object); + + detach_pixmap (self); + free_damage (self); + + G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object); +} + +static MetaWindow * +meta_surface_actor_x11_get_window (MetaSurfaceActor *actor) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (META_SURFACE_ACTOR_X11 (actor)); + + return priv->window; +} + +static void +meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_x11_dispose; + + surface_actor_class->process_damage = meta_surface_actor_x11_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_x11_pre_paint; + surface_actor_class->is_visible = meta_surface_actor_x11_is_visible; + + surface_actor_class->should_unredirect = meta_surface_actor_x11_should_unredirect; + surface_actor_class->set_unredirected = meta_surface_actor_x11_set_unredirected; + surface_actor_class->is_unredirected = meta_surface_actor_x11_is_unredirected; + + surface_actor_class->get_window = meta_surface_actor_x11_get_window; +} + +static void +meta_surface_actor_x11_init (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + priv->last_width = -1; + priv->last_height = -1; +} + +static void +create_damage (MetaSurfaceActorX11 *self) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + Display *xdisplay = meta_display_get_xdisplay (priv->display); + Window xwindow = meta_window_get_toplevel_xwindow (priv->window); + + priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox); +} + +static void +window_decorated_notify (MetaWindow *window, + GParamSpec *pspec, + gpointer user_data) +{ + MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data); + + free_damage (self); + create_damage (self); +} + +MetaSurfaceActor * +meta_surface_actor_x11_new (MetaWindow *window) +{ + MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL); + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + MetaDisplay *display = meta_window_get_display (window); + + g_assert (!meta_is_wayland_compositor ()); + + priv->window = window; + priv->display = display; + + create_damage (self); + g_signal_connect_object (priv->window, "notify::decorated", + G_CALLBACK (window_decorated_notify), self, 0); + + priv->unredirected = FALSE; + sync_unredirected (self); + + clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); + return META_SURFACE_ACTOR (self); +} + +void +meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height) +{ + MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self); + + if (priv->last_width == width && + priv->last_height == height) + return; + + priv->size_changed = TRUE; + priv->last_width = width; + priv->last_height = height; +} diff --git a/src/compositor/meta-surface-actor-x11.h b/src/compositor/meta-surface-actor-x11.h new file mode 100644 index 000000000..0e692ee0f --- /dev/null +++ b/src/compositor/meta-surface-actor-x11.h @@ -0,0 +1,69 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2013 Red Hat + * + * 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. + * + * Written by: + * Owen Taylor + * Jasper St. Pierre + */ + +#ifndef __META_SURFACE_ACTOR_X11_H__ +#define __META_SURFACE_ACTOR_X11_H__ + +#include + +#include "meta-surface-actor.h" + +#include + +#include +#include + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR_X11 (meta_surface_actor_x11_get_type ()) +#define META_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11)) +#define META_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class)) +#define META_IS_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_X11)) +#define META_IS_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_X11)) +#define META_SURFACE_ACTOR_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class)) + +typedef struct _MetaSurfaceActorX11 MetaSurfaceActorX11; +typedef struct _MetaSurfaceActorX11Class MetaSurfaceActorX11Class; + +struct _MetaSurfaceActorX11 +{ + MetaSurfaceActor parent; +}; + +struct _MetaSurfaceActorX11Class +{ + MetaSurfaceActorClass parent_class; +}; + +GType meta_surface_actor_x11_get_type (void); + +MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window); + +void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self, + int width, int height); + +G_END_DECLS + +#endif /* __META_SURFACE_ACTOR_X11_H__ */ diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c new file mode 100644 index 000000000..3e7db6b20 --- /dev/null +++ b/src/compositor/meta-surface-actor.c @@ -0,0 +1,338 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * SECTION:meta-surface-actor + * @title: MetaSurfaceActor + * @short_description: An actor representing a surface in the scene graph + * + * A surface can be either a shaped texture, or a group of shaped texture, + * used to draw the content of a window. + */ + +#include + +#include "meta-surface-actor.h" + +#include +#include +#include "meta-cullable.h" +#include "meta-shaped-texture-private.h" + +struct _MetaSurfaceActorPrivate +{ + MetaShapedTexture *texture; + + cairo_region_t *input_region; + + /* Freeze/thaw accounting */ + guint needs_damage_all : 1; + guint frozen : 1; +}; + +static void cullable_iface_init (MetaCullableInterface *iface); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR, + G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); + +enum { + REPAINT_SCHEDULED, + + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL]; + +gboolean +meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, + cairo_rectangle_int_t *unobscured_bounds) +{ + MetaSurfaceActorPrivate *priv = self->priv; + return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds); +} + +static void +meta_surface_actor_pick (ClutterActor *actor, + const ClutterColor *color) +{ + MetaSurfaceActor *self = META_SURFACE_ACTOR (actor); + MetaSurfaceActorPrivate *priv = self->priv; + + if (!clutter_actor_should_pick_paint (actor)) + return; + + /* If there is no region then use the regular pick */ + if (priv->input_region == NULL) + CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->pick (actor, color); + else + { + int n_rects; + float *rectangles; + int i; + CoglPipeline *pipeline; + CoglContext *ctx; + CoglFramebuffer *fb; + CoglColor cogl_color; + + n_rects = cairo_region_num_rectangles (priv->input_region); + rectangles = g_alloca (sizeof (float) * 4 * n_rects); + + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + int pos = i * 4; + + cairo_region_get_rectangle (priv->input_region, i, &rect); + + rectangles[pos + 0] = rect.x; + rectangles[pos + 1] = rect.y; + rectangles[pos + 2] = rect.x + rect.width; + rectangles[pos + 3] = rect.y + rect.height; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + fb = cogl_get_draw_framebuffer (); + + cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); + + pipeline = cogl_pipeline_new (ctx); + cogl_pipeline_set_color (pipeline, &cogl_color); + cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects); + cogl_object_unref (pipeline); + } +} + +static void +meta_surface_actor_dispose (GObject *object) +{ + MetaSurfaceActor *self = META_SURFACE_ACTOR (object); + MetaSurfaceActorPrivate *priv = self->priv; + + g_clear_pointer (&priv->input_region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); +} + +static void +meta_surface_actor_class_init (MetaSurfaceActorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_dispose; + actor_class->pick = meta_surface_actor_pick; + + signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate)); +} + +static void +meta_surface_actor_cull_out (MetaCullable *cullable, + cairo_region_t *unobscured_region, + cairo_region_t *clip_region) +{ + meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); +} + +static void +meta_surface_actor_reset_culling (MetaCullable *cullable) +{ + meta_cullable_reset_culling_children (cullable); +} + +static void +cullable_iface_init (MetaCullableInterface *iface) +{ + iface->cull_out = meta_surface_actor_cull_out; + iface->reset_culling = meta_surface_actor_reset_culling; +} + +static void +meta_surface_actor_init (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv; + + priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + META_TYPE_SURFACE_ACTOR, + MetaSurfaceActorPrivate); + + priv->texture = META_SHAPED_TEXTURE (meta_shaped_texture_new ()); + clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->texture)); +} + +cairo_surface_t * +meta_surface_actor_get_image (MetaSurfaceActor *self, + cairo_rectangle_int_t *clip) +{ + return meta_shaped_texture_get_image (self->priv->texture, clip); +} + +MetaShapedTexture * +meta_surface_actor_get_texture (MetaSurfaceActor *self) +{ + return self->priv->texture; +} + +void +meta_surface_actor_update_area (MetaSurfaceActor *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (meta_shaped_texture_update_area (priv->texture, x, y, width, height)) + g_signal_emit (self, signals[REPAINT_SCHEDULED], 0); +} + +gboolean +meta_surface_actor_is_obscured (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv = self->priv; + return meta_shaped_texture_is_obscured (priv->texture); +} + +void +meta_surface_actor_set_input_region (MetaSurfaceActor *self, + cairo_region_t *region) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (priv->input_region) + cairo_region_destroy (priv->input_region); + + if (region) + priv->input_region = cairo_region_reference (region); + else + priv->input_region = NULL; +} + +void +meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, + cairo_region_t *region) +{ + MetaSurfaceActorPrivate *priv = self->priv; + meta_shaped_texture_set_opaque_region (priv->texture, region); +} + +static gboolean +is_frozen (MetaSurfaceActor *self) +{ + MetaSurfaceActorPrivate *priv = self->priv; + return priv->frozen; +} + +void +meta_surface_actor_process_damage (MetaSurfaceActor *self, + int x, int y, int width, int height) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + if (is_frozen (self)) + { + /* The window is frozen due to an effect in progress: we ignore damage + * here on the off chance that this will stop the corresponding + * texture_from_pixmap from being update. + * + * needs_damage_all tracks that some unknown damage happened while the + * window was frozen so that when the window becomes unfrozen we can + * issue a full window update to cover any lost damage. + * + * It should be noted that this is an unreliable mechanism since it's + * quite likely that drivers will aim to provide a zero-copy + * implementation of the texture_from_pixmap extension and in those cases + * any drawing done to the window is always immediately reflected in the + * texture regardless of damage event handling. + */ + priv->needs_damage_all = TRUE; + return; + } + + META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height); +} + +void +meta_surface_actor_pre_paint (MetaSurfaceActor *self) +{ + META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self); +} + +gboolean +meta_surface_actor_is_argb32 (MetaSurfaceActor *self) +{ + MetaShapedTexture *stex = meta_surface_actor_get_texture (self); + CoglTexture *texture = meta_shaped_texture_get_texture (stex); + + /* If we don't have a texture, like during initialization, assume + * that we're ARGB32. */ + if (!texture) + return TRUE; + + switch (cogl_texture_get_components (texture)) + { + case COGL_TEXTURE_COMPONENTS_A: + case COGL_TEXTURE_COMPONENTS_RGBA: + return TRUE; + case COGL_TEXTURE_COMPONENTS_RG: + case COGL_TEXTURE_COMPONENTS_RGB: + case COGL_TEXTURE_COMPONENTS_DEPTH: + return FALSE; + default: + g_assert_not_reached (); + } +} + +gboolean +meta_surface_actor_is_visible (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self); +} + +void +meta_surface_actor_set_frozen (MetaSurfaceActor *self, + gboolean frozen) +{ + MetaSurfaceActorPrivate *priv = self->priv; + + priv->frozen = frozen; + + if (!frozen && priv->needs_damage_all) + { + /* Since we ignore damage events while a window is frozen for certain effects + * we may need to issue an update_area() covering the whole pixmap if we + * don't know what real damage has happened. */ + + meta_surface_actor_process_damage (self, 0, 0, + clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)), + clutter_actor_get_height (CLUTTER_ACTOR (priv->texture))); + priv->needs_damage_all = FALSE; + } +} + +gboolean +meta_surface_actor_should_unredirect (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self); +} + +void +meta_surface_actor_set_unredirected (MetaSurfaceActor *self, + gboolean unredirected) +{ + META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected); +} + +gboolean +meta_surface_actor_is_unredirected (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self); +} + +MetaWindow * +meta_surface_actor_get_window (MetaSurfaceActor *self) +{ + return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self); +} diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h new file mode 100644 index 000000000..3991d5297 --- /dev/null +++ b/src/compositor/meta-surface-actor.h @@ -0,0 +1,85 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#ifndef META_SURFACE_ACTOR_PRIVATE_H +#define META_SURFACE_ACTOR_PRIVATE_H + +#include + +#include +#include + +G_BEGIN_DECLS + +#define META_TYPE_SURFACE_ACTOR (meta_surface_actor_get_type()) +#define META_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActor)) +#define META_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass)) +#define META_IS_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR)) +#define META_IS_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR)) +#define META_SURFACE_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass)) + +typedef struct _MetaSurfaceActor MetaSurfaceActor; +typedef struct _MetaSurfaceActorClass MetaSurfaceActorClass; +typedef struct _MetaSurfaceActorPrivate MetaSurfaceActorPrivate; + +struct _MetaSurfaceActorClass +{ + /*< private >*/ + ClutterActorClass parent_class; + + void (* process_damage) (MetaSurfaceActor *actor, + int x, int y, int width, int height); + void (* pre_paint) (MetaSurfaceActor *actor); + gboolean (* is_visible) (MetaSurfaceActor *actor); + + gboolean (* should_unredirect) (MetaSurfaceActor *actor); + void (* set_unredirected) (MetaSurfaceActor *actor, + gboolean unredirected); + gboolean (* is_unredirected) (MetaSurfaceActor *actor); + + MetaWindow *(* get_window) (MetaSurfaceActor *actor); +}; + +struct _MetaSurfaceActor +{ + ClutterActor parent; + + MetaSurfaceActorPrivate *priv; +}; + +GType meta_surface_actor_get_type (void); + +cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self, + cairo_rectangle_int_t *clip); + +MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self); +MetaWindow *meta_surface_actor_get_window (MetaSurfaceActor *self); + +gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self); +gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, + cairo_rectangle_int_t *unobscured_bounds); + +void meta_surface_actor_set_input_region (MetaSurfaceActor *self, + cairo_region_t *region); +void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, + cairo_region_t *region); + +void meta_surface_actor_update_area (MetaSurfaceActor *actor, + int x, int y, int width, int height); + +void meta_surface_actor_process_damage (MetaSurfaceActor *actor, + int x, int y, int width, int height); +void meta_surface_actor_pre_paint (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor); +gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor); + +void meta_surface_actor_set_frozen (MetaSurfaceActor *actor, + gboolean frozen); + +gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor); +void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor, + gboolean unredirected); +gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor); + +G_END_DECLS + +#endif /* META_SURFACE_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h index 75a19e1a3..2d2785055 100644 --- a/src/compositor/meta-window-actor-private.h +++ b/src/compositor/meta-window-actor-private.h @@ -7,6 +7,7 @@ #include #include +#include "meta-surface-actor.h" MetaWindowActor *meta_window_actor_new (MetaWindow *window); @@ -24,8 +25,8 @@ void meta_window_actor_unmaximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect); -void meta_window_actor_process_damage (MetaWindowActor *self, - XDamageNotifyEvent *event); +void meta_window_actor_process_x11_damage (MetaWindowActor *self, + XDamageNotifyEvent *event); void meta_window_actor_pre_paint (MetaWindowActor *self); void meta_window_actor_post_paint (MetaWindowActor *self); @@ -58,4 +59,7 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, void meta_window_actor_effect_completed (MetaWindowActor *actor, gulong event); +MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self); +void meta_window_actor_update_surface (MetaWindowActor *self); + #endif /* META_WINDOW_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index b63358f41..ae5a276ed 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -10,10 +10,6 @@ #include -#include -#include -#include - #include #include #include /* for gdk_rectangle_union() */ @@ -24,7 +20,6 @@ #include "frame.h" #include #include -#include "xprops.h" #include "compositor-private.h" #include "meta-shaped-texture-private.h" @@ -32,15 +27,20 @@ #include "meta-window-actor-private.h" #include "meta-texture-rectangle.h" #include "region-utils.h" -#include "monitor-private.h" +#include "meta-monitor-manager.h" #include "meta-cullable.h" +#include "meta-surface-actor.h" +#include "meta-surface-actor-x11.h" + +#include "wayland/meta-wayland-surface.h" + struct _MetaWindowActorPrivate { - MetaWindow *window; - MetaScreen *screen; + MetaWindow *window; + MetaCompositor *compositor; - ClutterActor *actor; + MetaSurfaceActor *surface; /* MetaShadowFactory only caches shadows that are actually in use; * to avoid unnecessary recomputation we do two things: 1) we store @@ -56,10 +56,6 @@ struct _MetaWindowActorPrivate MetaShadow *focused_shadow; MetaShadow *unfocused_shadow; - Pixmap back_pixmap; - - Damage damage; - /* A region that matches the shape of the window, including frame bounds */ cairo_region_t *shape_region; /* The region we should clip to when painting the shadow */ @@ -72,10 +68,8 @@ struct _MetaWindowActorPrivate guint send_frame_messages_timer; gint64 frame_drawn_time; - gint last_width; - gint last_height; - - gint freeze_count; + guint repaint_scheduled_id; + guint allocation_changed_id; /* * These need to be counters rather than flags, since more plugins @@ -90,36 +84,25 @@ struct _MetaWindowActorPrivate /* List of FrameData for recent frames */ GList *frames; + guint freeze_count; guint visible : 1; - guint argb32 : 1; guint disposed : 1; - guint redecorating : 1; - - guint needs_damage_all : 1; - guint received_damage : 1; - guint repaint_scheduled : 1; /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN * client message using the most recent frame in ->frames */ guint needs_frame_drawn : 1; + guint repaint_scheduled : 1; - guint needs_pixmap : 1; guint needs_reshape : 1; guint recompute_focused_shadow : 1; guint recompute_unfocused_shadow : 1; - guint size_changed : 1; - guint updates_frozen : 1; guint needs_destroy : 1; guint no_shadow : 1; - guint unredirected : 1; - - /* This is used to detect fullscreen windows that need to be unredirected */ - guint full_damage_frames_count; - guint does_full_damage : 1; + guint updates_frozen : 1; }; typedef struct _FrameData FrameData; @@ -156,7 +139,6 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume); -static void meta_window_actor_detach (MetaWindowActor *self); static gboolean meta_window_actor_has_shadow (MetaWindowActor *self); static void meta_window_actor_handle_updates (MetaWindowActor *self); @@ -240,43 +222,6 @@ meta_window_actor_init (MetaWindowActor *self) priv->shadow_class = NULL; } -static void -window_decorated_notify (MetaWindow *mw, - GParamSpec *arg1, - gpointer data) -{ - MetaWindowActor *self = META_WINDOW_ACTOR (data); - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - - /* - * Basically, we have to reconstruct the the internals of this object - * from scratch, as everything has changed. - */ - priv->redecorating = TRUE; - - meta_window_actor_detach (self); - - /* - * First of all, clean up any resources we are currently using and will - * be replacing. - */ - if (priv->damage != None) - { - meta_error_trap_push (display); - XDamageDestroy (xdisplay, priv->damage); - meta_error_trap_pop (display); - priv->damage = None; - } - - /* - * Recreate the contents. - */ - meta_window_actor_constructed (G_OBJECT (self)); -} - static void window_appears_focused_notify (MetaWindow *mw, GParamSpec *arg1, @@ -285,53 +230,154 @@ window_appears_focused_notify (MetaWindow *mw, clutter_actor_queue_redraw (CLUTTER_ACTOR (data)); } +static void +surface_allocation_changed_notify (ClutterActor *actor, + const ClutterActorBox *allocation, + ClutterAllocationFlags flags, + MetaWindowActor *self) +{ + meta_window_actor_sync_actor_geometry (self, FALSE); + meta_window_actor_update_shape (self); +} + +static void +surface_repaint_scheduled (MetaSurfaceActor *actor, + gpointer user_data) +{ + MetaWindowActor *self = META_WINDOW_ACTOR (user_data); + MetaWindowActorPrivate *priv = self->priv; + + priv->repaint_scheduled = TRUE; +} + +static gboolean +is_argb32 (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + /* assume we're argb until we get the window (because + in practice we're drawing nothing, so we're fully + transparent) + */ + if (priv->surface) + return meta_surface_actor_is_argb32 (priv->surface); + else + return TRUE; +} + static gboolean is_non_opaque (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - return priv->argb32 || (window->opacity != 0xFF); + return is_argb32 (self) || (window->opacity != 0xFF); +} + +static gboolean +is_frozen (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + return priv->surface == NULL || priv->freeze_count > 0; +} + +static void +meta_window_actor_freeze (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + if (priv->freeze_count == 0 && priv->surface) + meta_surface_actor_set_frozen (priv->surface, TRUE); + + priv->freeze_count ++; +} + +static void +meta_window_actor_thaw (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + if (priv->freeze_count <= 0) + g_error ("Error in freeze/thaw accounting"); + + priv->freeze_count--; + if (priv->freeze_count > 0) + return; + + if (priv->surface) + meta_surface_actor_set_frozen (priv->surface, FALSE); + + /* We sometimes ignore moves and resizes on frozen windows */ + meta_window_actor_sync_actor_geometry (self, FALSE); + + /* We do this now since we might be going right back into the + * frozen state */ + meta_window_actor_handle_updates (self); +} + +static void +set_surface (MetaWindowActor *self, + MetaSurfaceActor *surface) +{ + MetaWindowActorPrivate *priv = self->priv; + + if (priv->surface) + { + g_signal_handler_disconnect (priv->surface, priv->repaint_scheduled_id); + priv->repaint_scheduled_id = 0; + g_signal_handler_disconnect (priv->surface, priv->allocation_changed_id); + priv->allocation_changed_id = 0; + clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); + g_object_unref (priv->surface); + } + + priv->surface = surface; + + if (priv->surface) + { + g_object_ref_sink (priv->surface); + priv->repaint_scheduled_id = g_signal_connect (priv->surface, "repaint-scheduled", + G_CALLBACK (surface_repaint_scheduled), self); + priv->allocation_changed_id = g_signal_connect (priv->surface, "allocation-changed", + G_CALLBACK (surface_allocation_changed_notify), self); + clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); + + /* If the previous surface actor was frozen, start out + * frozen as well... */ + meta_surface_actor_set_frozen (priv->surface, priv->freeze_count > 0); + + meta_window_actor_update_shape (self); + } +} + +void +meta_window_actor_update_surface (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + MetaWindow *window = priv->window; + MetaSurfaceActor *surface_actor; + + if (window->surface) + surface_actor = window->surface->surface_actor; + else if (!meta_is_wayland_compositor ()) + surface_actor = meta_surface_actor_x11_new (window); + else + surface_actor = NULL; + + set_surface (self, surface_actor); } static void meta_window_actor_constructed (GObject *object) { - MetaWindowActor *self = META_WINDOW_ACTOR (object); - MetaWindowActorPrivate *priv = self->priv; - MetaWindow *window = priv->window; - MetaScreen *screen = meta_window_get_screen (window); - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - XRenderPictFormat *format; - Window xwindow; + MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActorPrivate *priv = self->priv; + MetaWindow *window = priv->window; - xwindow = meta_window_get_toplevel_xwindow (window); + priv->compositor = window->display->compositor; - priv->screen = screen; - priv->damage = XDamageCreate (xdisplay, xwindow, - XDamageReportBoundingBox); - - format = XRenderFindVisualFormat (xdisplay, window->xvisual); - - if (format && format->type == PictTypeDirect && format->direct.alphaMask) - priv->argb32 = TRUE; - - if (!priv->actor) - { - priv->actor = meta_shaped_texture_new (); - - clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor); - - /* - * Since we are holding a pointer to this actor independently of the - * ClutterContainer internals, and provide a public API to access it, - * add a reference here, so that if someone is messing about with us - * via the container interface, we do not end up with a dangling pointer. - * We will release it in dispose(). - */ - g_object_ref (priv->actor); - } + meta_window_actor_update_surface (self); meta_window_actor_update_opacity (self); @@ -343,25 +389,15 @@ meta_window_actor_constructed (GObject *object) static void meta_window_actor_dispose (GObject *object) { - MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActor *self = META_WINDOW_ACTOR (object); MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen; - MetaDisplay *display; - Display *xdisplay; - MetaCompScreen *info; + MetaCompositor *compositor = priv->compositor; if (priv->disposed) return; priv->disposed = TRUE; - screen = priv->screen; - display = meta_screen_get_display (screen); - xdisplay = meta_display_get_xdisplay (display); - info = meta_screen_get_compositor_data (screen); - - meta_window_actor_detach (self); - if (priv->send_frame_messages_timer != 0) { g_source_remove (priv->send_frame_messages_timer); @@ -376,23 +412,11 @@ meta_window_actor_dispose (GObject *object) g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref); g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); - if (priv->damage != None) - { - meta_error_trap_push (display); - XDamageDestroy (xdisplay, priv->damage); - meta_error_trap_pop (display); - - priv->damage = None; - } - - info->windows = g_list_remove (info->windows, (gconstpointer) self); + compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self); g_clear_object (&priv->window); - /* - * Release the extra reference we took on the actor. - */ - g_clear_object (&priv->actor); + set_surface (self, NULL); G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); } @@ -421,9 +445,6 @@ meta_window_actor_set_property (GObject *object, { case PROP_META_WINDOW: priv->window = g_value_dup_object (value); - - g_signal_connect_object (priv->window, "notify::decorated", - G_CALLBACK (window_decorated_notify), self, 0); g_signal_connect_object (priv->window, "notify::appears-focused", G_CALLBACK (window_appears_focused_notify), self, 0); break; @@ -645,8 +666,11 @@ meta_window_actor_get_paint_volume (ClutterActor *actor, meta_window_actor_get_shape_bounds (self, &bounds); - if (meta_shaped_texture_get_unobscured_bounds (META_SHAPED_TEXTURE (priv->actor), &unobscured_bounds)) - gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds); + if (priv->surface) + { + if (meta_surface_actor_get_unobscured_bounds (priv->surface, &unobscured_bounds)) + gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds); + } if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow) { @@ -678,7 +702,6 @@ static gboolean meta_window_actor_has_shadow (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaWindowType window_type = meta_window_get_window_type (priv->window); if (priv->no_shadow) return FALSE; @@ -717,25 +740,6 @@ meta_window_actor_has_shadow (MetaWindowActor *self) if (priv->window->override_redirect) return TRUE; - /* - * Don't put shadow around DND icon windows - */ - if (window_type == META_WINDOW_DND || - window_type == META_WINDOW_DESKTOP) - return FALSE; - - if (window_type == META_WINDOW_MENU -#if 0 - || window_type == META_WINDOW_DROPDOWN_MENU -#endif - ) - return TRUE; - -#if 0 - if (window_type == META_WINDOW_TOOLTIP) - return TRUE; -#endif - return FALSE; } @@ -757,14 +761,33 @@ meta_window_actor_get_meta_window (MetaWindowActor *self) * meta_window_actor_get_texture: * @self: a #MetaWindowActor * - * Gets the ClutterActor that is used to display the contents of the window + * Gets the ClutterActor that is used to display the contents of the window, + * or NULL if no texture is shown yet, because the window is not mapped. * * Return value: (transfer none): the #ClutterActor for the contents */ ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self) { - return self->priv->actor; + if (self->priv->surface) + return CLUTTER_ACTOR (meta_surface_actor_get_texture (self->priv->surface)); + else + return NULL; +} + +/** + * meta_window_actor_get_surface: + * @self: a #MetaWindowActor + * + * Gets the MetaSurfaceActor that draws the content of this window, + * or NULL if there is no surface yet associated with this window. + * + * Return value: (transfer none): the #MetaSurfaceActor for the contents + */ +MetaSurfaceActor * +meta_window_actor_get_surface (MetaWindowActor *self) +{ + return self->priv->surface; } /** @@ -781,14 +804,8 @@ meta_window_actor_is_destroyed (MetaWindowActor *self) return self->priv->disposed; } -static void -meta_window_actor_freeze (MetaWindowActor *self) -{ - self->priv->freeze_count++; -} - -static -gboolean send_frame_messages_timeout (gpointer data) +static gboolean +send_frame_messages_timeout (gpointer data) { MetaWindowActor *self = (MetaWindowActor *) data; MetaWindowActorPrivate *priv = self->priv; @@ -810,8 +827,7 @@ static void queue_send_frame_messages_timeout (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); + MetaDisplay *display = meta_window_get_display (priv->window); gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ()); MetaMonitorManager *monitor_manager = meta_monitor_manager_get (); MetaWindow *window = priv->window; @@ -841,72 +857,6 @@ queue_send_frame_messages_timeout (MetaWindowActor *self) priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL); } -static void -update_area (MetaWindowActor *self, - int x, int y, int width, int height) -{ - MetaWindowActorPrivate *priv = self->priv; - CoglTexture *texture; - - texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); - - cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (texture), - x, y, width, height); -} - -static void -meta_window_actor_damage_all (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - CoglTexture *texture; - gboolean redraw_queued; - - if (!priv->needs_damage_all) - return; - - texture = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); - - if (priv->needs_pixmap) - return; - - update_area (self, 0, 0, cogl_texture_get_width (texture), cogl_texture_get_height (texture)); - redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), - 0, 0, - cogl_texture_get_width (texture), - cogl_texture_get_height (texture)); - priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued; - priv->needs_damage_all = FALSE; -} - -static void -meta_window_actor_thaw (MetaWindowActor *self) -{ - self->priv->freeze_count--; - - if (G_UNLIKELY (self->priv->freeze_count < 0)) - { - g_warning ("Error in freeze/thaw accounting."); - self->priv->freeze_count = 0; - return; - } - - if (self->priv->freeze_count) - return; - - /* We sometimes ignore moves and resizes on frozen windows */ - meta_window_actor_sync_actor_geometry (self, FALSE); - - /* We do this now since we might be going right back into the - * frozen state */ - meta_window_actor_handle_updates (self); - - /* Since we ignore damage events while a window is frozen for certain effects - * we may need to issue an update_area() covering the whole pixmap if we - * don't know what real damage has happened. */ - if (self->priv->needs_damage_all) - meta_window_actor_damage_all (self); -} - void meta_window_actor_queue_frame_drawn (MetaWindowActor *self, gboolean no_delay_frame) @@ -928,7 +878,12 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self, if (!priv->repaint_scheduled) { - gboolean is_obscured = meta_shaped_texture_is_obscured (META_SHAPED_TEXTURE (priv->actor)); + gboolean is_obscured; + + if (priv->surface) + is_obscured = meta_surface_actor_is_obscured (priv->surface); + else + is_obscured = FALSE; /* A frame was marked by the client without actually doing any * damage or any unobscured, or while we had the window frozen @@ -944,9 +899,12 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self, } else { - const cairo_rectangle_int_t clip = { 0, 0, 1, 1 }; - clutter_actor_queue_redraw_with_clip (priv->actor, &clip); - priv->repaint_scheduled = TRUE; + if (priv->surface) + { + const cairo_rectangle_int_t clip = { 0, 0, 1, 1 }; + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip); + priv->repaint_scheduled = TRUE; + } } } } @@ -961,12 +919,6 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self) self->priv->destroy_in_progress); } -static gboolean -is_frozen (MetaWindowActor *self) -{ - return self->priv->freeze_count ? TRUE : FALSE; -} - static gboolean is_freeze_thaw_effect (gulong event) { @@ -987,13 +939,10 @@ start_simple_effect (MetaWindowActor *self, gulong event) { MetaWindowActorPrivate *priv = self->priv; - MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen); + MetaCompositor *compositor = priv->compositor; gint *counter = NULL; gboolean use_freeze_thaw = FALSE; - if (!info->plugin_mgr) - return FALSE; - switch (event) { case META_PLUGIN_MINIMIZE: @@ -1021,9 +970,7 @@ start_simple_effect (MetaWindowActor *self, (*counter)++; - if (!meta_plugin_manager_event_simple (info->plugin_mgr, - self, - event)) + if (!meta_plugin_manager_event_simple (compositor->plugin_mgr, self, event)) { (*counter)--; if (use_freeze_thaw) @@ -1047,9 +994,6 @@ meta_window_actor_after_effects (MetaWindowActor *self) meta_window_actor_sync_visibility (self); meta_window_actor_sync_actor_geometry (self, FALSE); - - if (priv->needs_pixmap) - clutter_actor_queue_redraw (priv->actor); } void @@ -1124,106 +1068,34 @@ meta_window_actor_effect_completed (MetaWindowActor *self, meta_window_actor_after_effects (self); } -/* Called to drop our reference to a window backing pixmap that we - * previously obtained with XCompositeNameWindowPixmap. We do this - * when the window is unmapped or when we want to update to a new - * pixmap for a new size. - */ -static void -meta_window_actor_detach (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - - if (!priv->back_pixmap) - return; - - /* Get rid of all references to the pixmap before freeing it; it's unclear whether - * you are supposed to be able to free a GLXPixmap after freeing the underlying - * pixmap, but it certainly doesn't work with current DRI/Mesa - */ - meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL); - cogl_flush(); - - XFreePixmap (xdisplay, priv->back_pixmap); - priv->back_pixmap = None; - - priv->needs_pixmap = TRUE; -} - gboolean meta_window_actor_should_unredirect (MetaWindowActor *self) { - MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); MetaWindowActorPrivate *priv = self->priv; - - if (meta_window_requested_dont_bypass_compositor (metaWindow)) + if (priv->surface) + return meta_surface_actor_should_unredirect (priv->surface); + else return FALSE; - - if (metaWindow->opacity != 0xFF) - return FALSE; - - if (metaWindow->shape_region != NULL) - return FALSE; - - if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow)) - return FALSE; - - if (!meta_window_is_monitor_sized (metaWindow)) - return FALSE; - - if (meta_window_requested_bypass_compositor (metaWindow)) - return TRUE; - - if (meta_window_is_override_redirect (metaWindow)) - return TRUE; - - if (priv->does_full_damage) - return TRUE; - - return FALSE; } void meta_window_actor_set_unredirected (MetaWindowActor *self, gboolean unredirected) { - MetaWindow *metaWindow = meta_window_actor_get_meta_window (self); - MetaDisplay *display = meta_window_get_display (metaWindow); + MetaWindowActorPrivate *priv = self->priv; - Display *xdisplay = meta_display_get_xdisplay (display); - Window xwin = meta_window_get_toplevel_xwindow (metaWindow); - - meta_error_trap_push (display); - - if (unredirected) - { - XCompositeUnredirectWindow (xdisplay, xwin, CompositeRedirectManual); - } - else - { - XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual); - meta_window_actor_detach (self); - } - - self->priv->unredirected = unredirected; - meta_error_trap_pop (display); + g_assert(priv->surface); /* because otherwise should_unredirect() is FALSE */ + meta_surface_actor_set_unredirected (priv->surface, unredirected); } void meta_window_actor_destroy (MetaWindowActor *self) { - MetaWindow *window; - MetaCompScreen *info; - MetaWindowActorPrivate *priv; - MetaWindowType window_type; + MetaWindowActorPrivate *priv = self->priv; + MetaWindow *window = priv->window; + MetaCompositor *compositor = priv->compositor; + MetaWindowType window_type = meta_window_get_window_type (window); - priv = self->priv; - - window = priv->window; - window_type = meta_window_get_window_type (window); meta_window_set_compositor_private (window, NULL); if (priv->send_frame_messages_timer != 0) @@ -1236,8 +1108,7 @@ meta_window_actor_destroy (MetaWindowActor *self) * We remove the window from internal lookup hashes and thus any other * unmap events etc fail */ - info = meta_screen_get_compositor_data (priv->screen); - info->windows = g_list_remove (info->windows, (gconstpointer) self); + compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self); if (window_type == META_WINDOW_DROPDOWN_MENU || window_type == META_WINDOW_POPUP_MENU || @@ -1269,13 +1140,11 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, meta_window_get_input_rect (priv->window, &window_rect); - if (priv->last_width != window_rect.width || - priv->last_height != window_rect.height) - { - priv->size_changed = TRUE; - priv->last_width = window_rect.width; - priv->last_height = window_rect.height; - } + /* When running as a Wayland compositor we catch size changes when new + * buffers are attached */ + if (META_IS_SURFACE_ACTOR_X11 (priv->surface)) + meta_surface_actor_x11_set_size (META_SURFACE_ACTOR_X11 (priv->surface), + window_rect.width, window_rect.height); /* Normally we want freezing a window to also freeze its position; this allows * windows to atomically move and resize together, either under app control, @@ -1287,12 +1156,6 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self, if (is_frozen (self) && !did_placement) return; - if (priv->size_changed) - { - priv->needs_pixmap = TRUE; - meta_window_actor_update_shape (self); - } - if (meta_window_actor_effect_in_progress (self)) return; @@ -1306,18 +1169,14 @@ void meta_window_actor_show (MetaWindowActor *self, MetaCompEffect effect) { - MetaWindowActorPrivate *priv; - MetaCompScreen *info; - gulong event; - - priv = self->priv; - info = meta_screen_get_compositor_data (priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; + gulong event = 0; g_return_if_fail (!priv->visible); self->priv->visible = TRUE; - event = 0; switch (effect) { case META_COMP_EFFECT_CREATE: @@ -1334,13 +1193,11 @@ meta_window_actor_show (MetaWindowActor *self, g_assert_not_reached(); } - if (priv->redecorating || - info->switch_workspace_in_progress || + if (compositor->switch_workspace_in_progress || event == 0 || !start_simple_effect (self, event)) { clutter_actor_show (CLUTTER_ACTOR (self)); - priv->redecorating = FALSE; } } @@ -1348,12 +1205,9 @@ void meta_window_actor_hide (MetaWindowActor *self, MetaCompEffect effect) { - MetaWindowActorPrivate *priv; - MetaCompScreen *info; - gulong event; - - priv = self->priv; - info = meta_screen_get_compositor_data (priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; + gulong event = 0; g_return_if_fail (priv->visible); @@ -1363,10 +1217,9 @@ meta_window_actor_hide (MetaWindowActor *self, * hold off on hiding the window, and do it after the workspace * switch completes */ - if (info->switch_workspace_in_progress) + if (compositor->switch_workspace_in_progress) return; - event = 0; switch (effect) { case META_COMP_EFFECT_DESTROY: @@ -1392,7 +1245,8 @@ meta_window_actor_maximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { - MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the @@ -1403,8 +1257,7 @@ meta_window_actor_maximize (MetaWindowActor *self, self->priv->maximize_in_progress++; meta_window_actor_freeze (self); - if (!info->plugin_mgr || - !meta_plugin_manager_event_maximize (info->plugin_mgr, + if (!meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_MAXIMIZE, new_rect->x, new_rect->y, @@ -1421,7 +1274,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self, MetaRectangle *old_rect, MetaRectangle *new_rect) { - MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; /* The window has already been resized (in order to compute new_rect), * which by side effect caused the actor to be resized. Restore it to the @@ -1432,8 +1286,7 @@ meta_window_actor_unmaximize (MetaWindowActor *self, self->priv->unmaximize_in_progress++; meta_window_actor_freeze (self); - if (!info->plugin_mgr || - !meta_plugin_manager_event_maximize (info->plugin_mgr, + if (!meta_plugin_manager_event_maximize (compositor->plugin_mgr, self, META_PLUGIN_UNMAXIMIZE, new_rect->x, new_rect->y, @@ -1447,8 +1300,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self, MetaWindowActor * meta_window_actor_new (MetaWindow *window) { - MetaScreen *screen = meta_window_get_screen (window); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); + MetaDisplay *display = meta_window_get_display (window); + MetaCompositor *compositor = display->compositor; MetaWindowActor *self; MetaWindowActorPrivate *priv; ClutterActor *window_group; @@ -1459,13 +1312,7 @@ meta_window_actor_new (MetaWindow *window) priv = self->priv; - priv->last_width = -1; - priv->last_height = -1; - - priv->needs_pixmap = TRUE; - - meta_window_actor_set_updates_frozen (self, - meta_window_updates_are_frozen (priv->window)); + meta_window_actor_set_updates_frozen (self, meta_window_updates_are_frozen (priv->window)); /* If a window doesn't start off with updates frozen, we should * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. @@ -1479,20 +1326,18 @@ meta_window_actor_new (MetaWindow *window) meta_window_set_compositor_private (window, G_OBJECT (self)); if (window->layer == META_LAYER_OVERRIDE_REDIRECT) - window_group = info->top_window_group; + window_group = compositor->top_window_group; else - window_group = info->window_group; + window_group = compositor->window_group; clutter_actor_add_child (window_group, CLUTTER_ACTOR (self)); clutter_actor_hide (CLUTTER_ACTOR (self)); - clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); - /* Initial position in the stack is arbitrary; stacking will be synced * before we first paint. */ - info->windows = g_list_append (info->windows, self); + compositor->windows = g_list_append (compositor->windows, self); return self; } @@ -1582,11 +1427,6 @@ meta_window_actor_cull_out (MetaCullable *cullable, cairo_region_t *clip_region) { MetaWindowActor *self = META_WINDOW_ACTOR (cullable); - MetaWindowActorPrivate *priv = self->priv; - - /* Don't do any culling for the unredirected window */ - if (priv->unredirected) - return; meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); meta_window_actor_set_clip_region_beneath (self, clip_region); @@ -1599,6 +1439,7 @@ meta_window_actor_reset_culling (MetaCullable *cullable) MetaWindowActorPrivate *priv = self->priv; g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); + meta_cullable_reset_culling_children (cullable); } @@ -1609,78 +1450,6 @@ cullable_iface_init (MetaCullableInterface *iface) iface->reset_culling = meta_window_actor_reset_culling; } -static void -check_needs_pixmap (MetaWindowActor *self) -{ - MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - Window xwindow = meta_window_get_toplevel_xwindow (priv->window); - MetaCompositor *compositor; - - if (!priv->needs_pixmap) - return; - - if (xwindow == meta_screen_get_xroot (screen) || - xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage))) - return; - - compositor = meta_display_get_compositor (display); - - if (priv->size_changed) - { - meta_window_actor_detach (self); - priv->size_changed = FALSE; - } - - meta_error_trap_push (display); - - if (priv->back_pixmap == None) - { - CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - CoglTexture *texture; - - meta_error_trap_push (display); - - priv->back_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow); - - if (meta_error_trap_pop_with_return (display) != Success) - { - /* Probably a BadMatch if the window isn't viewable; we could - * GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync - * to avoid this, but there's no reason to take two round trips - * when one will do. (We need that Sync if we want to handle failures - * for any reason other than !viewable. That's unlikely, but maybe - * we'll BadAlloc or something.) - */ - priv->back_pixmap = None; - } - - if (priv->back_pixmap == None) - { - meta_verbose ("Unable to get named pixmap for %p\n", self); - goto out; - } - - if (compositor->no_mipmaps) - meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor), - FALSE); - - texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL)); - if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture)))) - g_warning ("NOTE: Not using GLX TFP!\n"); - - meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture); - } - - priv->needs_pixmap = FALSE; - - out: - meta_error_trap_pop (display); -} - static void check_needs_shadow (MetaWindowActor *self) { @@ -1744,66 +1513,17 @@ check_needs_shadow (MetaWindowActor *self) } void -meta_window_actor_process_damage (MetaWindowActor *self, - XDamageNotifyEvent *event) +meta_window_actor_process_x11_damage (MetaWindowActor *self, + XDamageNotifyEvent *event) { MetaWindowActorPrivate *priv = self->priv; - MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen); - gboolean redraw_queued; - priv->received_damage = TRUE; - - if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && !priv->unredirected) - { - MetaRectangle window_rect; - meta_window_get_frame_rect (priv->window, &window_rect); - - if (window_rect.x == event->area.x && - window_rect.y == event->area.y && - window_rect.width == event->area.width && - window_rect.height == event->area.height) - priv->full_damage_frames_count++; - else - priv->full_damage_frames_count = 0; - - if (priv->full_damage_frames_count >= 100) - priv->does_full_damage = TRUE; - } - - /* Drop damage event for unredirected windows */ - if (priv->unredirected) - return; - - if (is_frozen (self)) - { - /* The window is frozen due to an effect in progress: we ignore damage - * here on the off chance that this will stop the corresponding - * texture_from_pixmap from being update. - * - * needs_damage_all tracks that some unknown damage happened while the - * window was frozen so that when the window becomes unfrozen we can - * issue a full window update to cover any lost damage. - * - * It should be noted that this is an unreliable mechanism since it's - * quite likely that drivers will aim to provide a zero-copy - * implementation of the texture_from_pixmap extension and in those cases - * any drawing done to the window is always immediately reflected in the - * texture regardless of damage event handling. - */ - priv->needs_damage_all = TRUE; - return; - } - - if (priv->needs_pixmap) - return; - - update_area (self, event->area.x, event->area.y, event->area.width, event->area.height); - redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), - event->area.x, - event->area.y, - event->area.width, - event->area.height); - priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued; + if (priv->surface) + meta_surface_actor_process_damage (priv->surface, + event->area.x, + event->area.y, + event->area.width, + event->area.height); } void @@ -1865,12 +1585,18 @@ build_and_scan_frame_mask (MetaWindowActor *self, MetaWindowActorPrivate *priv = self->priv; guchar *mask_data; guint tex_width, tex_height; + MetaShapedTexture *stex; CoglTexture *paint_tex, *mask_texture; int stride; cairo_t *cr; cairo_surface_t *surface; - paint_tex = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); + stex = meta_surface_actor_get_texture (priv->surface); + g_return_if_fail (stex); + + meta_shaped_texture_set_mask_texture (stex, NULL); + + paint_tex = meta_shaped_texture_get_texture (stex); if (paint_tex == NULL) return; @@ -1944,8 +1670,7 @@ build_and_scan_frame_mask (MetaWindowActor *self, mask_data); } - meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), - mask_texture); + meta_shaped_texture_set_mask_texture (stex, mask_texture); if (mask_texture) cogl_object_unref (mask_texture); @@ -1978,7 +1703,6 @@ meta_window_actor_update_shape_region (MetaWindowActor *self) region = cairo_region_create_rectangle (&client_area); } - meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL); if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL)) build_and_scan_frame_mask (self, &client_area, region); @@ -1994,44 +1718,22 @@ static void meta_window_actor_update_input_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor); - cairo_region_t *region = NULL; - cairo_rectangle_int_t client_area; + MetaWindow *window = priv->window; + cairo_region_t *region; - meta_window_get_client_area_rect (priv->window, &client_area); - - if (priv->window->frame != NULL) + if (window->shape_region && window->input_region) { - region = meta_frame_get_frame_bounds (priv->window->frame); - - /* client area is in client window coordinates, so translate the - * input region into that coordinate system and back */ - cairo_region_translate (region, -client_area.x, -client_area.y); - cairo_region_union_rectangle (region, &client_area); - cairo_region_translate (region, client_area.x, client_area.y); - } - else if (priv->window->shape_region != NULL || - priv->window->input_region != NULL) - { - if (priv->window->shape_region != NULL) - { - region = cairo_region_copy (priv->window->shape_region); - - if (priv->window->input_region != NULL) - cairo_region_intersect (region, priv->window->input_region); - } - else - region = cairo_region_reference (priv->window->input_region); + region = cairo_region_copy (window->shape_region); + cairo_region_intersect (region, window->input_region); } + else if (window->shape_region) + region = cairo_region_reference (window->shape_region); + else if (window->input_region) + region = cairo_region_reference (window->input_region); else - { - /* If we don't have a shape on the server, that means that - * we have an implicit shape of one rectangle covering the - * entire window. */ - region = cairo_region_create_rectangle (&client_area); - } + region = NULL; - meta_shaped_texture_set_input_shape_region (stex, region); + meta_surface_actor_set_input_region (priv->surface, region); cairo_region_destroy (region); } @@ -2040,8 +1742,9 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; cairo_region_t *opaque_region; + gboolean argb32 = is_argb32 (self); - if (priv->argb32 && priv->window->opaque_region != NULL) + if (argb32 && priv->window->opaque_region != NULL) { cairo_rectangle_int_t client_area; @@ -2061,12 +1764,12 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) cairo_region_translate (opaque_region, client_area.x, client_area.y); cairo_region_intersect (opaque_region, priv->shape_region); } - else if (priv->argb32) + else if (argb32) opaque_region = NULL; else opaque_region = cairo_region_reference (priv->shape_region); - meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor), opaque_region); + meta_surface_actor_set_opaque_region (priv->surface, opaque_region); cairo_region_destroy (opaque_region); } @@ -2079,8 +1782,12 @@ check_needs_reshape (MetaWindowActor *self) return; meta_window_actor_update_shape_region (self); - meta_window_actor_update_input_region (self); - meta_window_actor_update_opaque_region (self); + + if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11) + { + meta_window_actor_update_input_region (self); + meta_window_actor_update_opaque_region (self); + } priv->needs_reshape = FALSE; } @@ -2095,16 +1802,13 @@ meta_window_actor_update_shape (MetaWindowActor *self) if (is_frozen (self)) return; - clutter_actor_queue_redraw (priv->actor); + clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->surface)); } static void meta_window_actor_handle_updates (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); if (is_frozen (self)) { @@ -2113,42 +1817,14 @@ meta_window_actor_handle_updates (MetaWindowActor *self) return; } - if (priv->unredirected) - { - /* Nothing to do here until/if the window gets redirected again */ - return; - } + if (meta_surface_actor_is_unredirected (priv->surface)) + return; - if (priv->received_damage) - { - meta_error_trap_push (display); - XDamageSubtract (xdisplay, priv->damage, None, None); - meta_error_trap_pop (display); + meta_surface_actor_pre_paint (priv->surface); - /* We need to make sure that any X drawing that happens before the - * XDamageSubtract() above is visible to subsequent GL rendering; - * the only standardized way to do this is EXT_x11_sync_object, - * which isn't yet widely available. For now, we count on details - * of Xorg and the open source drivers, and hope for the best - * otherwise. - * - * Xorg and open source driver specifics: - * - * The X server makes sure to flush drawing to the kernel before - * sending out damage events, but since we use DamageReportBoundingBox - * there may be drawing between the last damage event and the - * XDamageSubtract() that needs to be flushed as well. - * - * Xorg always makes sure that drawing is flushed to the kernel - * before writing events or responses to the client, so any round trip - * request at this point is sufficient to flush the GLX buffers. - */ - XSync (xdisplay, False); + if (!meta_surface_actor_is_visible (priv->surface)) + return; - priv->received_damage = FALSE; - } - - check_needs_pixmap (self); check_needs_reshape (self); check_needs_shadow (self); } @@ -2177,8 +1853,7 @@ static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); + MetaDisplay *display = meta_window_get_display (priv->window); Display *xdisplay = meta_display_get_xdisplay (display); XClientMessageEvent ev = { 0, }; @@ -2230,7 +1905,7 @@ do_send_frame_timings (MetaWindowActor *self, gint64 presentation_time) { MetaWindowActorPrivate *priv = self->priv; - MetaDisplay *display = meta_screen_get_display (priv->screen); + MetaDisplay *display = meta_window_get_display (priv->window); Display *xdisplay = meta_display_get_xdisplay (display); XClientMessageEvent ev = { 0, }; @@ -2329,7 +2004,8 @@ meta_window_actor_update_opacity (MetaWindowActor *self) MetaWindowActorPrivate *priv = self->priv; MetaWindow *window = priv->window; - clutter_actor_set_opacity (self->priv->actor, window->opacity); + if (priv->surface) + clutter_actor_set_opacity (CLUTTER_ACTOR (priv->surface), window->opacity); } void diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index 49a58b711..4096e4871 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -122,7 +122,6 @@ meta_window_group_paint (ClutterActor *actor) MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); ClutterActor *stage = clutter_actor_get_stage (actor); - MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen); /* Normally we expect an actor to be drawn at it's position on the screen. * However, if we're inside the paint of a ClutterClone, that won't be the @@ -165,15 +164,6 @@ meta_window_group_paint (ClutterActor *actor) paint_y_offset = paint_y_origin - actor_y_origin; cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset); - if (info->unredirected_window != NULL) - { - cairo_rectangle_int_t unredirected_rect; - - meta_window_get_frame_rect (info->unredirected_window, (MetaRectangle *)&unredirected_rect); - cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect); - cairo_region_subtract_rectangle (clip_region, &unredirected_rect); - } - meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region); cairo_region_destroy (unobscured_region); diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c index 056895355..1c1820fd5 100644 --- a/src/compositor/plugins/default.c +++ b/src/compositor/plugins/default.c @@ -32,7 +32,7 @@ #include #include -#define DESTROY_TIMEOUT 250 +#define DESTROY_TIMEOUT 100 #define MINIMIZE_TIMEOUT 250 #define MAXIMIZE_TIMEOUT 250 #define MAP_TIMEOUT 250 @@ -488,8 +488,6 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data /* FIXME - we shouldn't assume the original scale, it should be saved * at the start of the effect */ clutter_actor_set_scale (data->actor, 1.0, 1.0); - clutter_actor_move_anchor_point_from_gravity (data->actor, - CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_minimize_completed (plugin, window_actor); @@ -526,9 +524,6 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor) apriv->is_minimized = TRUE; - clutter_actor_move_anchor_point_from_gravity (actor, - CLUTTER_GRAVITY_CENTER); - animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MINIMIZE_TIMEOUT, @@ -567,8 +562,6 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data /* FIXME - don't assume the original scale was 1.0 */ clutter_actor_set_scale (data->actor, 1.0, 1.0); - clutter_actor_move_anchor_point_from_gravity (data->actor, - CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ meta_plugin_maximize_completed (plugin, window_actor); @@ -593,10 +586,8 @@ maximize (MetaPlugin *plugin, ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); - gdouble scale_x = 1.0; - gdouble scale_y = 1.0; - gfloat anchor_x = 0; - gfloat anchor_y = 0; + gdouble scale_x = 1.0; + gdouble scale_y = 1.0; type = meta_window_get_window_type (meta_window); @@ -620,13 +611,6 @@ maximize (MetaPlugin *plugin, scale_x = (gdouble)end_width / (gdouble) width; scale_y = (gdouble)end_height / (gdouble) height; - anchor_x = (gdouble)(x - end_x)*(gdouble)width / - ((gdouble)(end_width - width)); - anchor_y = (gdouble)(y - end_y)*(gdouble)height / - ((gdouble)(end_height - height)); - - clutter_actor_move_anchor_point (actor, anchor_x, anchor_y); - animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAXIMIZE_TIMEOUT, @@ -681,9 +665,6 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) apriv->tml_map = NULL; - clutter_actor_move_anchor_point_from_gravity (data->actor, - CLUTTER_GRAVITY_NORTH_WEST); - /* Now notify the manager that we are done with this effect */ meta_plugin_map_completed (plugin, window_actor); @@ -769,14 +750,12 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor) EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); - clutter_actor_move_anchor_point_from_gravity (actor, - CLUTTER_GRAVITY_CENTER); - animation = clutter_actor_animate (actor, - CLUTTER_EASE_IN_SINE, + CLUTTER_EASE_OUT_QUAD, DESTROY_TIMEOUT, - "scale-x", 0.0, - "scale-y", 1.0, + "opacity", 0, + "scale-x", 0.8, + "scale-y", 0.8, NULL); apriv->tml_destroy = clutter_animation_get_timeline (animation); data->plugin = plugin; diff --git a/src/core/above-tab-keycode.c b/src/core/above-tab-keycode.c deleted file mode 100644 index e980f5228..000000000 --- a/src/core/above-tab-keycode.c +++ /dev/null @@ -1,241 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Find the keycode for the key above the tab key */ -/* - * Copyright 2010 Red Hat, Inc. - * - * 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, see . - */ - -/* The standard cycle-windows keybinding should be the key above the - * tab key. This will have a different keysym on different keyboards - - * it's the ` (grave) key on US keyboards but something else on many - * other national layouts. So we need to figure out the keycode for - * this key without reference to key symbol. - * - * The "correct" way to do this is to get the XKB geometry from the - * X server, find the Tab key, find the key above the Tab key in the - * same section and use the keycode for that key. This is what I - * implemented here, but unfortunately, fetching the geometry is rather - * slow (It could take 20ms or more.) - * - * If you looking for a way to optimize Mutter startup performance: - * On all Linux systems using evdev the key above TAB will have - * keycode 49. (KEY_GRAVE=41 + the 8 code point offset between - * evdev keysyms and X keysyms.) So a configure option - * --with-above-tab-keycode=49 could be added that bypassed this - * code. It wouldn't work right for displaying Mutter remotely - * to a non-Linux X server, but that is pretty rare. - */ - -#include - -#include - -#include "display-private.h" - -#include - -#ifdef HAVE_XKB -#include -#include - -static guint -compute_above_tab_keycode (Display *xdisplay) -{ - XkbDescPtr keyboard; - XkbGeometryPtr geometry; - int i, j, k; - int tab_keycode; - char *tab_name; - XkbSectionPtr tab_section; - XkbBoundsRec tab_bounds; - XkbKeyPtr best_key = NULL; - guint best_keycode = (guint)-1; - int best_x_dist = G_MAXINT; - int best_y_dist = G_MAXINT; - - /* We need only the Names and the Geometry, but asking for these results - * in the Keyboard information retrieval failing for unknown reasons. - * (Testing with xorg-1.9.1.) So we ask for a part that we don't need - * as well. - */ - keyboard = XkbGetKeyboard (xdisplay, - XkbGBN_ClientSymbolsMask | XkbGBN_KeyNamesMask | XkbGBN_GeometryMask, - XkbUseCoreKbd); - if (!keyboard) - return best_keycode; - - geometry = keyboard->geom; - - /* There could potentially be multiple keys with the Tab keysym on the keyboard; - * but XKeysymToKeycode() returns us the one that the alt-Tab binding will - * use which is good enough - */ - tab_keycode = XKeysymToKeycode (xdisplay, XK_Tab); - if (tab_keycode == 0 || tab_keycode < keyboard->min_key_code || tab_keycode > keyboard->max_key_code) - goto out; - - /* The keyboard geometry is stored by key "name" rather than keycode. - * (Key names are 4-character strings like like TAB or AE01.) We use the - * 'names' part of the keyboard description to map keycode to key name. - * - * XKB has a "key aliases" feature where a single keyboard key can have - * multiple names (with separate sets of aliases in the 'names' part and - * in the 'geometry' part), but I don't really understand it or how it is used, - * so I'm ignoring it here. - */ - - tab_name = keyboard->names->keys[tab_keycode].name; /* Not NULL terminated! */ - - /* First, iterate through the keyboard geometry to find the tab key; the keyboard - * geometry has a three-level heirarchy of section > row > key - */ - for (i = 0; i < geometry->num_sections; i++) - { - XkbSectionPtr section = &geometry->sections[i]; - for (j = 0; j < section->num_rows; j++) - { - int x = 0; - int y = 0; - - XkbRowPtr row = §ion->rows[j]; - for (k = 0; k < row->num_keys; k++) - { - XkbKeyPtr key = &row->keys[k]; - XkbShapePtr shape = XkbKeyShape (geometry, key); - - if (row->vertical) - y += key->gap; - else - x += key->gap; - - if (strncmp (key->name.name, tab_name, XkbKeyNameLength) == 0) - { - tab_section = section; - tab_bounds = shape->bounds; - tab_bounds.x1 += row->left + x; - tab_bounds.x2 += row->left + x; - tab_bounds.y1 += row->top + y; - tab_bounds.y2 += row->top + y; - - goto found_tab; - } - - if (row->vertical) - y += (shape->bounds.y2 - shape->bounds.y1); - else - x += (shape->bounds.x2 - shape->bounds.x1); - } - } - } - - /* No tab key found */ - goto out; - - found_tab: - - /* Now find the key that: - * - Is in the same section as the Tab key - * - Has a horizontal center in the Tab key's horizonal bounds - * - Is above the Tab key at a distance closer than any other key - * - In case of ties, has its horizontal center as close as possible - * to the Tab key's horizontal center - */ - for (j = 0; j < tab_section->num_rows; j++) - { - int x = 0; - int y = 0; - - XkbRowPtr row = &tab_section->rows[j]; - for (k = 0; k < row->num_keys; k++) - { - XkbKeyPtr key = &row->keys[k]; - XkbShapePtr shape = XkbKeyShape(geometry, key); - XkbBoundsRec bounds = shape->bounds; - int x_center; - int x_dist, y_dist; - - if (row->vertical) - y += key->gap; - else - x += key->gap; - - bounds.x1 += row->left + x; - bounds.x2 += row->left + x; - bounds.y1 += row->top + y; - bounds.y2 += row->top + y; - - y_dist = tab_bounds.y1 - bounds.y2; - if (y_dist < 0) - continue; - - x_center = (bounds.x1 + bounds.x2) / 2; - if (x_center < tab_bounds.x1 || x_center > tab_bounds.x2) - continue; - - x_dist = ABS (x_center - (tab_bounds.x1 + tab_bounds.x2) / 2); - - if (y_dist < best_y_dist || - (y_dist == best_y_dist && x_dist < best_x_dist)) - { - best_key = key; - best_x_dist = x_dist; - best_y_dist = y_dist; - } - - if (row->vertical) - y += (shape->bounds.y2 - shape->bounds.y1); - else - x += (shape->bounds.x2 - shape->bounds.x1); - } - } - - if (best_key == NULL) - goto out; - - /* Now we need to resolve the name of the best key back to a keycode */ - for (i = keyboard->min_key_code; i < keyboard->max_key_code; i++) - { - if (strncmp (best_key->name.name, keyboard->names->keys[i].name, XkbKeyNameLength) == 0) - { - best_keycode = i; - break; - } - } - - out: - XkbFreeKeyboard (keyboard, 0, True); - - return best_keycode; -} -#else /* !HAVE_XKB */ -static guint -compute_above_tab_keycode (Display *xdisplay) -{ - return XKeysymToKeycode (xdisplay, XK_grave); -} -#endif /* HAVE_XKB */ - -guint -meta_display_get_above_tab_keycode (MetaDisplay *display) -{ - if (display->above_tab_keycode == 0) /* not yet computed */ - display->above_tab_keycode = compute_above_tab_keycode (display->xdisplay); - - if (display->above_tab_keycode == (guint)-1) /* failed to compute */ - return 0; - else - return display->above_tab_keycode; -} diff --git a/src/core/barrier.c b/src/core/barrier.c index 643b26ed7..b869d2ef2 100644 --- a/src/core/barrier.c +++ b/src/core/barrier.c @@ -366,11 +366,25 @@ meta_barrier_fire_event (MetaBarrier *barrier, } gboolean -meta_display_process_barrier_event (MetaDisplay *display, - XIBarrierEvent *xev) +meta_display_process_barrier_event (MetaDisplay *display, + XIEvent *event) { MetaBarrier *barrier; + XIBarrierEvent *xev; + if (event == NULL) + return FALSE; + + switch (event->evtype) + { + case XI_BarrierHit: + case XI_BarrierLeave: + break; + default: + return FALSE; + } + + xev = (XIBarrierEvent *) event; barrier = g_hash_table_lookup (display->xids, &xev->barrier); if (barrier != NULL) { diff --git a/src/core/bell.c b/src/core/bell.c index cc25a27ec..0b1457b40 100644 --- a/src/core/bell.c +++ b/src/core/bell.c @@ -58,88 +58,6 @@ #include #endif -/** - * bell_flash_screen: - * @display: The display which owns the screen (rather redundant) - * @screen: The screen to flash - * - * Flashes one entire screen. This is done by making a window the size of the - * whole screen (or reusing the old one, if it's still around), mapping it, - * painting it white and then black, and then unmapping it. We set saveunder so - * that all the windows behind it come back immediately. - * - * Unlike frame flashes, we don't do fullscreen flashes with a timeout; rather, - * we do them in one go, because we don't have to rely on the theme code - * redrawing the frame for us in order to do the flash. - */ -/* - * Bug: The way I read it, this appears not to do the flash - * the first time we flash a particular display. Am I wrong? - * - * Bug: This appears to destroy our current XSync status. - */ -static void -bell_flash_screen (MetaDisplay *display, - MetaScreen *screen) -{ - Window root = screen->xroot; - int width = screen->rect.width; - int height = screen->rect.height; - - if (screen->flash_window == None) - { - Visual *visual = (Visual *)CopyFromParent; - XSetWindowAttributes xswa; - int depth = CopyFromParent; - xswa.save_under = True; - xswa.override_redirect = True; - /* - * TODO: use XGetVisualInfo and determine which is an - * overlay, if one is present, and use the Overlay visual - * for this window (for performance reasons). - * Not sure how to tell this yet... - */ - screen->flash_window = XCreateWindow (display->xdisplay, root, - 0, 0, width, height, - 0, depth, - InputOutput, - visual, - /* note: XSun doesn't like SaveUnder here */ - CWSaveUnder | CWOverrideRedirect, - &xswa); - XSelectInput (display->xdisplay, screen->flash_window, ExposureMask); - XMapWindow (display->xdisplay, screen->flash_window); - XSync (display->xdisplay, False); - XFlush (display->xdisplay); - XUnmapWindow (display->xdisplay, screen->flash_window); - } - else - { - /* just draw something in the window */ - GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL); - XMapWindow (display->xdisplay, screen->flash_window); - XSetForeground (display->xdisplay, gc, - WhitePixel (display->xdisplay, - XScreenNumberOfScreen (screen->xscreen))); - XFillRectangle (display->xdisplay, screen->flash_window, gc, - 0, 0, width, height); - XSetForeground (display->xdisplay, gc, - BlackPixel (display->xdisplay, - XScreenNumberOfScreen (screen->xscreen))); - XFillRectangle (display->xdisplay, screen->flash_window, gc, - 0, 0, width, height); - XFlush (display->xdisplay); - XSync (display->xdisplay, False); - XUnmapWindow (display->xdisplay, screen->flash_window); - XFreeGC (display->xdisplay, gc); - } - - if (meta_prefs_get_focus_mode () != G_DESKTOP_FOCUS_MODE_CLICK && - !display->mouse_mode) - meta_display_increment_focus_sentinel (display); - XFlush (display->xdisplay); -} - /** * bell_flash_fullscreen: * @display: The display the event came in on @@ -156,34 +74,8 @@ static void bell_flash_fullscreen (MetaDisplay *display, XkbAnyEvent *xkb_ev) { - XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev; - MetaScreen *screen; - g_assert (xkb_ev->xkb_type == XkbBellNotify); - if (xkb_bell_ev->window != None) - { - screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window); - if (screen) - { - if (display->compositor) - meta_compositor_flash_screen (display->compositor, screen); - else - bell_flash_screen (display, screen); - } - } - else - { - GSList *screen_list = display->screens; - while (screen_list) - { - screen = (MetaScreen *) screen_list->data; - if (display->compositor) - meta_compositor_flash_screen (display->compositor, screen); - else - bell_flash_screen (display, screen); - screen_list = screen_list->next; - } - } + meta_compositor_flash_screen (display->compositor, display->screen); } /** diff --git a/src/core/constraints.c b/src/core/constraints.c index c6950ce01..8bb9b2510 100644 --- a/src/core/constraints.c +++ b/src/core/constraints.c @@ -425,6 +425,7 @@ setup_constraint_info (ConstraintInfo *info, * the monitor. */ if (meta_prefs_get_force_fullscreen() && + window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND && !window->hide_titlebar_when_maximized && (window->decorated || !meta_window_is_client_decorated (window)) && meta_rectangle_equal (new, &monitor_info->rect) && diff --git a/src/core/constraints.h b/src/core/constraints.h index e5d29ca55..9c3c41e0e 100644 --- a/src/core/constraints.h +++ b/src/core/constraints.h @@ -27,15 +27,6 @@ #include "window-private.h" #include "frame.h" -typedef enum -{ - META_IS_CONFIGURE_REQUEST = 1 << 0, - META_DO_GRAVITY_ADJUST = 1 << 1, - META_IS_USER_ACTION = 1 << 2, - META_IS_MOVE_ACTION = 1 << 3, - META_IS_RESIZE_ACTION = 1 << 4 -} MetaMoveResizeFlags; - void meta_window_constrain (MetaWindow *window, MetaMoveResizeFlags flags, int resize_gravity, diff --git a/src/core/core.c b/src/core/core.c index 319020d49..a091bb8ca 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -153,7 +153,7 @@ meta_core_get (Display *xdisplay, break; default: - meta_warning(_("Unknown window information request: %d"), request); + meta_warning("Unknown window information request: %d\n", request); } request = va_arg (args, MetaCoreGetType); @@ -270,9 +270,11 @@ meta_core_lower_beneath_grab_window (Display *xdisplay, MetaDisplay *display; MetaScreen *screen; MetaWindow *grab_window; + MetaStackWindow stack_window; + MetaStackWindow stack_sibling; display = meta_display_for_x_display (xdisplay); - screen = meta_display_screen_for_xwindow (display, xwindow); + screen = display->screen; grab_window = display->grab_window; if (grab_window == NULL) @@ -281,9 +283,13 @@ meta_core_lower_beneath_grab_window (Display *xdisplay, changes.stack_mode = Below; changes.sibling = meta_window_get_toplevel_xwindow (grab_window); + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = xwindow; + stack_sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_sibling.x11.xwindow = changes.sibling; meta_stack_tracker_record_lower_below (screen->stack_tracker, - xwindow, - changes.sibling, + &stack_window, + &stack_sibling, XNextRequest (screen->display->xdisplay)); meta_error_trap_push (display); @@ -597,13 +603,10 @@ meta_core_get_workspace_name_with_index (Display *xdisplay, int index) { MetaDisplay *display; - MetaScreen *screen; MetaWorkspace *workspace; display = meta_display_for_x_display (xdisplay); - screen = meta_display_screen_for_root (display, xroot); - g_assert (screen != NULL); - workspace = meta_screen_get_workspace_by_index (screen, index); + workspace = meta_screen_get_workspace_by_index (display->screen, index); return workspace ? meta_workspace_get_name (workspace) : NULL; } @@ -624,7 +627,7 @@ meta_core_begin_grab_op (Display *xdisplay, MetaScreen *screen; display = meta_display_for_x_display (xdisplay); - screen = meta_display_screen_for_xwindow (display, frame_xwindow); + screen = display->screen; g_assert (screen != NULL); @@ -664,10 +667,6 @@ meta_core_get_grab_frame (Display *xdisplay) display = meta_display_for_x_display (xdisplay); g_assert (display != NULL); - g_assert (display->grab_op == META_GRAB_OP_NONE || - display->grab_screen != NULL); - g_assert (display->grab_op == META_GRAB_OP_NONE || - display->grab_screen->display->xdisplay == xdisplay); if (display->grab_op != META_GRAB_OP_NONE && display->grab_window && @@ -712,16 +711,6 @@ meta_core_set_screen_cursor (Display *xdisplay, meta_frame_set_screen_cursor (window->frame, cursor); } -void -meta_core_increment_event_serial (Display *xdisplay) -{ - MetaDisplay *display; - - display = meta_display_for_x_display (xdisplay); - - meta_display_increment_event_serial (display); -} - void meta_invalidate_default_icons (void) { diff --git a/src/core/core.h b/src/core/core.h index a3321531b..4c9e58754 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -193,12 +193,6 @@ void meta_core_set_screen_cursor (Display *xdisplay, Window frame_on_screen, MetaCursor cursor); -/* Used because we ignore EnterNotify when a window is unmapped that - * really shouldn't cause focus changes, by comparing the event serial - * of the EnterNotify and the UnmapNotify. - */ -void meta_core_increment_event_serial (Display *display); - void meta_invalidate_default_icons (void); void meta_core_add_old_event_mask (Display *xdisplay, diff --git a/src/core/delete.c b/src/core/delete.c index 96e2ec59a..8b5070796 100644 --- a/src/core/delete.c +++ b/src/core/delete.c @@ -37,18 +37,17 @@ #include #include +#include "wayland/meta-wayland-surface.h" + static void meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp); static void -delete_ping_reply_func (MetaDisplay *display, - Window xwindow, +delete_ping_reply_func (MetaWindow *window, guint32 timestamp, void *user_data) { - meta_topic (META_DEBUG_PING, - "Got reply to delete ping for %s\n", - ((MetaWindow*)user_data)->desc); + meta_topic (META_DEBUG_PING, "Got reply to delete ping for %s\n", window->desc); /* we do nothing */ } @@ -66,12 +65,10 @@ dialog_exited (GPid pid, int status, gpointer user_data) } static void -delete_ping_timeout_func (MetaDisplay *display, - Window xwindow, +delete_ping_timeout_func (MetaWindow *window, guint32 timestamp, void *user_data) { - MetaWindow *window = user_data; char *window_title; gchar *window_content, *tmp; GPid dialog_pid; @@ -135,36 +132,18 @@ void meta_window_check_alive (MetaWindow *window, guint32 timestamp) { - meta_display_ping_window (window->display, - window, + meta_display_ping_window (window, timestamp, delete_ping_reply_func, delete_ping_timeout_func, - window); + NULL); } void meta_window_delete (MetaWindow *window, guint32 timestamp) { - meta_error_trap_push (window->display); - if (window->delete_window) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Deleting %s with delete_window request\n", - window->desc); - meta_window_send_icccm_message (window, - window->display->atom_WM_DELETE_WINDOW, - timestamp); - } - else - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Deleting %s with explicit kill\n", - window->desc); - XKillClient (window->display->xdisplay, window->xwindow); - } - meta_error_trap_pop (window->display); + META_WINDOW_GET_CLASS (window)->delete (window, timestamp); meta_window_check_alive (window, timestamp); @@ -197,33 +176,10 @@ meta_window_delete (MetaWindow *window, } } - void meta_window_kill (MetaWindow *window) { - meta_topic (META_DEBUG_WINDOW_OPS, - "Killing %s brutally\n", - window->desc); - - if (!meta_window_is_remote (window) && - window->net_wm_pid > 0) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Killing %s with kill()\n", - window->desc); - - if (kill (window->net_wm_pid, 9) < 0) - meta_topic (META_DEBUG_WINDOW_OPS, - "Failed to signal %s: %s\n", - window->desc, strerror (errno)); - } - - meta_topic (META_DEBUG_WINDOW_OPS, - "Disconnecting %s with XKillClient()\n", - window->desc); - meta_error_trap_push (window->display); - XKillClient (window->display->xdisplay, window->xwindow); - meta_error_trap_pop (window->display); + META_WINDOW_GET_CLASS (window)->kill (window); } void @@ -258,8 +214,7 @@ meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp) { MetaWindow *w = tmp->data; - if (w->xtransient_for == window->xwindow && - w->res_class && + if (w->transient_for == window && w->res_class && g_ascii_strcasecmp (w->res_class, "mutter-dialog") == 0) { meta_window_activate (w, timestamp); diff --git a/src/core/display-private.h b/src/core/display-private.h index 5c47d12f5..8209c8f19 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -37,6 +37,7 @@ #include "keybindings-private.h" #include #include +#include #ifdef HAVE_STARTUP_NOTIFICATION #include @@ -54,10 +55,9 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks; typedef struct MetaEdgeResistanceData MetaEdgeResistanceData; -typedef void (* MetaWindowPingFunc) (MetaDisplay *display, - Window xwindow, - guint32 timestamp, - gpointer user_data); +typedef void (* MetaWindowPingFunc) (MetaWindow *window, + guint32 timestamp, + gpointer user_data); typedef enum { META_LIST_DEFAULT = 0, /* normal windows */ @@ -91,6 +91,8 @@ struct _MetaDisplay char *name; Display *xdisplay; + int clutter_event_filter; + Window leader_window; Window timestamp_pinging_window; @@ -143,17 +145,12 @@ struct _MetaDisplay * multiple events with the same serial. */ guint focused_by_us : 1; - - guint static_gravity_works : 1; /*< private-ish >*/ - guint error_trap_synced_at_last_pop : 1; - GSList *screens; - MetaScreen *active_screen; + MetaScreen *screen; GHashTable *xids; - int error_traps; - int (* error_trap_handler) (Display *display, - XErrorEvent *error); + GHashTable *wayland_windows; + int server_grab_count; /* serials of leave/unmap events that may @@ -185,11 +182,10 @@ struct _MetaDisplay MetaWindow* autoraise_window; /* Alt+click button grabs */ - unsigned int window_grab_modifiers; + ClutterModifierType window_grab_modifiers; /* current window operation */ MetaGrabOp grab_op; - MetaScreen *grab_screen; MetaWindow *grab_window; Window grab_xwindow; int grab_button; @@ -200,7 +196,6 @@ struct _MetaDisplay int grab_tile_monitor_number; int grab_latest_motion_x; int grab_latest_motion_y; - gulong grab_mask; guint grab_have_pointer : 1; guint grab_have_keyboard : 1; guint grab_frame_action : 1; @@ -212,7 +207,6 @@ struct _MetaDisplay gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */ MetaResizePopup *grab_resize_popup; GTimeVal grab_last_moveresize_time; - guint32 grab_motion_notify_time; GList* grab_old_window_stacking; MetaEdgeResistanceData *grab_edge_resistance_data; unsigned int grab_last_user_action_was_snap; @@ -236,11 +230,7 @@ struct _MetaDisplay int max_keycode; KeySym *keymap; int keysyms_per_keycode; - XModifierKeymap *modmap; - unsigned int above_tab_keycode; unsigned int ignored_modifier_mask; - unsigned int num_lock_mask; - unsigned int scroll_lock_mask; unsigned int hyper_mask; unsigned int super_mask; unsigned int meta_mask; @@ -351,10 +341,6 @@ struct _MetaDisplayClass gboolean meta_display_open (void); void meta_display_close (MetaDisplay *display, guint32 timestamp); -MetaScreen* meta_display_screen_for_x_screen (MetaDisplay *display, - Screen *screen); -MetaScreen* meta_display_screen_for_xwindow (MetaDisplay *display, - Window xindow); void meta_display_grab (MetaDisplay *display); void meta_display_ungrab (MetaDisplay *display); @@ -377,6 +363,11 @@ void meta_display_register_x_window (MetaDisplay *display, void meta_display_unregister_x_window (MetaDisplay *display, Window xwindow); +void meta_display_register_wayland_window (MetaDisplay *display, + MetaWindow *window); +void meta_display_unregister_wayland_window (MetaDisplay *display, + MetaWindow *window); + #ifdef HAVE_XSYNC MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display, XSyncAlarm alarm); @@ -436,20 +427,22 @@ void meta_display_retheme_all (void); void meta_display_set_cursor_theme (const char *theme, int size); -void meta_display_ping_window (MetaDisplay *display, - MetaWindow *window, +void meta_display_ping_window (MetaWindow *window, guint32 timestamp, MetaWindowPingFunc ping_reply_func, MetaWindowPingFunc ping_timeout_func, void *user_data); -gboolean meta_display_window_has_pending_pings (MetaDisplay *display, - MetaWindow *window); +void meta_display_pong_for_serial (MetaDisplay *display, + guint32 serial); int meta_resize_gravity_from_grab_op (MetaGrabOp op); gboolean meta_grab_op_is_moving (MetaGrabOp op); gboolean meta_grab_op_is_resizing (MetaGrabOp op); gboolean meta_grab_op_is_mouse (MetaGrabOp op); +gboolean meta_grab_op_is_clicking (MetaGrabOp op); +gboolean meta_grab_op_is_wayland (MetaGrabOp op); +gboolean meta_grab_op_is_keyboard (MetaGrabOp op); void meta_display_devirtualize_modifiers (MetaDisplay *display, MetaVirtualModifier modifiers, @@ -464,18 +457,14 @@ void meta_display_queue_autoraise_callback (MetaDisplay *display, void meta_display_remove_autoraise_callback (MetaDisplay *display); void meta_display_overlay_key_activate (MetaDisplay *display); -void meta_display_accelerator_activate (MetaDisplay *display, - guint action, - guint deviceid, - guint timestamp); +void meta_display_accelerator_activate (MetaDisplay *display, + guint action, + ClutterKeyEvent *event); gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display); -/* In above-tab-keycode.c */ -guint meta_display_get_above_tab_keycode (MetaDisplay *display); - #ifdef HAVE_XI23 -gboolean meta_display_process_barrier_event (MetaDisplay *display, - XIBarrierEvent *event); +gboolean meta_display_process_barrier_event (MetaDisplay *display, + XIEvent *event); #endif /* HAVE_XI23 */ void meta_display_set_input_focus_xwindow (MetaDisplay *display, @@ -483,4 +472,16 @@ void meta_display_set_input_focus_xwindow (MetaDisplay *display, Window window, guint32 timestamp); +void meta_display_sync_wayland_input_focus (MetaDisplay *display); +void meta_display_update_focus_window (MetaDisplay *display, + MetaWindow *window, + Window xwindow, + gulong serial, + gboolean focused_by_us); + +void meta_display_sanity_check_timestamps (MetaDisplay *display, + guint32 timestamp); +gboolean meta_display_timestamp_too_old (MetaDisplay *display, + guint32 *timestamp); + #endif diff --git a/src/core/display.c b/src/core/display.c index e8a284fe2..4556389ee 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -32,25 +32,24 @@ #include #include "display-private.h" +#include "events.h" #include "util-private.h" #include #include "screen-private.h" #include "window-private.h" -#include "window-props.h" -#include "group-props.h" #include "frame.h" #include #include "keybindings-private.h" #include #include "resizepopup.h" -#include "xprops.h" #include "workspace-private.h" #include "bell.h" #include #include #include #include "mutter-enum-types.h" -#include "meta-idle-monitor-private.h" +#include "meta-idle-monitor-dbus.h" +#include "meta-cursor-tracker-private.h" #ifdef HAVE_RANDR #include @@ -58,12 +57,7 @@ #ifdef HAVE_SHAPE #include #endif -#ifdef HAVE_XKB -#include -#endif -#ifdef HAVE_XCURSOR #include -#endif #include #include #include @@ -72,6 +66,14 @@ #include #include +#include "x11/window-x11.h" +#include "x11/window-props.h" +#include "x11/group-props.h" +#include "x11/xprops.h" + +#include "wayland/meta-xwayland-private.h" +#include "meta-surface-actor-wayland.h" + /* * SECTION:pings * @@ -96,10 +98,9 @@ * does or doesn't respond to the ping, we use this information to deal with * these facts; we have a handler function for each. */ -typedef struct +typedef struct { - MetaDisplay *display; - Window xwindow; + MetaWindow *window; guint32 timestamp; MetaWindowPingFunc ping_reply_func; MetaWindowPingFunc ping_timeout_func; @@ -107,15 +108,6 @@ typedef struct guint ping_timeout_id; } MetaPingData; -typedef struct -{ - MetaDisplay *display; - MetaWindow *window; - int pointer_x; - int pointer_y; -} MetaFocusData; - - G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT); /* Signals */ @@ -153,36 +145,10 @@ static MetaDisplay *the_display = NULL; static const char *gnome_wm_keybindings = "Mutter"; static const char *net_wm_name = "Mutter"; -#ifdef WITH_VERBOSE_MODE -static void meta_spew_event (MetaDisplay *display, - XEvent *event); -#endif - -static gboolean event_callback (XEvent *event, - gpointer data); -static Window event_get_modified_window (MetaDisplay *display, - XEvent *event); -static guint32 event_get_time (MetaDisplay *display, - XEvent *event); -static void process_request_frame_extents (MetaDisplay *display, - XEvent *event); -static void process_pong_message (MetaDisplay *display, - XEvent *event); -static void process_selection_request (MetaDisplay *display, - XEvent *event); -static void process_selection_clear (MetaDisplay *display, - XEvent *event); - static void update_window_grab_modifiers (MetaDisplay *display); static void prefs_changed_callback (MetaPreference pref, void *data); - -static void sanity_check_timestamps (MetaDisplay *display, - guint32 known_good_timestamp); - -MetaGroup* get_focussed_group (MetaDisplay *display); - static void meta_display_get_property(GObject *object, guint prop_id, @@ -347,14 +313,14 @@ remove_pending_pings_for_window (MetaDisplay *display, Window xwindow) GSList *dead; /* could obviously be more efficient, don't care */ - + /* build list to be removed */ dead = NULL; for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; - if (ping_data->xwindow == xwindow) + if (ping_data->window->xwindow == xwindow) dead = g_slist_prepend (dead, ping_data); } @@ -396,13 +362,11 @@ sn_error_trap_pop (SnDisplay *sn_display, static void enable_compositor (MetaDisplay *display) { - GSList *list; - if (!META_DISPLAY_HAS_COMPOSITE (display) || !META_DISPLAY_HAS_DAMAGE (display) || !META_DISPLAY_HAS_RENDER (display)) { - meta_warning (_("Missing %s extension required for compositing"), + meta_warning ("Missing %s extension required for compositing", !META_DISPLAY_HAS_COMPOSITE (display) ? "composite" : !META_DISPLAY_HAS_DAMAGE (display) ? "damage" : "render"); return; @@ -413,14 +377,8 @@ enable_compositor (MetaDisplay *display) if (!display->compositor) return; - - for (list = display->screens; list != NULL; list = list->next) - { - MetaScreen *screen = list->data; - - meta_compositor_manage_screen (screen->display->compositor, - screen); - } + + meta_compositor_manage (display->compositor); } static void @@ -474,9 +432,7 @@ gboolean meta_display_open (void) { Display *xdisplay; - GSList *screens; MetaScreen *screen; - GSList *tmp; int i; guint32 timestamp; @@ -499,6 +455,9 @@ meta_display_open (void) return FALSE; } + if (meta_is_wayland_compositor ()) + meta_xwayland_complete_init (); + if (meta_is_syncing ()) XSynchronize (xdisplay, True); @@ -513,9 +472,6 @@ meta_display_open (void) */ the_display->name = g_strdup (XDisplayName (NULL)); the_display->xdisplay = xdisplay; - the_display->error_trap_synced_at_last_pop = TRUE; - the_display->error_traps = 0; - the_display->error_trap_handler = NULL; the_display->server_grab_count = 0; the_display->display_opening = TRUE; @@ -531,9 +487,6 @@ meta_display_open (void) the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */ the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a terminal has the focus */ - - /* FIXME copy the checks from GDK probably */ - the_display->static_gravity_works = g_getenv ("MUTTER_USE_STATIC_GRAVITY") != NULL; meta_bell_init (the_display); @@ -571,8 +524,7 @@ meta_display_open (void) the_display->window_with_menu = NULL; the_display->window_menu = NULL; - the_display->screens = NULL; - the_display->active_screen = NULL; + the_display->screen = NULL; #ifdef HAVE_STARTUP_NOTIFICATION the_display->sn_display = sn_display_new (the_display->xdisplay, @@ -581,12 +533,11 @@ meta_display_open (void) #endif /* Get events */ - meta_ui_add_event_func (the_display->xdisplay, - event_callback, - the_display); - + meta_display_init_events (the_display); + the_display->xids = g_hash_table_new (meta_unsigned_long_hash, meta_unsigned_long_equal); + the_display->wayland_windows = g_hash_table_new (NULL, NULL); i = 0; while (i < N_IGNORED_CROSSING_SERIALS) @@ -608,7 +559,6 @@ meta_display_open (void) the_display->grab_op = META_GRAB_OP_NONE; the_display->grab_window = NULL; - the_display->grab_screen = NULL; the_display->grab_resize_popup = NULL; the_display->grab_tile_mode = META_TILE_NONE; the_display->grab_tile_monitor_number = -1; @@ -806,14 +756,10 @@ meta_display_open (void) meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n"); } -#ifdef HAVE_XCURSOR { XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ()); XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ()); } -#else /* HAVE_XCURSOR */ - meta_verbose ("Not compiled with Xcursor support\n"); -#endif /* !HAVE_XCURSOR */ /* Create the leader window here. Set its properties and * use the timestamp from one of the PropertyNotify events @@ -881,23 +827,15 @@ meta_display_open (void) the_display->last_focus_time = timestamp; the_display->last_user_time = timestamp; the_display->compositor = NULL; - + /* Mutter used to manage all X screens of the display in a single process, but * now it always manages exactly one screen as specified by the DISPLAY - * environment variable. The screens GSList is left for simplicity. + * environment variable. */ - screens = NULL; - i = meta_ui_get_screen_number (); - screen = meta_screen_new (the_display, i, timestamp); - if (screen) - screens = g_slist_prepend (screens, screen); - - the_display->screens = screens; - - if (screens == NULL) + if (!screen) { /* This would typically happen because all the screens already * have window managers. @@ -906,18 +844,17 @@ meta_display_open (void) return FALSE; } - enable_compositor (the_display); - - /* Now manage all existing windows */ - tmp = the_display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_manage_all_windows (screen); + the_display->screen = screen; - tmp = tmp->next; - } + enable_compositor (the_display); + + meta_screen_create_guard_window (screen); + + /* We know that if mutter is running as a Wayland compositor, + * we start out with no windows. + */ + if (!meta_is_wayland_compositor ()) + meta_screen_manage_all_windows (screen); { Window focus; @@ -939,7 +876,7 @@ meta_display_open (void) if (focus == None || focus == PointerRoot) /* Just focus the no_focus_window on the first screen */ meta_display_focus_the_no_focus_window (the_display, - the_display->screens->data, + the_display->screen, timestamp); else { @@ -950,7 +887,7 @@ meta_display_open (void) else /* Just focus the no_focus_window on the first screen */ meta_display_focus_the_no_focus_window (the_display, - the_display->screens->data, + the_display->screen, timestamp); } @@ -992,8 +929,8 @@ meta_display_list_windows (MetaDisplay *display, MetaListWindowsFlags flags) { GSList *winlist; - GSList *tmp; GSList *prev; + GSList *tmp; GHashTableIter iter; gpointer key, value; @@ -1012,6 +949,19 @@ meta_display_list_windows (MetaDisplay *display, winlist = g_slist_prepend (winlist, window); } + g_hash_table_iter_init (&iter, display->wayland_windows); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + MetaWindow *window = value; + + if (!META_IS_WINDOW (window)) + continue; + + if (!window->override_redirect || + (flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0) + winlist = g_slist_prepend (winlist, window); + } + /* Uniquify the list, since both frame windows and plain * windows are in the hash */ @@ -1055,8 +1005,6 @@ void meta_display_close (MetaDisplay *display, guint32 timestamp) { - GSList *tmp; - g_assert (display != NULL); if (display->closing != 0) @@ -1065,9 +1013,6 @@ meta_display_close (MetaDisplay *display, return; } - if (display->error_traps > 0) - meta_bug ("Display closed with error traps pending\n"); - display->closing += 1; meta_prefs_remove_listener (prefs_changed_callback, display); @@ -1080,23 +1025,11 @@ meta_display_close (MetaDisplay *display, if (display->grab_old_window_stacking) g_list_free (display->grab_old_window_stacking); - - /* Stop caring about events */ - meta_ui_remove_event_func (display->xdisplay, - event_callback, - display); - - /* Free all screens */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - meta_screen_free (screen, timestamp); - tmp = tmp->next; - } - g_slist_free (display->screens); - display->screens = NULL; + /* Stop caring about events */ + meta_display_free_events (display); + + meta_screen_free (display->screen, timestamp); #ifdef HAVE_STARTUP_NOTIFICATION if (display->sn_display) @@ -1132,77 +1065,6 @@ meta_display_close (MetaDisplay *display, meta_quit (META_EXIT_SUCCESS); } -/** - * meta_display_screen_for_root: - * @display: a #MetaDisplay - * @xroot: a X window - * - * Return the #MetaScreen corresponding to a specified X root window ID. - * - * Return Value: (transfer none): the screen for the specified root window ID, or %NULL - */ -MetaScreen* -meta_display_screen_for_root (MetaDisplay *display, - Window xroot) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (xroot == screen->xroot) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -MetaScreen* -meta_display_screen_for_xwindow (MetaDisplay *display, - Window xwindow) -{ - XWindowAttributes attr; - int result; - - meta_error_trap_push (display); - attr.screen = NULL; - result = XGetWindowAttributes (display->xdisplay, xwindow, &attr); - meta_error_trap_pop (display); - - /* Note, XGetWindowAttributes is on all kinds of crack - * and returns 1 on success 0 on failure, rather than Success - * on success. - */ - if (result == 0 || attr.screen == NULL) - return NULL; - - return meta_display_screen_for_x_screen (display, attr.screen); -} - -MetaScreen* -meta_display_screen_for_x_screen (MetaDisplay *display, - Screen *xscreen) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (xscreen == screen->xscreen) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - /* Grab/ungrab routines taken from fvwm. * Calling this function will cause X to ignore all other clients until * you ungrab. This may not be quite as bad as it sounds, yet there is @@ -1286,10 +1148,6 @@ meta_get_display (void) return the_display; } -#ifdef WITH_VERBOSE_MODE -static gboolean dump_events = TRUE; -#endif - static gboolean grab_op_is_mouse_only (MetaGrabOp op) { @@ -1343,8 +1201,8 @@ meta_grab_op_is_mouse (MetaGrabOp op) } } -static gboolean -grab_op_is_keyboard (MetaGrabOp op) +gboolean +meta_grab_op_is_keyboard (MetaGrabOp op) { switch (op) { @@ -1409,6 +1267,35 @@ meta_grab_op_is_moving (MetaGrabOp op) } } +gboolean +meta_grab_op_is_clicking (MetaGrabOp grab_op) +{ + switch (grab_op) + { + case META_GRAB_OP_CLICKING_MINIMIZE: + case META_GRAB_OP_CLICKING_MAXIMIZE: + case META_GRAB_OP_CLICKING_UNMAXIMIZE: + case META_GRAB_OP_CLICKING_DELETE: + case META_GRAB_OP_CLICKING_MENU: + case META_GRAB_OP_CLICKING_SHADE: + case META_GRAB_OP_CLICKING_UNSHADE: + case META_GRAB_OP_CLICKING_ABOVE: + case META_GRAB_OP_CLICKING_UNABOVE: + case META_GRAB_OP_CLICKING_STICK: + case META_GRAB_OP_CLICKING_UNSTICK: + return TRUE; + + default: + return FALSE; + } +} + +gboolean +meta_grab_op_is_wayland (MetaGrabOp op) +{ + return (op != META_GRAB_OP_NONE && !meta_grab_op_is_clicking (op)); +} + /** * meta_display_xserver_time_is_before: * @display: a #MetaDisplay @@ -1485,24 +1372,11 @@ meta_display_get_current_time_roundtrip (MetaDisplay *display) timestamp = property_event.xproperty.time; } - sanity_check_timestamps (display, timestamp); + meta_display_sanity_check_timestamps (display, timestamp); return timestamp; } -/** - * meta_display_get_ignored_modifier_mask: - * @display: a #MetaDisplay - * - * Returns: a mask of modifiers that should be ignored - * when matching keybindings to events - */ -unsigned int -meta_display_get_ignored_modifier_mask (MetaDisplay *display) -{ - return display->ignored_modifier_mask; -} - /** * meta_display_add_ignored_crossing_serial: * @display: a #MetaDisplay @@ -1535,37 +1409,6 @@ meta_display_add_ignored_crossing_serial (MetaDisplay *display, display->ignored_crossing_serials[i] = serial; } -static gboolean -crossing_serial_is_ignored (MetaDisplay *display, - unsigned long serial) -{ - int i; - - i = 0; - while (i < N_IGNORED_CROSSING_SERIALS) - { - if (display->ignored_crossing_serials[i] == serial) - return TRUE; - ++i; - } - return FALSE; -} - -static void -reset_ignored_crossing_serials (MetaDisplay *display) -{ - int i; - - i = 0; - while (i < N_IGNORED_CROSSING_SERIALS) - { - display->ignored_crossing_serials[i] = 0; - ++i; - } - - display->ungrab_should_not_cause_focus_window = None; -} - static gboolean window_raise_with_delay_callback (void *data) { @@ -1606,110 +1449,6 @@ window_raise_with_delay_callback (void *data) return FALSE; } -static void -meta_display_mouse_mode_focus (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp) -{ - if (window->type != META_WINDOW_DESKTOP) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s at time %u.\n", window->desc, timestamp); - - meta_window_focus (window, timestamp); - - if (meta_prefs_get_auto_raise ()) - meta_display_queue_autoraise_callback (display, window); - else - meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled\n"); - } - else - { - /* In mouse focus mode, we defocus when the mouse *enters* - * the DESKTOP window, instead of defocusing on LeaveNotify. - * This is because having the mouse enter override-redirect - * child windows unfortunately causes LeaveNotify events that - * we can't distinguish from the mouse actually leaving the - * toplevel window as we expect. But, since we filter out - * EnterNotify events on override-redirect windows, this - * alternative mechanism works great. - */ - if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE && - display->focus_window != NULL) - { - meta_topic (META_DEBUG_FOCUS, - "Unsetting focus from %s due to mouse entering " - "the DESKTOP window\n", - display->focus_window->desc); - meta_display_focus_the_no_focus_window (display, - window->screen, - timestamp); - } - } -} - -static gboolean -window_focus_on_pointer_rest_callback (gpointer data) -{ - MetaFocusData *focus_data; - MetaDisplay *display; - MetaScreen *screen; - MetaWindow *window; - Window root, child; - double root_x, root_y, x, y; - guint32 timestamp; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; - - focus_data = data; - display = focus_data->display; - screen = focus_data->window->screen; - - if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) - goto out; - - meta_error_trap_push (display); - XIQueryPointer (display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - screen->xroot, - &root, &child, - &root_x, &root_y, &x, &y, - &buttons, &mods, &group); - meta_error_trap_pop (display); - free (buttons.mask); - - if (root_x != focus_data->pointer_x || - root_y != focus_data->pointer_y) - { - focus_data->pointer_x = root_x; - focus_data->pointer_y = root_y; - return TRUE; - } - - /* Explicitly check for the overlay window, as get_focus_window_at_point() - * may return windows that extend underneath the chrome (like - * override-redirect or DESKTOP windows) - */ - if (child == meta_get_overlay_window (screen)) - goto out; - - window = - meta_stack_get_default_focus_window_at_point (screen->stack, - screen->active_workspace, - None, root_x, root_y); - - if (window == NULL) - goto out; - - timestamp = meta_display_get_current_time_roundtrip (display); - meta_display_mouse_mode_focus (display, window, timestamp); - - out: - display->focus_timeout_id = 0; - return FALSE; -} - void meta_display_queue_autoraise_callback (MetaDisplay *display, MetaWindow *window) @@ -1730,37 +1469,6 @@ meta_display_queue_autoraise_callback (MetaDisplay *display, display->autoraise_window = window; } -/* The interval, in milliseconds, we use in focus-follows-mouse - * mode to check whether the pointer has stopped moving after a - * crossing event. - */ -#define FOCUS_TIMEOUT_DELAY 25 - -static void -meta_display_queue_focus_callback (MetaDisplay *display, - MetaWindow *window, - int pointer_x, - int pointer_y) -{ - MetaFocusData *focus_data; - - focus_data = g_new (MetaFocusData, 1); - focus_data->display = display; - focus_data->window = window; - focus_data->pointer_x = pointer_x; - focus_data->pointer_y = pointer_y; - - if (display->focus_timeout_id != 0) - g_source_remove (display->focus_timeout_id); - - display->focus_timeout_id = - g_timeout_add_full (G_PRIORITY_DEFAULT, - FOCUS_TIMEOUT_DELAY, - window_focus_on_pointer_rest_callback, - focus_data, - g_free); -} - #if 0 static void handle_net_restack_window (MetaDisplay* display, @@ -1778,7 +1486,7 @@ handle_net_restack_window (MetaDisplay* display, * * Also, unconditionally following these is REALLY stupid--we should * combine this code with the stuff in - * meta_window_configure_request() which is smart about whether to + * meta_window_x11_configure_request() which is smart about whether to * follow the request or do something else (though not smart enough * and is also too stupid to handle the sibling stuff). */ @@ -1799,72 +1507,41 @@ handle_net_restack_window (MetaDisplay* display, } #endif -static XIEvent * -get_input_event (MetaDisplay *display, - XEvent *event) +void +meta_display_sync_wayland_input_focus (MetaDisplay *display) { - if (event->type == GenericEvent && - event->xcookie.extension == display->xinput_opcode) - { - XIEvent *input_event; + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + MetaWindow *focus_window = NULL; - /* NB: GDK event filters already have generic events - * allocated, so no need to do XGetEventData() on our own - */ - input_event = (XIEvent *) event->xcookie.data; + if (meta_grab_op_is_wayland (display->grab_op)) + focus_window = NULL; + else if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow)) + focus_window = NULL; + else if (display->focus_window && display->focus_window->surface) + focus_window = display->focus_window; + else + meta_topic (META_DEBUG_FOCUS, "Focus change has no effect, because there is no matching wayland surface"); - switch (input_event->evtype) - { - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - case XI_Motion: - case XI_ButtonPress: - case XI_ButtonRelease: - if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) - return input_event; - break; - case XI_KeyPress: - case XI_KeyRelease: - if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) - return input_event; - break; - case XI_FocusIn: - case XI_FocusOut: - if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) - return input_event; - break; - case XI_Enter: - case XI_Leave: - if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) - return input_event; - break; -#ifdef HAVE_XI23 - case XI_BarrierHit: - case XI_BarrierLeave: - if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) - return input_event; - break; -#endif /* HAVE_XI23 */ - default: - break; - } - } + meta_wayland_compositor_set_input_focus (compositor, focus_window); - return NULL; + if (meta_grab_op_is_wayland (display->grab_op)) + meta_wayland_pointer_set_focus (&compositor->seat->pointer, NULL); + else + meta_wayland_seat_repick (compositor->seat, NULL); } -static void -update_focus_window (MetaDisplay *display, - MetaWindow *window, - Window xwindow, - gulong serial, - gboolean focused_by_us) +void +meta_display_update_focus_window (MetaDisplay *display, + MetaWindow *window, + Window xwindow, + gulong serial, + gboolean focused_by_us) { display->focus_serial = serial; display->focused_by_us = focused_by_us; - if (display->focus_xwindow == xwindow) + if (display->focus_xwindow == xwindow && + display->focus_window == window) return; if (display->focus_window) @@ -1898,13 +1575,16 @@ update_focus_window (MetaDisplay *display, else meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial); + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); + g_object_notify (G_OBJECT (display), "focus-window"); meta_display_update_active_window_hint (display); } -static gboolean -timestamp_too_old (MetaDisplay *display, - guint32 *timestamp) +gboolean +meta_display_timestamp_too_old (MetaDisplay *display, + guint32 *timestamp) { /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow * us to sanity check the timestamp here and ensure it doesn't correspond to @@ -1934,17 +1614,15 @@ timestamp_too_old (MetaDisplay *display, static void request_xserver_input_focus_change (MetaDisplay *display, MetaScreen *screen, + MetaWindow *meta_window, Window xwindow, guint32 timestamp) { - MetaWindow *meta_window; gulong serial; - if (timestamp_too_old (display, ×tamp)) + if (meta_display_timestamp_too_old (display, ×tamp)) return; - meta_window = meta_display_lookup_x_window (display, xwindow); - meta_error_trap_push (display); /* In order for mutter to know that the focus request succeeded, we track @@ -1970,1830 +1648,20 @@ request_xserver_input_focus_change (MetaDisplay *display, meta_display_ungrab (display); - update_focus_window (display, - meta_window, - xwindow, - serial, - TRUE); + meta_display_update_focus_window (display, + meta_window, + xwindow, + serial, + TRUE); meta_error_trap_pop (display); display->last_focus_time = timestamp; - display->active_screen = screen; if (meta_window == NULL || meta_window != display->autoraise_window) meta_display_remove_autoraise_callback (display); } -static void -handle_window_focus_event (MetaDisplay *display, - MetaWindow *window, - XIEnterEvent *event, - unsigned long serial) -{ - MetaWindow *focus_window; -#ifdef WITH_VERBOSE_MODE - const char *window_type; - - /* Note the event can be on either the window or the frame, - * we focus the frame for shaded windows - */ - if (window) - { - if (event->event == window->xwindow) - window_type = "client window"; - else if (window->frame && event->event == window->frame->xwindow) - window_type = "frame window"; - else - window_type = "unknown client window"; - } - else if (meta_display_xwindow_is_a_no_focus_window (display, event->event)) - window_type = "no_focus_window"; - else if (meta_display_screen_for_root (display, event->event)) - window_type = "root window"; - else - window_type = "unknown window"; - - meta_topic (META_DEBUG_FOCUS, - "Focus %s event received on %s 0x%lx (%s) " - "mode %s detail %s serial %lu\n", - event->evtype == XI_FocusIn ? "in" : - event->evtype == XI_FocusOut ? "out" : - "???", - window ? window->desc : "", - event->event, window_type, - meta_event_mode_to_string (event->mode), - meta_event_detail_to_string (event->mode), - event->serial); -#endif - - /* FIXME our pointer tracking is broken; see how - * gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c - * for how to handle it the correct way. In brief you need to track - * pointer focus and regular focus, and handle EnterNotify in - * PointerRoot mode with no window manager. However as noted above, - * accurate focus tracking will break things because we want to keep - * windows "focused" when using keybindings on them, and also we - * sometimes "focus" a window by focusing its frame or - * no_focus_window; so this all needs rethinking massively. - * - * My suggestion is to change it so that we clearly separate - * actual keyboard focus tracking using the xterm algorithm, - * and mutter's "pretend" focus window, and go through all - * the code and decide which one should be used in each place; - * a hard bit is deciding on a policy for that. - * - * http://bugzilla.gnome.org/show_bug.cgi?id=90382 - */ - - /* We ignore grabs, though this is questionable. It may be better to - * increase the intelligence of the focus window tracking. - * - * The problem is that keybindings for windows are done with - * XGrabKey, which means focus_window disappears and the front of - * the MRU list gets confused from what the user expects once a - * keybinding is used. - */ - - if (event->mode == XINotifyGrab || - event->mode == XINotifyUngrab || - /* From WindowMaker, ignore all funky pointer root events */ - event->detail > XINotifyNonlinearVirtual) - { - meta_topic (META_DEBUG_FOCUS, - "Ignoring focus event generated by a grab or other weirdness\n"); - return; - } - - if (event->evtype == XI_FocusIn) - { - display->server_focus_window = event->event; - display->server_focus_serial = serial; - focus_window = window; - } - else if (event->evtype == XI_FocusOut) - { - if (event->detail == XINotifyInferior) - { - /* This event means the client moved focus to a subwindow */ - meta_topic (META_DEBUG_FOCUS, - "Ignoring focus out with NotifyInferior\n"); - return; - } - - display->server_focus_window = None; - display->server_focus_serial = serial; - focus_window = NULL; - } - else - g_return_if_reached (); - - /* If display->focused_by_us, then the focus_serial will be used only - * for a focus change we made and have already accounted for. - * (See request_xserver_input_focus_change().) Otherwise, we can get - * multiple focus events with the same serial. - */ - if (display->server_focus_serial > display->focus_serial || - (!display->focused_by_us && - display->server_focus_serial == display->focus_serial)) - { - update_focus_window (display, - focus_window, - focus_window ? focus_window->xwindow : None, - display->server_focus_serial, - FALSE); - } -} - -static gboolean -window_has_xwindow (MetaWindow *window, - Window xwindow) -{ - if (window->xwindow == xwindow) - return TRUE; - - if (window->frame && window->frame->xwindow == xwindow) - return TRUE; - - return FALSE; -} - -/** - * event_callback: - * @event: The event that just happened - * @data: The #MetaDisplay that events are coming from, cast to a gpointer - * so that it can be sent to a callback - * - * This is the most important function in the whole program. It is the heart, - * it is the nexus, it is the Grand Central Station of Mutter's world. - * When we create a #MetaDisplay, we ask GDK to pass *all* events for *all* - * windows to this function. So every time anything happens that we might - * want to know about, this function gets called. You see why it gets a bit - * busy around here. Most of this function is a ginormous switch statement - * dealing with all the kinds of events that might turn up. - */ -static gboolean -event_callback (XEvent *event, - gpointer data) -{ - MetaWindow *window; - MetaWindow *property_for_window; - MetaDisplay *display; - Window modified; - gboolean frame_was_receiver; - gboolean bypass_compositor; - gboolean filter_out_event; - XIEvent *input_event; - MetaMonitorManager *monitor; - MetaScreen *screen; - - display = data; - -#ifdef WITH_VERBOSE_MODE - if (dump_events) - meta_spew_event (display, event); -#endif - -#ifdef HAVE_STARTUP_NOTIFICATION - sn_display_process_event (display->sn_display, event); -#endif - - /* Intercept XRandR events early and don't attempt any - processing for them. We still let them through to Gdk though, - so it can update its own internal state. - */ - monitor = meta_monitor_manager_get (); - if (meta_monitor_manager_handle_xevent (monitor, event)) - return FALSE; - - bypass_compositor = FALSE; - filter_out_event = FALSE; - display->current_time = event_get_time (display, event); - display->monitor_cache_invalidated = TRUE; - - if (display->focused_by_us && - event->xany.serial > display->focus_serial && - display->focus_window && - !window_has_xwindow (display->focus_window, display->server_focus_window)) - { - meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n", - display->focus_window->desc); - update_focus_window (display, - meta_display_lookup_x_window (display, display->server_focus_window), - display->server_focus_window, - display->server_focus_serial, - FALSE); - } - - screen = meta_display_screen_for_root (display, event->xany.window); - if (screen) - { - if (meta_screen_handle_xevent (screen, event)) - return TRUE; - } - - modified = event_get_modified_window (display, event); - - input_event = get_input_event (display, event); - - if (event->type == UnmapNotify) - { - if (meta_ui_window_should_not_cause_focus (display->xdisplay, - modified)) - { - meta_display_add_ignored_crossing_serial (display, event->xany.serial); - meta_topic (META_DEBUG_FOCUS, - "Adding EnterNotify serial %lu to ignored focus serials\n", - event->xany.serial); - } - } - else if (input_event && - input_event->evtype == XI_Leave && - ((XILeaveEvent *)input_event)->mode == XINotifyUngrab && - modified == display->ungrab_should_not_cause_focus_window) - { - meta_display_add_ignored_crossing_serial (display, event->xany.serial); - meta_topic (META_DEBUG_FOCUS, - "Adding LeaveNotify serial %lu to ignored focus serials\n", - event->xany.serial); - } - - if (modified != None) - window = meta_display_lookup_x_window (display, modified); - else - window = NULL; - - /* We only want to respond to _NET_WM_USER_TIME property notify - * events on _NET_WM_USER_TIME_WINDOW windows; in particular, - * responding to UnmapNotify events is kind of bad. - */ - property_for_window = NULL; - if (window && modified == window->user_time_window) - { - property_for_window = window; - window = NULL; - } - - - frame_was_receiver = FALSE; - if (window && - window->frame && - modified == window->frame->xwindow) - { - /* Note that if the frame and the client both have an - * XGrabButton (as is normal with our setup), the event - * goes to the frame. - */ - frame_was_receiver = TRUE; - meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n", - window->desc); - } - -#ifdef HAVE_XSYNC - if (META_DISPLAY_HAS_XSYNC (display) && - event->type == (display->xsync_event_base + XSyncAlarmNotify)) - { - MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display, - ((XSyncAlarmNotifyEvent*)event)->alarm); - - if (alarm_window != NULL) - { - XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value; - gint64 new_counter_value; - new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32); - meta_window_update_sync_request_counter (alarm_window, new_counter_value); - filter_out_event = TRUE; /* GTK doesn't want to see this really */ - } - else - meta_idle_monitor_handle_xevent_all (event); - } -#endif /* HAVE_XSYNC */ - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - filter_out_event = TRUE; /* GTK doesn't want to see this really */ - - if (window && !frame_was_receiver) - { - XShapeEvent *sev = (XShapeEvent*) event; - - if (sev->kind == ShapeBounding) - meta_window_update_shape_region_x11 (window); - } - else - { - meta_topic (META_DEBUG_SHAPES, - "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n", - window ? window->desc : "(none)", - frame_was_receiver); - } - } -#endif /* HAVE_SHAPE */ - - if (input_event != NULL) - { - XIDeviceEvent *device_event = (XIDeviceEvent *) input_event; - XIEnterEvent *enter_event = (XIEnterEvent *) input_event; - gint button = 0; - - if (window && !window->override_redirect && - ((input_event->evtype == XI_KeyPress) || (input_event->evtype == XI_ButtonPress))) - { - if (CurrentTime == display->current_time) - { - /* We can't use missing (i.e. invalid) timestamps to set user time, - * nor do we want to use them to sanity check other timestamps. - * See bug 313490 for more details. - */ - meta_warning ("Event has no timestamp! You may be using a broken " - "program such as xse. Please ask the authors of that " - "program to fix it.\n"); - } - else - { - meta_window_set_user_time (window, display->current_time); - sanity_check_timestamps (display, display->current_time); - } - } - - switch (input_event->evtype) - { - case XI_KeyPress: - case XI_KeyRelease: - - /* For key events, it's important to enforce single-handling, or - * we can get into a confused state. So if a keybinding is - * handled (because it's one of our hot-keys, or because we are - * in a keyboard-grabbed mode like moving a window, we don't - * want to pass the key event to the compositor or GTK+ at all. - */ - if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event)) - filter_out_event = bypass_compositor = TRUE; - break; - case XI_TouchBegin: - /* Filter out non-pointer-emulating touches */ - if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0) - break; - - /* Fall through */ - case XI_ButtonPress: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - display->overlay_key_only_pressed = FALSE; - - if (input_event->evtype == XI_ButtonPress) - { - if (device_event->detail == 4 || device_event->detail == 5) - /* Scrollwheel event, do nothing and deliver event to compositor below */ - break; - else - button = device_event->detail; - } - else if (input_event->evtype == XI_TouchBegin) - button = 1; - - if ((window && - meta_grab_op_is_mouse (display->grab_op) && - (device_event->mods.effective & display->window_grab_modifiers) && - display->grab_button != button && - display->grab_window == window) || - grab_op_is_keyboard (display->grab_op)) - { - meta_topic (META_DEBUG_WINDOW_OPS, - "Ending grab op %u on window %s due to button press\n", - display->grab_op, - (display->grab_window ? - display->grab_window->desc : - "none")); - meta_display_end_grab_op (display, - device_event->time); - } - else if (window && display->grab_op == META_GRAB_OP_NONE) - { - gboolean begin_move = FALSE; - unsigned int grab_mask; - gboolean unmodified; - - grab_mask = display->window_grab_modifiers; - if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS")) - grab_mask |= ControlMask; - - /* Two possible sources of an unmodified event; one is a - * client that's letting button presses pass through to the - * frame, the other is our focus_window_grab on unmodified - * button 1. So for all such events we focus the window. - */ - unmodified = (device_event->mods.effective & grab_mask) == 0; - - if (unmodified || button == 1) - { - /* don't focus if frame received, will be lowered in - * frames.c or special-cased if the click was on a - * minimize/close button. - */ - if (!frame_was_receiver) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - else - meta_topic (META_DEBUG_FOCUS, - "Not raising window on click due to don't-raise-on-click option\n"); - - /* Don't focus panels--they must explicitly request focus. - * See bug 160470 - */ - if (window->type != META_WINDOW_DOCK) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s due to unmodified button %u press (display.c)\n", - window->desc, button); - meta_window_focus (window, device_event->time); - } - else - /* However, do allow terminals to lose focus due to new - * window mappings after the user clicks on a panel. - */ - display->allow_terminal_deactivation = TRUE; - } - - /* you can move on alt-click but not on - * the click-to-focus - */ - if (!unmodified) - begin_move = TRUE; - } - else if (!unmodified && button == meta_prefs_get_mouse_button_resize()) - { - if (window->has_resize_func) - { - gboolean north, south; - gboolean west, east; - MetaRectangle frame_rect; - MetaGrabOp op; - - meta_window_get_frame_rect (window, &frame_rect); - - west = device_event->root_x < (frame_rect.x + 1 * frame_rect.width / 3); - east = device_event->root_x > (frame_rect.x + 2 * frame_rect.width / 3); - north = device_event->root_y < (frame_rect.y + 1 * frame_rect.height / 3); - south = device_event->root_y > (frame_rect.y + 2 * frame_rect.height / 3); - - if (north && west) - op = META_GRAB_OP_RESIZING_NW; - else if (north && east) - op = META_GRAB_OP_RESIZING_NE; - else if (south && west) - op = META_GRAB_OP_RESIZING_SW; - else if (south && east) - op = META_GRAB_OP_RESIZING_SE; - else if (north) - op = META_GRAB_OP_RESIZING_N; - else if (west) - op = META_GRAB_OP_RESIZING_W; - else if (east) - op = META_GRAB_OP_RESIZING_E; - else if (south) - op = META_GRAB_OP_RESIZING_S; - else /* Middle region is no-op to avoid user triggering wrong action */ - op = META_GRAB_OP_NONE; - - if (op != META_GRAB_OP_NONE) - meta_display_begin_grab_op (display, - window->screen, - window, - op, - TRUE, - FALSE, - button, - 0, - device_event->time, - device_event->root_x, - device_event->root_y); - } - } - else if (button == meta_prefs_get_mouse_button_menu()) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_show_menu (window, - device_event->root_x, - device_event->root_y, - button, - device_event->time); - } - - if (!frame_was_receiver && unmodified) - { - /* This is from our synchronous grab since - * it has no modifiers and was on the client window - */ - - meta_verbose ("Allowing events time %u\n", - (unsigned int)device_event->time); - - XIAllowEvents (display->xdisplay, device_event->deviceid, - XIReplayDevice, device_event->time); - } - - if (begin_move && window->has_move_func) - { - meta_display_begin_grab_op (display, - window->screen, - window, - META_GRAB_OP_MOVING, - TRUE, - FALSE, - button, - 0, - device_event->time, - device_event->root_x, - device_event->root_y); - } - } - break; - case XI_ButtonRelease: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - display->overlay_key_only_pressed = FALSE; - - if (display->grab_window == window && - meta_grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, device_event); - break; - case XI_Motion: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - if (display->grab_window == window && - meta_grab_op_is_mouse (display->grab_op)) - meta_window_handle_mouse_grab_op_event (window, device_event); - break; - case XI_Enter: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - /* If the mouse switches screens, active the default window on the new - * screen; this will make keybindings and workspace-launched items - * actually appear on the right screen. - */ - { - MetaScreen *new_screen = - meta_display_screen_for_root (display, enter_event->root); - - if (new_screen != NULL && display->active_screen != new_screen) - meta_workspace_focus_default_window (new_screen->active_workspace, - NULL, - enter_event->time); - } - - /* Check if we've entered a window; do this even if window->has_focus to - * avoid races. - */ - if (window && !crossing_serial_is_ignored (display, event->xany.serial) && - enter_event->mode != XINotifyGrab && - enter_event->mode != XINotifyUngrab && - enter_event->detail != XINotifyInferior && - meta_display_focus_sentinel_clear (display)) - { - switch (meta_prefs_get_focus_mode ()) - { - case G_DESKTOP_FOCUS_MODE_SLOPPY: - case G_DESKTOP_FOCUS_MODE_MOUSE: - display->mouse_mode = TRUE; - if (window->type != META_WINDOW_DOCK) - { - meta_topic (META_DEBUG_FOCUS, - "Queuing a focus change for %s due to " - "enter notify with serial %lu at time %lu, " - "and setting display->mouse_mode to TRUE.\n", - window->desc, - event->xany.serial, - enter_event->time); - - if (meta_prefs_get_focus_change_on_pointer_rest()) - meta_display_queue_focus_callback (display, window, - enter_event->root_x, - enter_event->root_y); - else - meta_display_mouse_mode_focus (display, window, - enter_event->time); - - /* stop ignoring stuff */ - reset_ignored_crossing_serials (display); - } - break; - case G_DESKTOP_FOCUS_MODE_CLICK: - break; - } - - if (window->type == META_WINDOW_DOCK) - meta_window_raise (window); - } - break; - case XI_Leave: - if (display->grab_op == META_GRAB_OP_COMPOSITOR) - break; - - if (window != NULL) - { - if (window->type == META_WINDOW_DOCK && - enter_event->mode != XINotifyGrab && - enter_event->mode != XINotifyUngrab && - !window->has_focus) - meta_window_lower (window); - } - break; - case XI_FocusIn: - case XI_FocusOut: - /* libXi does not properly copy the serial to the XIEnterEvent, so pull it - * from the parent XAnyEvent. - * See: https://bugs.freedesktop.org/show_bug.cgi?id=64687 - */ - handle_window_focus_event (display, window, enter_event, event->xany.serial); - if (!window) - { - /* Check if the window is a root window. */ - MetaScreen *screen = - meta_display_screen_for_root(display, - enter_event->event); - if (screen == NULL) - break; - - if (enter_event->evtype == XI_FocusIn && - enter_event->mode == XINotifyDetailNone) - { - meta_topic (META_DEBUG_FOCUS, - "Focus got set to None, probably due to " - "brain-damage in the X protocol (see bug " - "125492). Setting the default focus window.\n"); - meta_workspace_focus_default_window (screen->active_workspace, - NULL, - meta_display_get_current_time_roundtrip (display)); - } - else if (enter_event->evtype == XI_FocusIn && - enter_event->mode == XINotifyNormal && - enter_event->detail == XINotifyInferior) - { - meta_topic (META_DEBUG_FOCUS, - "Focus got set to root window, probably due to " - "gnome-session logout dialog usage (see bug " - "153220). Setting the default focus window.\n"); - meta_workspace_focus_default_window (screen->active_workspace, - NULL, - meta_display_get_current_time_roundtrip (display)); - } - - } - break; -#ifdef HAVE_XI23 - case XI_BarrierHit: - case XI_BarrierLeave: - if (meta_display_process_barrier_event (display, (XIBarrierEvent *) input_event)) - filter_out_event = bypass_compositor = TRUE; - break; -#endif /* HAVE_XI23 */ - case XI_TouchUpdate: - case XI_TouchEnd: - /* Filter out non-pointer-emulating touches */ - if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0) - break; - - /* Currently unhandled, if any grab_op is started through XI_TouchBegin, - * the XIGrabDevice() evmask drops touch events, so only emulated - * XI_Motions and XI_ButtonRelease will follow. - */ - g_assert_not_reached (); - break; - } - } - else - { - switch (event->type) - { - case KeymapNotify: - break; - case Expose: - break; - case GraphicsExpose: - break; - case NoExpose: - break; - case VisibilityNotify: - break; - case CreateNotify: - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xcreatewindow.parent); - if (screen) - meta_stack_tracker_create_event (screen->stack_tracker, - &event->xcreatewindow); - } - break; - - case DestroyNotify: - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xdestroywindow.event); - if (screen) - meta_stack_tracker_destroy_event (screen->stack_tracker, - &event->xdestroywindow); - } - if (window) - { - /* FIXME: It sucks that DestroyNotify events don't come with - * a timestamp; could we do something better here? Maybe X - * will change one day? - */ - guint32 timestamp; - timestamp = meta_display_get_current_time_roundtrip (display); - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window == window) - meta_display_end_grab_op (display, timestamp); - - if (frame_was_receiver) - { - meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", - window->frame->xwindow); - meta_error_trap_push (display); - meta_window_destroy_frame (window->frame->window); - meta_error_trap_pop (display); - } - else - { - /* Unmanage destroyed window */ - meta_window_unmanage (window, timestamp); - window = NULL; - } - } - break; - case UnmapNotify: - if (window) - { - /* FIXME: It sucks that UnmapNotify events don't come with - * a timestamp; could we do something better here? Maybe X - * will change one day? - */ - guint32 timestamp; - timestamp = meta_display_get_current_time_roundtrip (display); - - if (display->grab_op != META_GRAB_OP_NONE && - display->grab_window == window && - window->frame == NULL) - meta_display_end_grab_op (display, timestamp); - - if (!frame_was_receiver) - { - if (window->unmaps_pending == 0) - { - meta_topic (META_DEBUG_WINDOW_STATE, - "Window %s withdrawn\n", - window->desc); - - /* Unmanage withdrawn window */ - window->withdrawn = TRUE; - meta_window_unmanage (window, timestamp); - window = NULL; - } - else - { - window->unmaps_pending -= 1; - meta_topic (META_DEBUG_WINDOW_STATE, - "Received pending unmap, %d now pending\n", - window->unmaps_pending); - } - } - } - break; - case MapNotify: - /* NB: override redirect windows wont cause a map request so we - * watch out for map notifies against any root windows too if a - * compositor is enabled: */ - if (display->compositor && window == NULL - && meta_display_screen_for_root (display, event->xmap.event)) - { - window = meta_window_new (display, event->xmap.window, - FALSE, META_COMP_EFFECT_CREATE); - } - break; - case MapRequest: - if (window == NULL) - { - window = meta_window_new (display, event->xmaprequest.window, - FALSE, META_COMP_EFFECT_CREATE); - } - /* if frame was receiver it's some malicious send event or something */ - else if (!frame_was_receiver && window) - { - meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n", - window->desc, window->mapped, window->minimized); - if (window->minimized) - { - meta_window_unminimize (window); - if (window->workspace != window->screen->active_workspace) - { - meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n", - window->mapped, window->minimized); - meta_window_change_workspace (window, - window->screen->active_workspace); - } - } - } - break; - case ReparentNotify: - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xconfigure.event); - if (screen) - meta_stack_tracker_reparent_event (screen->stack_tracker, - &event->xreparent); - } - break; - case ConfigureNotify: - if (event->xconfigure.event != event->xconfigure.window) - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xconfigure.event); - if (screen) - meta_stack_tracker_configure_event (screen->stack_tracker, - &event->xconfigure); - } - - if (window && window->override_redirect) - meta_window_configure_notify (window, &event->xconfigure); - - break; - case ConfigureRequest: - /* This comment and code is found in both twm and fvwm */ - /* - * According to the July 27, 1988 ICCCM draft, we should ignore size and - * position fields in the WM_NORMAL_HINTS property when we map a window. - * Instead, we'll read the current geometry. Therefore, we should respond - * to configuration requests for windows which have never been mapped. - */ - if (window == NULL) - { - unsigned int xwcm; - XWindowChanges xwc; - - xwcm = event->xconfigurerequest.value_mask & - (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); - - xwc.x = event->xconfigurerequest.x; - xwc.y = event->xconfigurerequest.y; - xwc.width = event->xconfigurerequest.width; - xwc.height = event->xconfigurerequest.height; - xwc.border_width = event->xconfigurerequest.border_width; - - meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n", - xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width); - meta_error_trap_push (display); - XConfigureWindow (display->xdisplay, event->xconfigurerequest.window, - xwcm, &xwc); - meta_error_trap_pop (display); - } - else - { - if (!frame_was_receiver) - meta_window_configure_request (window, event); - } - break; - case GravityNotify: - break; - case ResizeRequest: - break; - case CirculateNotify: - break; - case CirculateRequest: - break; - case PropertyNotify: - { - MetaGroup *group; - MetaScreen *screen; - - if (window && !frame_was_receiver) - meta_window_property_notify (window, event); - else if (property_for_window && !frame_was_receiver) - meta_window_property_notify (property_for_window, event); - - group = meta_display_lookup_group (display, - event->xproperty.window); - if (group != NULL) - meta_group_property_notify (group, event); - - screen = NULL; - if (window == NULL && - group == NULL) /* window/group != NULL means it wasn't a root window */ - screen = meta_display_screen_for_root (display, - event->xproperty.window); - - if (screen != NULL) - { - if (event->xproperty.atom == - display->atom__NET_DESKTOP_LAYOUT) - meta_screen_update_workspace_layout (screen); - else if (event->xproperty.atom == - display->atom__NET_DESKTOP_NAMES) - meta_screen_update_workspace_names (screen); -#if 0 - else if (event->xproperty.atom == - display->atom__NET_RESTACK_WINDOW) - handle_net_restack_window (display, event); -#endif - - /* we just use this property as a sentinel to avoid - * certain race conditions. See the comment for the - * sentinel_counter variable declaration in display.h - */ - if (event->xproperty.atom == - display->atom__MUTTER_SENTINEL) - { - meta_display_decrement_focus_sentinel (display); - } - } - } - break; - case SelectionClear: - /* do this here instead of at end of function - * so we can return - */ - - /* FIXME: Clearing display->current_time here makes no sense to - * me; who put this here and why? - */ - display->current_time = CurrentTime; - - process_selection_clear (display, event); - /* Note that processing that may have resulted in - * closing the display... so return right away. - */ - return FALSE; - case SelectionRequest: - process_selection_request (display, event); - break; - case SelectionNotify: - break; - case ColormapNotify: - if (window && !frame_was_receiver) - window->colormap = event->xcolormap.colormap; - break; - case ClientMessage: - if (window) - { - if (!frame_was_receiver) - meta_window_client_message (window, event); - } - else - { - MetaScreen *screen; - - screen = meta_display_screen_for_root (display, - event->xclient.window); - - if (screen) - { - if (event->xclient.message_type == - display->atom__NET_CURRENT_DESKTOP) - { - int space; - MetaWorkspace *workspace; - guint32 time; - - space = event->xclient.data.l[0]; - time = event->xclient.data.l[1]; - - meta_verbose ("Request to change current workspace to %d with " - "specified timestamp of %u\n", - space, time); - - workspace = - meta_screen_get_workspace_by_index (screen, - space); - - /* Handle clients using the older version of the spec... */ - if (time == 0 && workspace) - { - meta_warning ("Received a NET_CURRENT_DESKTOP message " - "from a broken (outdated) client who sent " - "a 0 timestamp\n"); - time = meta_display_get_current_time_roundtrip (display); - } - - if (workspace) - meta_workspace_activate (workspace, time); - else - meta_verbose ("Don't know about workspace %d\n", space); - } - else if (event->xclient.message_type == - display->atom__NET_NUMBER_OF_DESKTOPS) - { - int num_spaces; - - num_spaces = event->xclient.data.l[0]; - - meta_verbose ("Request to set number of workspaces to %d\n", - num_spaces); - - meta_prefs_set_num_workspaces (num_spaces); - } - else if (event->xclient.message_type == - display->atom__NET_SHOWING_DESKTOP) - { - gboolean showing_desktop; - guint32 timestamp; - - showing_desktop = event->xclient.data.l[0] != 0; - /* FIXME: Braindead protocol doesn't have a timestamp */ - timestamp = meta_display_get_current_time_roundtrip (display); - meta_verbose ("Request to %s desktop\n", - showing_desktop ? "show" : "hide"); - - if (showing_desktop) - meta_screen_show_desktop (screen, timestamp); - else - { - meta_screen_unshow_desktop (screen); - meta_workspace_focus_default_window (screen->active_workspace, NULL, timestamp); - } - } - else if (event->xclient.message_type == - display->atom_WM_PROTOCOLS) - { - meta_verbose ("Received WM_PROTOCOLS message\n"); - - if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING) - { - process_pong_message (display, event); - - /* We don't want ping reply events going into - * the GTK+ event loop because gtk+ will treat - * them as ping requests and send more replies. - */ - filter_out_event = TRUE; - } - } - } - - if (event->xclient.message_type == - display->atom__NET_REQUEST_FRAME_EXTENTS) - { - meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n"); - process_request_frame_extents (display, event); - } - } - break; - case MappingNotify: - { - gboolean ignore_current; - - ignore_current = FALSE; - - /* Check whether the next event is an identical MappingNotify - * event. If it is, ignore the current event, we'll update - * when we get the next one. - */ - if (XPending (display->xdisplay)) - { - XEvent next_event; - - XPeekEvent (display->xdisplay, &next_event); - - if (next_event.type == MappingNotify && - next_event.xmapping.request == event->xmapping.request) - ignore_current = TRUE; - } - - if (!ignore_current) - { - /* Let XLib know that there is a new keyboard mapping. - */ - XRefreshKeyboardMapping (&event->xmapping); - meta_display_process_mapping_event (display, event); - } - } - break; - default: -#ifdef HAVE_XKB - if (event->type == display->xkb_base_event_type) - { - XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; - - switch (xkb_ev->xkb_type) - { - case XkbBellNotify: - if (XSERVER_TIME_IS_BEFORE(display->last_bell_time, - xkb_ev->time - 100)) - { - display->last_bell_time = xkb_ev->time; - meta_bell_notify (display, xkb_ev); - } - break; - case XkbNewKeyboardNotify: - case XkbMapNotify: - if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID) - meta_display_process_mapping_event (display, event); - break; - } - } -#endif - break; - } - } - - if (display->compositor && !bypass_compositor) - { - if (meta_compositor_process_event (display->compositor, - event, - window)) - filter_out_event = TRUE; - } - - display->current_time = CurrentTime; - return filter_out_event; -} - -/* Return the window this has to do with, if any, rather - * than the frame or root window that was selecting - * for substructure - */ -static Window -event_get_modified_window (MetaDisplay *display, - XEvent *event) -{ - XIEvent *input_event = get_input_event (display, event); - - if (input_event) - { - switch (input_event->evtype) - { - case XI_Motion: - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_KeyPress: - case XI_KeyRelease: - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - return ((XIDeviceEvent *) input_event)->event; - case XI_FocusIn: - case XI_FocusOut: - case XI_Enter: - case XI_Leave: - return ((XIEnterEvent *) input_event)->event; -#ifdef HAVE_XI23 - case XI_BarrierHit: - case XI_BarrierLeave: - return ((XIBarrierEvent *) input_event)->event; -#endif /* HAVE_XI23 */ - } - } - - switch (event->type) - { - case KeymapNotify: - case Expose: - case GraphicsExpose: - case NoExpose: - case VisibilityNotify: - case ResizeRequest: - case PropertyNotify: - case SelectionClear: - case SelectionRequest: - case SelectionNotify: - case ColormapNotify: - case ClientMessage: - return event->xany.window; - - case CreateNotify: - return event->xcreatewindow.window; - - case DestroyNotify: - return event->xdestroywindow.window; - - case UnmapNotify: - return event->xunmap.window; - - case MapNotify: - return event->xmap.window; - - case MapRequest: - return event->xmaprequest.window; - - case ReparentNotify: - return event->xreparent.window; - - case ConfigureNotify: - return event->xconfigure.window; - - case ConfigureRequest: - return event->xconfigurerequest.window; - - case GravityNotify: - return event->xgravity.window; - - case CirculateNotify: - return event->xcirculate.window; - - case CirculateRequest: - return event->xcirculaterequest.window; - - case MappingNotify: - return None; - - default: -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - XShapeEvent *sev = (XShapeEvent*) event; - return sev->window; - } -#endif - - return None; - } -} - -static guint32 -event_get_time (MetaDisplay *display, - XEvent *event) -{ - XIEvent *input_event = get_input_event (display, event); - - if (input_event) - return input_event->time; - - switch (event->type) - { - case PropertyNotify: - return event->xproperty.time; - - case SelectionClear: - case SelectionRequest: - case SelectionNotify: - return event->xselection.time; - - case KeymapNotify: - case Expose: - case GraphicsExpose: - case NoExpose: - case MapNotify: - case UnmapNotify: - case VisibilityNotify: - case ResizeRequest: - case ColormapNotify: - case ClientMessage: - case CreateNotify: - case DestroyNotify: - case MapRequest: - case ReparentNotify: - case ConfigureNotify: - case ConfigureRequest: - case GravityNotify: - case CirculateNotify: - case CirculateRequest: - case MappingNotify: - default: - return CurrentTime; - } -} - -#ifdef WITH_VERBOSE_MODE -const char* -meta_event_detail_to_string (int d) -{ - const char *detail = "???"; - switch (d) - { - /* We are an ancestor in the A<->B focus change relationship */ - case XINotifyAncestor: - detail = "NotifyAncestor"; - break; - case XINotifyDetailNone: - detail = "NotifyDetailNone"; - break; - /* We are a descendant in the A<->B focus change relationship */ - case XINotifyInferior: - detail = "NotifyInferior"; - break; - case XINotifyNonlinear: - detail = "NotifyNonlinear"; - break; - case XINotifyNonlinearVirtual: - detail = "NotifyNonlinearVirtual"; - break; - case XINotifyPointer: - detail = "NotifyPointer"; - break; - case XINotifyPointerRoot: - detail = "NotifyPointerRoot"; - break; - case XINotifyVirtual: - detail = "NotifyVirtual"; - break; - } - - return detail; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -const char* -meta_event_mode_to_string (int m) -{ - const char *mode = "???"; - switch (m) - { - case XINotifyNormal: - mode = "NotifyNormal"; - break; - case XINotifyGrab: - mode = "NotifyGrab"; - break; - case XINotifyUngrab: - mode = "NotifyUngrab"; - break; - case XINotifyWhileGrabbed: - mode = "NotifyWhileGrabbed"; - break; - } - - return mode; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static const char* -stack_mode_to_string (int mode) -{ - switch (mode) - { - case Above: - return "Above"; - case Below: - return "Below"; - case TopIf: - return "TopIf"; - case BottomIf: - return "BottomIf"; - case Opposite: - return "Opposite"; - } - - return "Unknown"; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef HAVE_XSYNC -#ifdef WITH_VERBOSE_MODE -static gint64 -sync_value_to_64 (const XSyncValue *value) -{ - gint64 v; - - v = XSyncValueLow32 (*value); - v |= (((gint64)XSyncValueHigh32 (*value)) << 32); - - return v; -} -#endif /* WITH_VERBOSE_MODE */ - -#ifdef WITH_VERBOSE_MODE -static const char* -alarm_state_to_string (XSyncAlarmState state) -{ - switch (state) - { - case XSyncAlarmActive: - return "Active"; - case XSyncAlarmInactive: - return "Inactive"; - case XSyncAlarmDestroyed: - return "Destroyed"; - default: - return "(unknown)"; - } -} -#endif /* WITH_VERBOSE_MODE */ - -#endif /* HAVE_XSYNC */ - -#ifdef WITH_VERBOSE_MODE -static void -meta_spew_xi2_event (MetaDisplay *display, - XIEvent *input_event, - const char **name_p, - char **extra_p) -{ - const char *name = NULL; - char *extra = NULL; - - XIDeviceEvent *device_event = (XIDeviceEvent *) input_event; - XIEnterEvent *enter_event = (XIEnterEvent *) input_event; - - switch (input_event->evtype) - { - case XI_Motion: - name = "XI_Motion"; - break; - case XI_ButtonPress: - name = "XI_ButtonPress"; - break; - case XI_ButtonRelease: - name = "XI_ButtonRelease"; - break; - case XI_KeyPress: - name = "XI_KeyPress"; - break; - case XI_KeyRelease: - name = "XI_KeyRelease"; - break; - case XI_FocusIn: - name = "XI_FocusIn"; - break; - case XI_FocusOut: - name = "XI_FocusOut"; - break; - case XI_Enter: - name = "XI_Enter"; - break; - case XI_Leave: - name = "XI_Leave"; - break; - case XI_TouchBegin: - name = "XI_TouchBegin"; - break; - case XI_TouchUpdate: - name = "XI_TouchUpdate"; - break; - case XI_TouchEnd: - name = "XI_TouchEnd"; - break; -#ifdef HAVE_XI23 - case XI_BarrierHit: - name = "XI_BarrierHit"; - break; - case XI_BarrierLeave: - name = "XI_BarrierLeave"; - break; -#endif /* HAVE_XI23 */ - } - - switch (input_event->evtype) - { - case XI_Motion: - extra = g_strdup_printf ("win: 0x%lx x: %g y: %g", - device_event->event, - device_event->root_x, - device_event->root_y); - break; - case XI_ButtonPress: - case XI_ButtonRelease: - extra = g_strdup_printf ("button %u x %g y %g root 0x%lx", - device_event->detail, - device_event->root_x, - device_event->root_y, - device_event->root); - break; - case XI_KeyPress: - case XI_KeyRelease: - { - KeySym keysym; - const char *str; - - keysym = XKeycodeToKeysym (display->xdisplay, device_event->detail, 0); - - str = XKeysymToString (keysym); - - extra = g_strdup_printf ("Key '%s' state 0x%x", - str ? str : "none", device_event->mods.effective); - } - break; - case XI_FocusIn: - case XI_FocusOut: - extra = g_strdup_printf ("detail: %s mode: %s\n", - meta_event_detail_to_string (enter_event->detail), - meta_event_mode_to_string (enter_event->mode)); - break; - case XI_Enter: - case XI_Leave: - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx mode: %s detail: %s focus: %d x: %g y: %g", - enter_event->event, - enter_event->root, - meta_event_mode_to_string (enter_event->mode), - meta_event_detail_to_string (enter_event->detail), - enter_event->focus, - enter_event->root_x, - enter_event->root_y); - break; - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx touch sequence: %d x: %g y: %g state: 0x%x flags: 0x%x", - device_event->event, - device_event->root, - device_event->detail, - device_event->root_x, - device_event->root_y, - device_event->mods.effective, - device_event->flags); - break; - } - - *name_p = name; - *extra_p = extra; -} - -static void -meta_spew_core_event (MetaDisplay *display, - XEvent *event, - const char **name_p, - char **extra_p) -{ - const char *name = NULL; - char *extra = NULL; - - switch (event->type) - { - case KeymapNotify: - name = "KeymapNotify"; - break; - case Expose: - name = "Expose"; - break; - case GraphicsExpose: - name = "GraphicsExpose"; - break; - case NoExpose: - name = "NoExpose"; - break; - case VisibilityNotify: - name = "VisibilityNotify"; - break; - case CreateNotify: - name = "CreateNotify"; - extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx", - event->xcreatewindow.parent, - event->xcreatewindow.window); - break; - case DestroyNotify: - name = "DestroyNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx", - event->xdestroywindow.event, - event->xdestroywindow.window); - break; - case UnmapNotify: - name = "UnmapNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d", - event->xunmap.event, - event->xunmap.window, - event->xunmap.from_configure); - break; - case MapNotify: - name = "MapNotify"; - extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d", - event->xmap.event, - event->xmap.window, - event->xmap.override_redirect); - break; - case MapRequest: - name = "MapRequest"; - extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n", - event->xmaprequest.window, - event->xmaprequest.parent); - break; - case ReparentNotify: - name = "ReparentNotify"; - extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n", - event->xreparent.window, - event->xreparent.parent, - event->xreparent.event); - break; - case ConfigureNotify: - name = "ConfigureNotify"; - extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d", - event->xconfigure.x, - event->xconfigure.y, - event->xconfigure.width, - event->xconfigure.height, - event->xconfigure.above, - event->xconfigure.override_redirect); - break; - case ConfigureRequest: - name = "ConfigureRequest"; - extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s", - event->xconfigurerequest.parent, - event->xconfigurerequest.window, - event->xconfigurerequest.x, - event->xconfigurerequest.value_mask & - CWX ? "" : "(unset) ", - event->xconfigurerequest.y, - event->xconfigurerequest.value_mask & - CWY ? "" : "(unset) ", - event->xconfigurerequest.width, - event->xconfigurerequest.value_mask & - CWWidth ? "" : "(unset) ", - event->xconfigurerequest.height, - event->xconfigurerequest.value_mask & - CWHeight ? "" : "(unset) ", - event->xconfigurerequest.border_width, - event->xconfigurerequest.value_mask & - CWBorderWidth ? "" : "(unset)", - event->xconfigurerequest.above, - event->xconfigurerequest.value_mask & - CWSibling ? "" : "(unset)", - stack_mode_to_string (event->xconfigurerequest.detail), - event->xconfigurerequest.value_mask & - CWStackMode ? "" : "(unset)"); - break; - case GravityNotify: - name = "GravityNotify"; - break; - case ResizeRequest: - name = "ResizeRequest"; - extra = g_strdup_printf ("width = %d height = %d", - event->xresizerequest.width, - event->xresizerequest.height); - break; - case CirculateNotify: - name = "CirculateNotify"; - break; - case CirculateRequest: - name = "CirculateRequest"; - break; - case PropertyNotify: - { - char *str; - const char *state; - - name = "PropertyNotify"; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xproperty.atom); - meta_error_trap_pop (display); - - if (event->xproperty.state == PropertyNewValue) - state = "PropertyNewValue"; - else if (event->xproperty.state == PropertyDelete) - state = "PropertyDelete"; - else - state = "???"; - - extra = g_strdup_printf ("atom: %s state: %s", - str ? str : "(unknown atom)", - state); - meta_XFree (str); - } - break; - case SelectionClear: - name = "SelectionClear"; - break; - case SelectionRequest: - name = "SelectionRequest"; - break; - case SelectionNotify: - name = "SelectionNotify"; - break; - case ColormapNotify: - name = "ColormapNotify"; - break; - case ClientMessage: - { - char *str; - name = "ClientMessage"; - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xclient.message_type); - meta_error_trap_pop (display); - extra = g_strdup_printf ("type: %s format: %d\n", - str ? str : "(unknown atom)", - event->xclient.format); - meta_XFree (str); - } - break; - case MappingNotify: - name = "MappingNotify"; - break; - default: -#ifdef HAVE_XSYNC - if (META_DISPLAY_HAS_XSYNC (display) && - event->type == (display->xsync_event_base + XSyncAlarmNotify)) - { - XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event; - - name = "XSyncAlarmNotify"; - extra = - g_strdup_printf ("alarm: 0x%lx" - " counter_value: %" G_GINT64_FORMAT - " alarm_value: %" G_GINT64_FORMAT - " time: %u alarm state: %s", - aevent->alarm, - (gint64) sync_value_to_64 (&aevent->counter_value), - (gint64) sync_value_to_64 (&aevent->alarm_value), - (unsigned int)aevent->time, - alarm_state_to_string (aevent->state)); - } - else -#endif /* HAVE_XSYNC */ -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display) && - event->type == (display->shape_event_base + ShapeNotify)) - { - XShapeEvent *sev = (XShapeEvent*) event; - - name = "ShapeNotify"; - - extra = - g_strdup_printf ("kind: %s " - "x: %d y: %d w: %u h: %u " - "shaped: %d", - sev->kind == ShapeBounding ? - "ShapeBounding" : - (sev->kind == ShapeClip ? - "ShapeClip" : "(unknown)"), - sev->x, sev->y, sev->width, sev->height, - sev->shaped); - } - else -#endif /* HAVE_SHAPE */ - { - name = "(Unknown event)"; - extra = g_strdup_printf ("type: %d", event->xany.type); - } - break; - } - - *name_p = name; - *extra_p = extra; -} - -static void -meta_spew_event (MetaDisplay *display, - XEvent *event) -{ - const char *name = NULL; - char *extra = NULL; - char *winname; - MetaScreen *screen; - XIEvent *input_event; - - if (!meta_is_verbose()) - return; - - /* filter overnumerous events */ - if (event->type == Expose || event->type == MotionNotify || - event->type == NoExpose) - return; - - if (event->type == (display->damage_event_base + XDamageNotify)) - return; - - if (event->type == (display->xsync_event_base + XSyncAlarmNotify)) - return; - - if (event->type == PropertyNotify && event->xproperty.atom == display->atom__NET_WM_USER_TIME) - return; - - input_event = get_input_event (display, event); - - if (input_event) - meta_spew_xi2_event (display, input_event, &name, &extra); - else - meta_spew_core_event (display, event, &name, &extra); - - screen = meta_display_screen_for_root (display, event->xany.window); - - if (screen) - winname = g_strdup_printf ("root %d", screen->number); - else - winname = g_strdup_printf ("0x%lx", event->xany.window); - - meta_topic (META_DEBUG_EVENTS, - "%s on %s%s %s %sserial %lu\n", name, winname, - extra ? ":" : "", extra ? extra : "", - event->xany.send_event ? "SEND " : "", - event->xany.serial); - - g_free (winname); - - if (extra) - g_free (extra); -} -#endif /* WITH_VERBOSE_MODE */ - MetaWindow* meta_display_lookup_x_window (MetaDisplay *display, Window xwindow) @@ -3823,6 +1691,20 @@ meta_display_unregister_x_window (MetaDisplay *display, remove_pending_pings_for_window (display, xwindow); } +void +meta_display_register_wayland_window (MetaDisplay *display, + MetaWindow *window) +{ + g_hash_table_add (display->wayland_windows, window); +} + +void +meta_display_unregister_wayland_window (MetaDisplay *display, + MetaWindow *window) +{ + g_hash_table_remove (display->wayland_windows, window); +} + #ifdef HAVE_XSYNC /* We store sync alarms in the window ID hash table, because they are * just more types of XIDs in the same global space, but we have @@ -3876,73 +1758,56 @@ gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, Window xwindow) { - gboolean is_a_no_focus_window = FALSE; - GSList *temp = display->screens; - while (temp != NULL) { - MetaScreen *screen = temp->data; - if (screen->no_focus_window == xwindow) { - is_a_no_focus_window = TRUE; - break; - } - temp = temp->next; - } - - return is_a_no_focus_window; + return xwindow == display->screen->no_focus_window; } -static Cursor -xcursor_for_op (MetaDisplay *display, - MetaGrabOp op) +static MetaCursor +meta_cursor_for_grab_op (MetaGrabOp op) { - MetaCursor cursor = META_CURSOR_DEFAULT; - switch (op) { case META_GRAB_OP_RESIZING_SE: case META_GRAB_OP_KEYBOARD_RESIZING_SE: - cursor = META_CURSOR_SE_RESIZE; + return META_CURSOR_SE_RESIZE; break; case META_GRAB_OP_RESIZING_S: case META_GRAB_OP_KEYBOARD_RESIZING_S: - cursor = META_CURSOR_SOUTH_RESIZE; + return META_CURSOR_SOUTH_RESIZE; break; case META_GRAB_OP_RESIZING_SW: case META_GRAB_OP_KEYBOARD_RESIZING_SW: - cursor = META_CURSOR_SW_RESIZE; + return META_CURSOR_SW_RESIZE; break; case META_GRAB_OP_RESIZING_N: case META_GRAB_OP_KEYBOARD_RESIZING_N: - cursor = META_CURSOR_NORTH_RESIZE; + return META_CURSOR_NORTH_RESIZE; break; case META_GRAB_OP_RESIZING_NE: case META_GRAB_OP_KEYBOARD_RESIZING_NE: - cursor = META_CURSOR_NE_RESIZE; + return META_CURSOR_NE_RESIZE; break; case META_GRAB_OP_RESIZING_NW: case META_GRAB_OP_KEYBOARD_RESIZING_NW: - cursor = META_CURSOR_NW_RESIZE; + return META_CURSOR_NW_RESIZE; break; case META_GRAB_OP_RESIZING_W: case META_GRAB_OP_KEYBOARD_RESIZING_W: - cursor = META_CURSOR_WEST_RESIZE; + return META_CURSOR_WEST_RESIZE; break; case META_GRAB_OP_RESIZING_E: case META_GRAB_OP_KEYBOARD_RESIZING_E: - cursor = META_CURSOR_EAST_RESIZE; + return META_CURSOR_EAST_RESIZE; break; case META_GRAB_OP_MOVING: case META_GRAB_OP_KEYBOARD_MOVING: case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - cursor = META_CURSOR_MOVE_OR_RESIZE_WINDOW; + return META_CURSOR_MOVE_OR_RESIZE_WINDOW; break; - default: break; } - if (cursor == META_CURSOR_DEFAULT) - return None; - return meta_display_create_x_cursor (display, cursor); + return META_CURSOR_DEFAULT; } void @@ -3952,9 +1817,10 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, Window grab_xwindow, guint32 timestamp) { - Cursor cursor = xcursor_for_op (display, op); unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + MetaCursor cursor = meta_cursor_for_grab_op (op); + MetaCursorReference *cursor_ref; XISetMask (mask.mask, XI_ButtonPress); XISetMask (mask.mask, XI_ButtonRelease); @@ -3969,7 +1835,7 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, META_VIRTUAL_CORE_POINTER_ID, grab_xwindow, timestamp, - cursor, + meta_display_create_x_cursor (display, cursor), XIGrabModeAsync, XIGrabModeAsync, False, /* owner_events */ &mask) == Success) @@ -3985,10 +1851,12 @@ meta_display_set_grab_op_cursor (MetaDisplay *display, "XIGrabDevice() failed time %u\n", timestamp); } + meta_error_trap_pop (display); - - if (cursor != None) - XFreeCursor (display->xdisplay, cursor); + + cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor); + meta_cursor_tracker_set_grab_cursor (screen->cursor_tracker, cursor_ref); + meta_cursor_reference_unref (cursor_ref); } gboolean @@ -3999,7 +1867,7 @@ meta_display_begin_grab_op (MetaDisplay *display, gboolean pointer_already_grabbed, gboolean frame_action, int button, - gulong modmask, + gulong modmask, /* XXX - ignored */ guint32 timestamp, int root_x, int root_y) @@ -4062,7 +1930,7 @@ meta_display_begin_grab_op (MetaDisplay *display, meta_display_set_grab_op_cursor (display, screen, op, grab_xwindow, timestamp); - if (!display->grab_have_pointer && !grab_op_is_keyboard (op)) + if (!display->grab_have_pointer && !meta_grab_op_is_keyboard (op)) { meta_topic (META_DEBUG_WINDOW_OPS, "XIGrabDevice() failed\n"); @@ -4070,7 +1938,7 @@ meta_display_begin_grab_op (MetaDisplay *display, } /* Grab keys for keyboard ops and mouse move/resizes; see #126497 */ - if (grab_op_is_keyboard (op) || grab_op_is_mouse_only (op)) + if (meta_grab_op_is_keyboard (op) || grab_op_is_mouse_only (op)) { if (grab_window) display->grab_have_keyboard = @@ -4092,10 +1960,8 @@ meta_display_begin_grab_op (MetaDisplay *display, display->grab_op = op; display->grab_window = grab_window; - display->grab_screen = screen; display->grab_xwindow = grab_xwindow; display->grab_button = button; - display->grab_mask = modmask; if (window) { display->grab_tile_mode = window->tile_mode; @@ -4112,7 +1978,6 @@ meta_display_begin_grab_op (MetaDisplay *display, display->grab_latest_motion_y = root_y; display->grab_last_moveresize_time.tv_sec = 0; display->grab_last_moveresize_time.tv_usec = 0; - display->grab_motion_notify_time = 0; display->grab_old_window_stacking = NULL; #ifdef HAVE_XSYNC display->grab_last_user_action_was_snap = FALSE; @@ -4146,7 +2011,7 @@ meta_display_begin_grab_op (MetaDisplay *display, "Grab op %u on window %s successful\n", display->grab_op, window ? window->desc : "(null)"); - g_assert (display->grab_window != NULL || display->grab_screen != NULL); + g_assert (display->grab_window != NULL); g_assert (display->grab_op != META_GRAB_OP_NONE); if (display->grab_window) @@ -4154,6 +2019,9 @@ meta_display_begin_grab_op (MetaDisplay *display, meta_window_refresh_resize_popup (display->grab_window); } + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); + g_signal_emit (display, display_signals[GRAB_OP_BEGIN], 0, screen, display->grab_window, display->grab_op); @@ -4171,7 +2039,7 @@ meta_display_end_grab_op (MetaDisplay *display, return; g_signal_emit (display, display_signals[GRAB_OP_END], 0, - display->grab_screen, display->grab_window, display->grab_op); + display->screen, display->grab_window, display->grab_op); if (display->grab_window != NULL) display->grab_window->shaken_loose = FALSE; @@ -4223,13 +2091,13 @@ meta_display_end_grab_op (MetaDisplay *display, if (display->grab_window) meta_window_ungrab_all_keys (display->grab_window, timestamp); else - meta_screen_ungrab_all_keys (display->grab_screen, timestamp); + meta_screen_ungrab_all_keys (display->screen, timestamp); } - + meta_cursor_tracker_set_grab_cursor (display->screen->cursor_tracker, NULL); + display->grab_timestamp = 0; display->grab_window = NULL; - display->grab_screen = NULL; display->grab_xwindow = None; display->grab_tile_mode = META_TILE_NONE; display->grab_tile_monitor_number = -1; @@ -4246,6 +2114,9 @@ meta_display_end_grab_op (MetaDisplay *display, g_source_remove (display->grab_resize_timeout_id); display->grab_resize_timeout_id = 0; } + + if (meta_is_wayland_compositor ()) + meta_display_sync_wayland_input_focus (display); } /** @@ -4321,7 +2192,7 @@ meta_change_button_grab (MetaDisplay *display, mods = (XIGrabModifiers) { modmask | ignored_mask, 0 }; if (meta_is_debugging ()) - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); /* GrabModeSync means freeze until XAllowEvents */ @@ -4516,30 +2387,19 @@ meta_display_increment_event_serial (MetaDisplay *display) void meta_display_update_active_window_hint (MetaDisplay *display) { - GSList *tmp; - gulong data[1]; if (display->focus_window) data[0] = display->focus_window->xwindow; else data[0] = None; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, screen->xroot, - display->atom__NET_ACTIVE_WINDOW, - XA_WINDOW, - 32, PropModeReplace, (guchar*) data, 1); - meta_error_trap_pop (display); - - tmp = tmp->next; - } + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, display->screen->xroot, + display->atom__NET_ACTIVE_WINDOW, + XA_WINDOW, + 32, PropModeReplace, (guchar*) data, 1); + meta_error_trap_pop (display); } void @@ -4577,25 +2437,12 @@ void meta_display_set_cursor_theme (const char *theme, int size) { -#ifdef HAVE_XCURSOR - GSList *tmp; - MetaDisplay *display = meta_get_display (); XcursorSetTheme (display->xdisplay, theme); XcursorSetDefaultSize (display->xdisplay, size); - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_update_cursor (screen); - - tmp = tmp->next; - } - -#endif + meta_screen_update_cursor (display->screen); } /* @@ -4662,24 +2509,20 @@ meta_set_syncing (gboolean setting) static gboolean meta_display_ping_timeout (gpointer data) { - MetaPingData *ping_data; - - ping_data = data; + MetaPingData *ping_data = data; + MetaDisplay *display = ping_data->window->display; ping_data->ping_timeout_id = 0; meta_topic (META_DEBUG_PING, - "Ping %u on window %lx timed out\n", - ping_data->timestamp, ping_data->xwindow); - - (* ping_data->ping_timeout_func) (ping_data->display, ping_data->xwindow, - ping_data->timestamp, ping_data->user_data); + "Ping %u on window %s timed out\n", + ping_data->timestamp, ping_data->window->desc); - ping_data->display->pending_pings = - g_slist_remove (ping_data->display->pending_pings, - ping_data); + (* ping_data->ping_timeout_func) (ping_data->window, ping_data->timestamp, ping_data->user_data); + + display->pending_pings = g_slist_remove (display->pending_pings, ping_data); ping_data_free (ping_data); - + return FALSE; } @@ -4703,19 +2546,15 @@ meta_display_ping_timeout (gpointer data) * we call the "got a response" callback immediately and return. * This function returns straight away after setting things up; * the callbacks will be called from the event loop. - * - * FIXME: This should probably be a method on windows, rather than displays - * for one of their windows. - * */ void -meta_display_ping_window (MetaDisplay *display, - MetaWindow *window, +meta_display_ping_window (MetaWindow *window, guint32 timestamp, MetaWindowPingFunc ping_reply_func, MetaWindowPingFunc ping_timeout_func, gpointer user_data) { + MetaDisplay *display = window->display; MetaPingData *ping_data; if (timestamp == CurrentTime) @@ -4724,17 +2563,16 @@ meta_display_ping_window (MetaDisplay *display, return; } - if (!window->net_wm_ping) + if (!window->can_ping) { if (ping_reply_func) - (* ping_reply_func) (display, window->xwindow, timestamp, user_data); + (* ping_reply_func) (window, timestamp, user_data); return; } - + ping_data = g_new (MetaPingData, 1); - ping_data->display = display; - ping_data->xwindow = window->xwindow; + ping_data->window = window; ping_data->timestamp = timestamp; ping_data->ping_reply_func = ping_reply_func; ping_data->ping_timeout_func = ping_timeout_func; @@ -4742,106 +2580,41 @@ meta_display_ping_window (MetaDisplay *display, ping_data->ping_timeout_id = g_timeout_add (PING_TIMEOUT_DELAY, meta_display_ping_timeout, ping_data); - + display->pending_pings = g_slist_prepend (display->pending_pings, ping_data); meta_topic (META_DEBUG_PING, "Sending ping with timestamp %u to window %s\n", timestamp, window->desc); - meta_window_send_icccm_message (window, - display->atom__NET_WM_PING, - timestamp); -} -static void -process_request_frame_extents (MetaDisplay *display, - XEvent *event) -{ - /* The X window whose frame extents will be set. */ - Window xwindow = event->xclient.window; - unsigned long data[4] = { 0, 0, 0, 0 }; - - MotifWmHints *hints = NULL; - gboolean hints_set = FALSE; - - meta_verbose ("Setting frame extents for 0x%lx\n", xwindow); - - /* See if the window is decorated. */ - hints_set = meta_prop_get_motif_hints (display, - xwindow, - display->atom__MOTIF_WM_HINTS, - &hints); - if ((hints_set && hints->decorations) || !hints_set) - { - MetaFrameBorders borders; - MetaScreen *screen; - - screen = meta_display_screen_for_xwindow (display, - event->xclient.window); - if (screen == NULL) - { - meta_warning ("Received request to set _NET_FRAME_EXTENTS " - "on 0x%lx which is on a screen we are not managing\n", - event->xclient.window); - meta_XFree (hints); - return; - } - - /* Return estimated frame extents for a normal window. */ - meta_ui_theme_get_frame_borders (screen->ui, - META_FRAME_TYPE_NORMAL, - 0, - &borders); - data[0] = borders.visible.left; - data[1] = borders.visible.right; - data[2] = borders.visible.top; - data[3] = borders.visible.bottom; - } - - meta_topic (META_DEBUG_GEOMETRY, - "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx " - "to top = %lu, left = %lu, bottom = %lu, right = %lu\n", - xwindow, data[0], data[1], data[2], data[3]); - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, xwindow, - display->atom__NET_FRAME_EXTENTS, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 4); - meta_error_trap_pop (display); - - meta_XFree (hints); + META_WINDOW_GET_CLASS (window)->ping (window, timestamp); } /** - * process_pong_message: + * meta_display_pong_for_serial: * @display: the display we got the pong from - * @event: the #XEvent which is a pong; we can tell which - * ping it corresponds to because it bears the - * same timestamp. + * @serial: the serial in the pong repsonse * * Process the pong (the response message) from the ping we sent * to the window. This involves removing the timeout, calling the * reply handler function, and freeing memory. */ -static void -process_pong_message (MetaDisplay *display, - XEvent *event) +void +meta_display_pong_for_serial (MetaDisplay *display, + guint32 serial) { GSList *tmp; - guint32 timestamp = event->xclient.data.l[1]; - meta_topic (META_DEBUG_PING, "Received a pong with timestamp %u\n", - timestamp); - + meta_topic (META_DEBUG_PING, "Received a pong with serial %u\n", serial); + for (tmp = display->pending_pings; tmp; tmp = tmp->next) { MetaPingData *ping_data = tmp->data; - - if (timestamp == ping_data->timestamp) + + if (serial == ping_data->timestamp) { meta_topic (META_DEBUG_PING, - "Matching ping found for pong %u\n", + "Matching ping found for pong %u\n", ping_data->timestamp); /* Remove the ping data from the list */ @@ -4854,13 +2627,12 @@ process_pong_message (MetaDisplay *display, g_source_remove (ping_data->ping_timeout_id); ping_data->ping_timeout_id = 0; } - + /* Call callback */ - (* ping_data->ping_reply_func) (display, - ping_data->xwindow, - ping_data->timestamp, + (* ping_data->ping_reply_func) (ping_data->window, + ping_data->timestamp, ping_data->user_data); - + ping_data_free (ping_data); break; @@ -4868,38 +2640,8 @@ process_pong_message (MetaDisplay *display, } } -/** - * meta_display_window_has_pending_pings: - * @display: The #MetaDisplay of the window. - * @window: The #MetaWindow whose pings we want to know about. - * - * Finds whether a window has any pings waiting on it. - * - * FIXME: This should probably be a method on windows, rather than displays - * for one of their windows. - * - * Returns: %TRUE if there is at least one ping which has been sent - * to the window without getting a response; %FALSE otherwise. - */ -gboolean -meta_display_window_has_pending_pings (MetaDisplay *display, - MetaWindow *window) -{ - GSList *tmp; - - for (tmp = display->pending_pings; tmp; tmp = tmp->next) - { - MetaPingData *ping_data = tmp->data; - - if (ping_data->xwindow == window->xwindow) - return TRUE; - } - - return FALSE; -} - -MetaGroup* -get_focussed_group (MetaDisplay *display) +static MetaGroup * +get_focused_group (MetaDisplay *display) { if (display->focus_window) return display->focus_window->group; @@ -4909,13 +2651,12 @@ get_focussed_group (MetaDisplay *display) #define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \ || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \ - || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))) \ + || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focused_group (w->display))) \ || ((t) == META_TAB_LIST_NORMAL_ALL && META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w))) static MetaWindow* find_tab_forward (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, GList *start, gboolean skip_first) @@ -4933,8 +2674,7 @@ find_tab_forward (MetaDisplay *display, { MetaWindow *window = tmp->data; - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) + if (IN_TAB_CHAIN (window, type)) return window; tmp = tmp->next; @@ -4957,7 +2697,6 @@ find_tab_forward (MetaDisplay *display, static MetaWindow* find_tab_backward (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, GList *start, gboolean skip_last) @@ -4974,8 +2713,7 @@ find_tab_backward (MetaDisplay *display, { MetaWindow *window = tmp->data; - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) + if (IN_TAB_CHAIN (window, type)) return window; tmp = tmp->prev; @@ -5055,8 +2793,7 @@ meta_display_get_tab_list (MetaDisplay *display, { MetaWindow *window = tmp->data; - if (window->screen == screen && - IN_TAB_CHAIN (window, type)) + if (IN_TAB_CHAIN (window, type)) tab_list = g_list_prepend (tab_list, window); } @@ -5086,7 +2823,6 @@ meta_display_get_tab_list (MetaDisplay *display, * meta_display_get_tab_next: * @display: a #MetaDisplay * @type: type of tab list - * @screen: a #MetaScreen * @workspace: origin workspace * @window: (allow-none): starting window * @backward: If %TRUE, look for the previous window. @@ -5100,7 +2836,6 @@ meta_display_get_tab_list (MetaDisplay *display, MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, MetaWindow *window, gboolean backward) @@ -5108,10 +2843,7 @@ meta_display_get_tab_next (MetaDisplay *display, gboolean skip; GList *tab_list; MetaWindow *ret; - tab_list = meta_display_get_tab_list(display, - type, - screen, - workspace); + tab_list = meta_display_get_tab_list (display, type, NULL, workspace); if (tab_list == NULL) return NULL; @@ -5121,26 +2853,18 @@ meta_display_get_tab_next (MetaDisplay *display, g_assert (window->display == display); if (backward) - ret = find_tab_backward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); + ret = find_tab_backward (display, type, workspace, g_list_find (tab_list, window), TRUE); else - ret = find_tab_forward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); + ret = find_tab_forward (display, type, workspace, g_list_find (tab_list, window), TRUE); } else { skip = display->focus_window != NULL && tab_list->data == display->focus_window; if (backward) - ret = find_tab_backward (display, type, screen, workspace, - tab_list, skip); + ret = find_tab_backward (display, type, workspace, tab_list, skip); else - ret = find_tab_forward (display, type, screen, workspace, - tab_list, skip); + ret = find_tab_forward (display, type, workspace, tab_list, skip); } g_list_free (tab_list); @@ -5151,7 +2875,6 @@ meta_display_get_tab_next (MetaDisplay *display, * meta_display_get_tab_current: * @display: a #MetaDisplay * @type: type of tab list - * @screen: a #MetaScreen * @workspace: origin workspace * * Determine the active window that should be displayed for Alt-TAB. @@ -5162,7 +2885,6 @@ meta_display_get_tab_next (MetaDisplay *display, MetaWindow* meta_display_get_tab_current (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace) { MetaWindow *window; @@ -5170,7 +2892,6 @@ meta_display_get_tab_current (MetaDisplay *display, window = display->focus_window; if (window != NULL && - window->screen == screen && IN_TAB_CHAIN (window, type) && (workspace == NULL || meta_window_located_on_workspace (window, workspace))) @@ -5229,222 +2950,6 @@ meta_resize_gravity_from_grab_op (MetaGrabOp op) return gravity; } -static MetaScreen* -find_screen_for_selection (MetaDisplay *display, - Window owner, - Atom selection) -{ - GSList *tmp; - - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - if (screen->wm_sn_selection_window == owner && - screen->wm_sn_atom == selection) - return screen; - - tmp = tmp->next; - } - - return NULL; -} - -/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ -static gboolean -convert_property (MetaDisplay *display, - MetaScreen *screen, - Window w, - Atom target, - Atom property) -{ -#define N_TARGETS 4 - Atom conversion_targets[N_TARGETS]; - long icccm_version[] = { 2, 0 }; - - conversion_targets[0] = display->atom_TARGETS; - conversion_targets[1] = display->atom_MULTIPLE; - conversion_targets[2] = display->atom_TIMESTAMP; - conversion_targets[3] = display->atom_VERSION; - - meta_error_trap_push_with_return (display); - if (target == display->atom_TARGETS) - XChangeProperty (display->xdisplay, w, property, - XA_ATOM, 32, PropModeReplace, - (unsigned char *)conversion_targets, N_TARGETS); - else if (target == display->atom_TIMESTAMP) - XChangeProperty (display->xdisplay, w, property, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *)&screen->wm_sn_timestamp, 1); - else if (target == display->atom_VERSION) - XChangeProperty (display->xdisplay, w, property, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *)icccm_version, 2); - else - { - meta_error_trap_pop_with_return (display); - return FALSE; - } - - if (meta_error_trap_pop_with_return (display) != Success) - return FALSE; - - /* Be sure the PropertyNotify has arrived so we - * can send SelectionNotify - */ - /* FIXME the error trap pop synced anyway, right? */ - meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC); - XSync (display->xdisplay, False); - - return TRUE; -} - -/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ -static void -process_selection_request (MetaDisplay *display, - XEvent *event) -{ - XSelectionEvent reply; - MetaScreen *screen; - - screen = find_screen_for_selection (display, - event->xselectionrequest.owner, - event->xselectionrequest.selection); - - if (screen == NULL) - { - char *str; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xselectionrequest.selection); - meta_error_trap_pop (display); - - meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n", - str ? str : "(bad atom)", event->xselectionrequest.owner); - - meta_XFree (str); - - return; - } - - reply.type = SelectionNotify; - reply.display = display->xdisplay; - reply.requestor = event->xselectionrequest.requestor; - reply.selection = event->xselectionrequest.selection; - reply.target = event->xselectionrequest.target; - reply.property = None; - reply.time = event->xselectionrequest.time; - - if (event->xselectionrequest.target == display->atom_MULTIPLE) - { - if (event->xselectionrequest.property != None) - { - Atom type, *adata; - int i, format; - unsigned long num, rest; - unsigned char *data; - - meta_error_trap_push_with_return (display); - if (XGetWindowProperty (display->xdisplay, - event->xselectionrequest.requestor, - event->xselectionrequest.property, 0, 256, False, - display->atom_ATOM_PAIR, - &type, &format, &num, &rest, &data) != Success) - { - meta_error_trap_pop_with_return (display); - return; - } - - if (meta_error_trap_pop_with_return (display) == Success) - { - /* FIXME: to be 100% correct, should deal with rest > 0, - * but since we have 4 possible targets, we will hardly ever - * meet multiple requests with a length > 8 - */ - adata = (Atom*)data; - i = 0; - while (i < (int) num) - { - if (!convert_property (display, screen, - event->xselectionrequest.requestor, - adata[i], adata[i+1])) - adata[i+1] = None; - i += 2; - } - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, - event->xselectionrequest.requestor, - event->xselectionrequest.property, - display->atom_ATOM_PAIR, - 32, PropModeReplace, data, num); - meta_error_trap_pop (display); - meta_XFree (data); - } - } - } - else - { - if (event->xselectionrequest.property == None) - event->xselectionrequest.property = event->xselectionrequest.target; - - if (convert_property (display, screen, - event->xselectionrequest.requestor, - event->xselectionrequest.target, - event->xselectionrequest.property)) - reply.property = event->xselectionrequest.property; - } - - XSendEvent (display->xdisplay, - event->xselectionrequest.requestor, - False, 0L, (XEvent*)&reply); - - meta_verbose ("Handled selection request\n"); -} - -static void -process_selection_clear (MetaDisplay *display, - XEvent *event) -{ - /* We need to unmanage the screen on which we lost the selection */ - MetaScreen *screen; - - screen = find_screen_for_selection (display, - event->xselectionclear.window, - event->xselectionclear.selection); - - - if (screen != NULL) - { - meta_verbose ("Got selection clear for screen %d on display %s\n", - screen->number, display->name); - - meta_display_unmanage_screen (display, - screen, - event->xselectionclear.time); - - /* display and screen may both be invalid memory... */ - - return; - } - - { - char *str; - - meta_error_trap_push (display); - str = XGetAtomName (display->xdisplay, - event->xselectionclear.selection); - meta_error_trap_pop (display); - - meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n", - str ? str : "(bad atom)", event->xselectionclear.window); - - meta_XFree (str); - } -} - void meta_display_unmanage_screen (MetaDisplay *display, MetaScreen *screen, @@ -5452,14 +2957,7 @@ meta_display_unmanage_screen (MetaDisplay *display, { meta_verbose ("Unmanaging screen %d on display %s\n", screen->number, display->name); - - g_return_if_fail (g_slist_find (display->screens, screen) != NULL); - - meta_screen_free (screen, timestamp); - display->screens = g_slist_remove (display->screens, screen); - - if (display->screens == NULL) - meta_display_close (display, timestamp); + meta_display_close (display, timestamp); } void @@ -5501,15 +2999,7 @@ meta_display_stack_cmp (const void *a, MetaWindow *aw = (void*) a; MetaWindow *bw = (void*) b; - if (aw->screen == bw->screen) - return meta_stack_windows_cmp (aw->screen->stack, aw, bw); - /* Then assume screens are stacked by number */ - else if (aw->screen->number < bw->screen->number) - return -1; - else if (aw->screen->number > bw->screen->number) - return 1; - else - return 0; /* not reached in theory, if windows on same display */ + return meta_stack_windows_cmp (aw->screen->stack, aw, bw); } /** @@ -5571,7 +3061,6 @@ meta_display_devirtualize_modifiers (MetaDisplay *display, static void update_window_grab_modifiers (MetaDisplay *display) - { MetaVirtualModifier virtual_mods; unsigned int mods; @@ -5645,7 +3134,7 @@ meta_display_increment_focus_sentinel (MetaDisplay *display) data[0] = meta_display_get_current_time (display); XChangeProperty (display->xdisplay, - ((MetaScreen*) display->screens->data)->xroot, + display->screen->xroot, display->atom__MUTTER_SENTINEL, XA_CARDINAL, 32, PropModeReplace, (guchar*) data, 1); @@ -5668,9 +3157,9 @@ meta_display_focus_sentinel_clear (MetaDisplay *display) return (display->sentinel_counter == 0); } -static void -sanity_check_timestamps (MetaDisplay *display, - guint32 timestamp) +void +meta_display_sanity_check_timestamps (MetaDisplay *display, + guint32 timestamp) { if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time)) { @@ -5722,26 +3211,11 @@ meta_display_set_input_focus_window (MetaDisplay *display, { request_xserver_input_focus_change (display, window->screen, + window, focus_frame ? window->frame->xwindow : window->xwindow, timestamp); } -void -meta_display_request_take_focus (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp) -{ - if (timestamp_too_old (display, ×tamp)) - return; - - meta_topic (META_DEBUG_FOCUS, "WM_TAKE_FOCUS(%s, %u)\n", - window->desc, timestamp); - - meta_window_send_icccm_message (window, - display->atom_WM_TAKE_FOCUS, - timestamp); -} - void meta_display_set_input_focus_xwindow (MetaDisplay *display, MetaScreen *screen, @@ -5750,6 +3224,7 @@ meta_display_set_input_focus_xwindow (MetaDisplay *display, { request_xserver_input_focus_change (display, screen, + NULL, window, timestamp); } @@ -5761,6 +3236,7 @@ meta_display_focus_the_no_focus_window (MetaDisplay *display, { request_xserver_input_focus_change (display, screen, + NULL, screen->no_focus_window, timestamp); } @@ -5783,13 +3259,14 @@ meta_display_overlay_key_activate (MetaDisplay *display) } void -meta_display_accelerator_activate (MetaDisplay *display, - guint action, - guint deviceid, - guint timestamp) +meta_display_accelerator_activate (MetaDisplay *display, + guint action, + ClutterKeyEvent *event) { g_signal_emit (display, display_signals[ACCELERATOR_ACTIVATED], - 0, action, deviceid, timestamp); + 0, action, + clutter_input_device_get_device_id (event->device), + event->time); } gboolean @@ -5836,7 +3313,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display) gboolean meta_display_supports_extended_barriers (MetaDisplay *display) { - return META_DISPLAY_HAS_XINPUT_23 (display); + return META_DISPLAY_HAS_XINPUT_23 (display) && !meta_is_wayland_compositor (); } /** @@ -5861,18 +3338,6 @@ meta_display_get_compositor (MetaDisplay *display) return display->compositor; } -/** - * meta_display_get_screens: - * @display: a #MetaDisplay - * - * Returns: (transfer none) (element-type Meta.Screen): Screens for this display - */ -GSList * -meta_display_get_screens (MetaDisplay *display) -{ - return display->screens; -} - gboolean meta_display_has_shape (MetaDisplay *display) { @@ -5909,22 +3374,6 @@ meta_display_get_shape_event_base (MetaDisplay *display) } #endif -/** - * meta_display_get_leader_window: - * @display: a #MetaDisplay - * - * Returns the window manager's leader window (as defined by the - * _NET_SUPPORTING_WM_CHECK mechanism of EWMH). For use by plugins that wish - * to attach additional custom properties to this window. - * - * Return value: (transfer none): xid of the leader window. - **/ -Window -meta_display_get_leader_window (MetaDisplay *display) -{ - return display->leader_window; -} - /** * meta_display_clear_mouse_mode: * @display: a #MetaDisplay diff --git a/src/core/edge-resistance.c b/src/core/edge-resistance.c index 6a2648a0a..8eb48a729 100644 --- a/src/core/edge-resistance.c +++ b/src/core/edge-resistance.c @@ -30,7 +30,6 @@ */ #define WINDOW_EDGES_RELEVANT(window, display) \ meta_window_should_be_showing (window) && \ - window->screen == display->grab_screen && \ window != display->grab_window && \ window->type != META_WINDOW_DESKTOP && \ window->type != META_WINDOW_MENU && \ @@ -963,9 +962,9 @@ compute_resistance_and_snapping_edges (MetaDisplay *display) /* * 1st: Get the list of relevant windows, from bottom to top */ - stacked_windows = - meta_stack_list_windows (display->grab_screen->stack, - display->grab_screen->active_workspace); + stacked_windows = + meta_stack_list_windows (display->screen->stack, + display->screen->active_workspace); /* * 2nd: we need to separate that stacked list into a list of windows that @@ -1026,7 +1025,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display) * by other windows or DOCKS, but that's handled below). */ meta_rectangle_intersect (&cur_rect, - &display->grab_screen->rect, + &display->screen->rect, &reduced); new_edges = NULL; @@ -1123,8 +1122,8 @@ compute_resistance_and_snapping_edges (MetaDisplay *display) */ cache_edges (display, edges, - display->grab_screen->active_workspace->monitor_edges, - display->grab_screen->active_workspace->screen_edges); + display->screen->active_workspace->monitor_edges, + display->screen->active_workspace->screen_edges); g_list_free (edges); /* diff --git a/src/core/errors.c b/src/core/errors.c index 56a7bd423..f199c69b2 100644 --- a/src/core/errors.c +++ b/src/core/errors.c @@ -55,12 +55,6 @@ meta_error_trap_pop (MetaDisplay *display) gdk_error_trap_pop_ignored (); } -void -meta_error_trap_push_with_return (MetaDisplay *display) -{ - gdk_error_trap_push (); -} - int meta_error_trap_pop_with_return (MetaDisplay *display) { diff --git a/src/core/events.c b/src/core/events.c new file mode 100644 index 000000000..3cc548835 --- /dev/null +++ b/src/core/events.c @@ -0,0 +1,2224 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. + * Copyright (C) 2003, 2004 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * 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, see . + */ + +#include "config.h" +#include "events.h" + +#include +#include +#ifdef HAVE_SHAPE +#include +#endif + +#include +#include "display-private.h" +#include "window-private.h" +#include "bell.h" +#include "workspace-private.h" +#include "backends/x11/meta-idle-monitor-xsync.h" +#include "backends/native/meta-idle-monitor-native.h" + +#include "x11/window-x11.h" +#include "x11/xprops.h" +#include "wayland/meta-xwayland.h" +#include "wayland/meta-wayland-private.h" +#include "meta-surface-actor-wayland.h" + +static MetaWindow * +get_window_for_event (MetaDisplay *display, + const ClutterEvent *event) +{ + ClutterActor *source; + + if (display->grab_op != META_GRAB_OP_NONE) + return display->grab_window; + + /* Always use the key focused window for key events. */ + switch (event->type) + { + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + return display->focus_window; + default: + break; + } + + source = clutter_event_get_source (event); + if (META_IS_SURFACE_ACTOR (source)) + return meta_surface_actor_get_window (META_SURFACE_ACTOR (source)); + + return NULL; +} + +static XIEvent * +get_input_event (MetaDisplay *display, + XEvent *event) +{ + if (event->type == GenericEvent && + event->xcookie.extension == display->xinput_opcode) + { + XIEvent *input_event; + + /* NB: GDK event filters already have generic events + * allocated, so no need to do XGetEventData() on our own + */ + input_event = (XIEvent *) event->xcookie.data; + + switch (input_event->evtype) + { + case XI_Motion: + case XI_ButtonPress: + case XI_ButtonRelease: + if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) + return input_event; + break; + case XI_KeyPress: + case XI_KeyRelease: + if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) + return input_event; + break; + case XI_FocusIn: + case XI_FocusOut: + if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID) + return input_event; + break; + case XI_Enter: + case XI_Leave: + if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) + return input_event; + break; +#ifdef HAVE_XI23 + case XI_BarrierHit: + case XI_BarrierLeave: + if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID) + return input_event; + break; +#endif /* HAVE_XI23 */ + default: + break; + } + } + + return NULL; +} + +static Window +xievent_get_modified_window (MetaDisplay *display, + XIEvent *input_event) +{ + switch (input_event->evtype) + { + case XI_Motion: + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_KeyPress: + case XI_KeyRelease: + return ((XIDeviceEvent *) input_event)->event; + case XI_FocusIn: + case XI_FocusOut: + case XI_Enter: + case XI_Leave: + return ((XIEnterEvent *) input_event)->event; +#ifdef HAVE_XI23 + case XI_BarrierHit: + case XI_BarrierLeave: + return ((XIBarrierEvent *) input_event)->event; +#endif /* HAVE_XI23 */ + } + + return None; +} + +/* Return the window this has to do with, if any, rather + * than the frame or root window that was selecting + * for substructure + */ +static Window +event_get_modified_window (MetaDisplay *display, + XEvent *event) +{ + XIEvent *input_event = get_input_event (display, event); + + if (input_event) + return xievent_get_modified_window (display, input_event); + + switch (event->type) + { + case KeymapNotify: + case Expose: + case GraphicsExpose: + case NoExpose: + case VisibilityNotify: + case ResizeRequest: + case PropertyNotify: + case SelectionClear: + case SelectionRequest: + case SelectionNotify: + case ColormapNotify: + case ClientMessage: + return event->xany.window; + + case CreateNotify: + return event->xcreatewindow.window; + + case DestroyNotify: + return event->xdestroywindow.window; + + case UnmapNotify: + return event->xunmap.window; + + case MapNotify: + return event->xmap.window; + + case MapRequest: + return event->xmaprequest.window; + + case ReparentNotify: + return event->xreparent.window; + + case ConfigureNotify: + return event->xconfigure.window; + + case ConfigureRequest: + return event->xconfigurerequest.window; + + case GravityNotify: + return event->xgravity.window; + + case CirculateNotify: + return event->xcirculate.window; + + case CirculateRequest: + return event->xcirculaterequest.window; + + case MappingNotify: + return None; + + default: +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display) && + event->type == (display->shape_event_base + ShapeNotify)) + { + XShapeEvent *sev = (XShapeEvent*) event; + return sev->window; + } +#endif + + return None; + } +} + +static guint32 +event_get_time (MetaDisplay *display, + XEvent *event) +{ + XIEvent *input_event = get_input_event (display, event); + + if (input_event) + return input_event->time; + + switch (event->type) + { + case PropertyNotify: + return event->xproperty.time; + + case SelectionClear: + case SelectionRequest: + case SelectionNotify: + return event->xselection.time; + + case KeymapNotify: + case Expose: + case GraphicsExpose: + case NoExpose: + case MapNotify: + case UnmapNotify: + case VisibilityNotify: + case ResizeRequest: + case ColormapNotify: + case ClientMessage: + case CreateNotify: + case DestroyNotify: + case MapRequest: + case ReparentNotify: + case ConfigureNotify: + case ConfigureRequest: + case GravityNotify: + case CirculateNotify: + case CirculateRequest: + case MappingNotify: + default: + return CurrentTime; + } +} + +G_GNUC_UNUSED const char* +meta_event_detail_to_string (int d) +{ + const char *detail = "???"; + switch (d) + { + /* We are an ancestor in the A<->B focus change relationship */ + case XINotifyAncestor: + detail = "NotifyAncestor"; + break; + case XINotifyDetailNone: + detail = "NotifyDetailNone"; + break; + /* We are a descendant in the A<->B focus change relationship */ + case XINotifyInferior: + detail = "NotifyInferior"; + break; + case XINotifyNonlinear: + detail = "NotifyNonlinear"; + break; + case XINotifyNonlinearVirtual: + detail = "NotifyNonlinearVirtual"; + break; + case XINotifyPointer: + detail = "NotifyPointer"; + break; + case XINotifyPointerRoot: + detail = "NotifyPointerRoot"; + break; + case XINotifyVirtual: + detail = "NotifyVirtual"; + break; + } + + return detail; +} + +G_GNUC_UNUSED const char* +meta_event_mode_to_string (int m) +{ + const char *mode = "???"; + switch (m) + { + case XINotifyNormal: + mode = "NotifyNormal"; + break; + case XINotifyGrab: + mode = "NotifyGrab"; + break; + case XINotifyUngrab: + mode = "NotifyUngrab"; + break; + case XINotifyWhileGrabbed: + mode = "NotifyWhileGrabbed"; + break; + } + + return mode; +} + +G_GNUC_UNUSED static const char* +stack_mode_to_string (int mode) +{ + switch (mode) + { + case Above: + return "Above"; + case Below: + return "Below"; + case TopIf: + return "TopIf"; + case BottomIf: + return "BottomIf"; + case Opposite: + return "Opposite"; + } + + return "Unknown"; +} + +#ifdef HAVE_XSYNC +G_GNUC_UNUSED static gint64 +sync_value_to_64 (const XSyncValue *value) +{ + gint64 v; + + v = XSyncValueLow32 (*value); + v |= (((gint64)XSyncValueHigh32 (*value)) << 32); + + return v; +} + +G_GNUC_UNUSED static const char* +alarm_state_to_string (XSyncAlarmState state) +{ + switch (state) + { + case XSyncAlarmActive: + return "Active"; + case XSyncAlarmInactive: + return "Inactive"; + case XSyncAlarmDestroyed: + return "Destroyed"; + default: + return "(unknown)"; + } +} +#endif /* HAVE_XSYNC */ + +G_GNUC_UNUSED static void +meta_spew_xi2_event (MetaDisplay *display, + XIEvent *input_event, + const char **name_p, + char **extra_p) +{ + const char *name = NULL; + char *extra = NULL; + + XIEnterEvent *enter_event = (XIEnterEvent *) input_event; + + switch (input_event->evtype) + { + case XI_FocusIn: + name = "XI_FocusIn"; + break; + case XI_FocusOut: + name = "XI_FocusOut"; + break; + case XI_Enter: + name = "XI_Enter"; + break; + case XI_Leave: + name = "XI_Leave"; + break; +#ifdef HAVE_XI23 + case XI_BarrierHit: + name = "XI_BarrierHit"; + break; + case XI_BarrierLeave: + name = "XI_BarrierLeave"; + break; +#endif /* HAVE_XI23 */ + } + + switch (input_event->evtype) + { + case XI_FocusIn: + case XI_FocusOut: + extra = g_strdup_printf ("detail: %s mode: %s\n", + meta_event_detail_to_string (enter_event->detail), + meta_event_mode_to_string (enter_event->mode)); + break; + case XI_Enter: + case XI_Leave: + extra = g_strdup_printf ("win: 0x%lx root: 0x%lx mode: %s detail: %s focus: %d x: %g y: %g", + enter_event->event, + enter_event->root, + meta_event_mode_to_string (enter_event->mode), + meta_event_detail_to_string (enter_event->detail), + enter_event->focus, + enter_event->root_x, + enter_event->root_y); + break; + } + + *name_p = name; + *extra_p = extra; +} + +G_GNUC_UNUSED static void +meta_spew_core_event (MetaDisplay *display, + XEvent *event, + const char **name_p, + char **extra_p) +{ + const char *name = NULL; + char *extra = NULL; + + switch (event->type) + { + case KeymapNotify: + name = "KeymapNotify"; + break; + case Expose: + name = "Expose"; + break; + case GraphicsExpose: + name = "GraphicsExpose"; + break; + case NoExpose: + name = "NoExpose"; + break; + case VisibilityNotify: + name = "VisibilityNotify"; + break; + case CreateNotify: + name = "CreateNotify"; + extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx", + event->xcreatewindow.parent, + event->xcreatewindow.window); + break; + case DestroyNotify: + name = "DestroyNotify"; + extra = g_strdup_printf ("event: 0x%lx window: 0x%lx", + event->xdestroywindow.event, + event->xdestroywindow.window); + break; + case UnmapNotify: + name = "UnmapNotify"; + extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d", + event->xunmap.event, + event->xunmap.window, + event->xunmap.from_configure); + break; + case MapNotify: + name = "MapNotify"; + extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d", + event->xmap.event, + event->xmap.window, + event->xmap.override_redirect); + break; + case MapRequest: + name = "MapRequest"; + extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n", + event->xmaprequest.window, + event->xmaprequest.parent); + break; + case ReparentNotify: + name = "ReparentNotify"; + extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n", + event->xreparent.window, + event->xreparent.parent, + event->xreparent.event); + break; + case ConfigureNotify: + name = "ConfigureNotify"; + extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d", + event->xconfigure.x, + event->xconfigure.y, + event->xconfigure.width, + event->xconfigure.height, + event->xconfigure.above, + event->xconfigure.override_redirect); + break; + case ConfigureRequest: + name = "ConfigureRequest"; + extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s", + event->xconfigurerequest.parent, + event->xconfigurerequest.window, + event->xconfigurerequest.x, + event->xconfigurerequest.value_mask & + CWX ? "" : "(unset) ", + event->xconfigurerequest.y, + event->xconfigurerequest.value_mask & + CWY ? "" : "(unset) ", + event->xconfigurerequest.width, + event->xconfigurerequest.value_mask & + CWWidth ? "" : "(unset) ", + event->xconfigurerequest.height, + event->xconfigurerequest.value_mask & + CWHeight ? "" : "(unset) ", + event->xconfigurerequest.border_width, + event->xconfigurerequest.value_mask & + CWBorderWidth ? "" : "(unset)", + event->xconfigurerequest.above, + event->xconfigurerequest.value_mask & + CWSibling ? "" : "(unset)", + stack_mode_to_string (event->xconfigurerequest.detail), + event->xconfigurerequest.value_mask & + CWStackMode ? "" : "(unset)"); + break; + case GravityNotify: + name = "GravityNotify"; + break; + case ResizeRequest: + name = "ResizeRequest"; + extra = g_strdup_printf ("width = %d height = %d", + event->xresizerequest.width, + event->xresizerequest.height); + break; + case CirculateNotify: + name = "CirculateNotify"; + break; + case CirculateRequest: + name = "CirculateRequest"; + break; + case PropertyNotify: + { + char *str; + const char *state; + + name = "PropertyNotify"; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xproperty.atom); + meta_error_trap_pop (display); + + if (event->xproperty.state == PropertyNewValue) + state = "PropertyNewValue"; + else if (event->xproperty.state == PropertyDelete) + state = "PropertyDelete"; + else + state = "???"; + + extra = g_strdup_printf ("atom: %s state: %s", + str ? str : "(unknown atom)", + state); + meta_XFree (str); + } + break; + case SelectionClear: + name = "SelectionClear"; + break; + case SelectionRequest: + name = "SelectionRequest"; + break; + case SelectionNotify: + name = "SelectionNotify"; + break; + case ColormapNotify: + name = "ColormapNotify"; + break; + case ClientMessage: + { + char *str; + name = "ClientMessage"; + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xclient.message_type); + meta_error_trap_pop (display); + extra = g_strdup_printf ("type: %s format: %d\n", + str ? str : "(unknown atom)", + event->xclient.format); + meta_XFree (str); + } + break; + case MappingNotify: + name = "MappingNotify"; + break; + default: +#ifdef HAVE_XSYNC + if (META_DISPLAY_HAS_XSYNC (display) && + event->type == (display->xsync_event_base + XSyncAlarmNotify)) + { + XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event; + + name = "XSyncAlarmNotify"; + extra = + g_strdup_printf ("alarm: 0x%lx" + " counter_value: %" G_GINT64_FORMAT + " alarm_value: %" G_GINT64_FORMAT + " time: %u alarm state: %s", + aevent->alarm, + (gint64) sync_value_to_64 (&aevent->counter_value), + (gint64) sync_value_to_64 (&aevent->alarm_value), + (unsigned int)aevent->time, + alarm_state_to_string (aevent->state)); + } + else +#endif /* HAVE_XSYNC */ +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display) && + event->type == (display->shape_event_base + ShapeNotify)) + { + XShapeEvent *sev = (XShapeEvent*) event; + + name = "ShapeNotify"; + + extra = + g_strdup_printf ("kind: %s " + "x: %d y: %d w: %u h: %u " + "shaped: %d", + sev->kind == ShapeBounding ? + "ShapeBounding" : + (sev->kind == ShapeClip ? + "ShapeClip" : "(unknown)"), + sev->x, sev->y, sev->width, sev->height, + sev->shaped); + } + else +#endif /* HAVE_SHAPE */ + { + name = "(Unknown event)"; + extra = g_strdup_printf ("type: %d", event->xany.type); + } + break; + } + + *name_p = name; + *extra_p = extra; +} + +G_GNUC_UNUSED static void +meta_spew_event (MetaDisplay *display, + XEvent *event) +{ + MetaScreen *screen = display->screen; + const char *name = NULL; + char *extra = NULL; + char *winname; + XIEvent *input_event; + + /* filter overnumerous events */ + if (event->type == Expose || event->type == MotionNotify || + event->type == NoExpose) + return; + + if (event->type == (display->damage_event_base + XDamageNotify)) + return; + + if (event->type == (display->xsync_event_base + XSyncAlarmNotify)) + return; + + if (event->type == PropertyNotify && event->xproperty.atom == display->atom__NET_WM_USER_TIME) + return; + + input_event = get_input_event (display, event); + + if (input_event) + meta_spew_xi2_event (display, input_event, &name, &extra); + else + meta_spew_core_event (display, event, &name, &extra); + + if (event->xany.window == screen->xroot) + winname = g_strdup_printf ("root %d", screen->number); + else + winname = g_strdup_printf ("0x%lx", event->xany.window); + + g_print ("%s on %s%s %s %sserial %lu\n", name, winname, + extra ? ":" : "", extra ? extra : "", + event->xany.send_event ? "SEND " : "", + event->xany.serial); + + g_free (winname); + + if (extra) + g_free (extra); +} + +static void +handle_window_focus_event (MetaDisplay *display, + MetaWindow *window, + XIEnterEvent *event, + unsigned long serial) +{ + MetaWindow *focus_window; +#ifdef WITH_VERBOSE_MODE + const char *window_type; + + /* Note the event can be on either the window or the frame, + * we focus the frame for shaded windows + */ + if (window) + { + if (event->event == window->xwindow) + window_type = "client window"; + else if (window->frame && event->event == window->frame->xwindow) + window_type = "frame window"; + else + window_type = "unknown client window"; + } + else if (meta_display_xwindow_is_a_no_focus_window (display, event->event)) + window_type = "no_focus_window"; + else if (event->event == display->screen->xroot) + window_type = "root window"; + else + window_type = "unknown window"; + + meta_topic (META_DEBUG_FOCUS, + "Focus %s event received on %s 0x%lx (%s) " + "mode %s detail %s serial %lu\n", + event->evtype == XI_FocusIn ? "in" : + event->evtype == XI_FocusOut ? "out" : + "???", + window ? window->desc : "", + event->event, window_type, + meta_event_mode_to_string (event->mode), + meta_event_detail_to_string (event->mode), + event->serial); +#endif + + /* FIXME our pointer tracking is broken; see how + * gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c + * for how to handle it the correct way. In brief you need to track + * pointer focus and regular focus, and handle EnterNotify in + * PointerRoot mode with no window manager. However as noted above, + * accurate focus tracking will break things because we want to keep + * windows "focused" when using keybindings on them, and also we + * sometimes "focus" a window by focusing its frame or + * no_focus_window; so this all needs rethinking massively. + * + * My suggestion is to change it so that we clearly separate + * actual keyboard focus tracking using the xterm algorithm, + * and mutter's "pretend" focus window, and go through all + * the code and decide which one should be used in each place; + * a hard bit is deciding on a policy for that. + * + * http://bugzilla.gnome.org/show_bug.cgi?id=90382 + */ + + /* We ignore grabs, though this is questionable. It may be better to + * increase the intelligence of the focus window tracking. + * + * The problem is that keybindings for windows are done with + * XGrabKey, which means focus_window disappears and the front of + * the MRU list gets confused from what the user expects once a + * keybinding is used. + */ + + if (event->mode == XINotifyGrab || + event->mode == XINotifyUngrab || + /* From WindowMaker, ignore all funky pointer root events */ + event->detail > XINotifyNonlinearVirtual) + { + meta_topic (META_DEBUG_FOCUS, + "Ignoring focus event generated by a grab or other weirdness\n"); + return; + } + + if (event->evtype == XI_FocusIn) + { + display->server_focus_window = event->event; + display->server_focus_serial = serial; + focus_window = window; + } + else if (event->evtype == XI_FocusOut) + { + if (event->detail == XINotifyInferior) + { + /* This event means the client moved focus to a subwindow */ + meta_topic (META_DEBUG_FOCUS, + "Ignoring focus out with NotifyInferior\n"); + return; + } + + display->server_focus_window = None; + display->server_focus_serial = serial; + focus_window = NULL; + } + else + g_return_if_reached (); + + /* If display->focused_by_us, then the focus_serial will be used only + * for a focus change we made and have already accounted for. + * (See request_xserver_input_focus_change().) Otherwise, we can get + * multiple focus events with the same serial. + */ + if (display->server_focus_serial > display->focus_serial || + (!display->focused_by_us && + display->server_focus_serial == display->focus_serial)) + { + meta_display_update_focus_window (display, + focus_window, + focus_window ? focus_window->xwindow : None, + display->server_focus_serial, + FALSE); + } +} + +static gboolean +crossing_serial_is_ignored (MetaDisplay *display, + unsigned long serial) +{ + int i; + + i = 0; + while (i < N_IGNORED_CROSSING_SERIALS) + { + if (display->ignored_crossing_serials[i] == serial) + return TRUE; + ++i; + } + return FALSE; +} + +static gboolean +handle_input_xevent (MetaDisplay *display, + XIEvent *input_event, + gulong serial) +{ + XIEnterEvent *enter_event = (XIEnterEvent *) input_event; + Window modified; + MetaWindow *window; + MetaScreen *screen = display->screen; + + if (input_event == NULL) + return FALSE; + + switch (input_event->evtype) + { + case XI_Enter: + case XI_Leave: + case XI_FocusIn: + case XI_FocusOut: + break; + default: + return FALSE; + } + + modified = xievent_get_modified_window (display, input_event); + window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL; + + /* If this is an event for a GTK+ widget, let GTK+ handle it. */ + if (meta_ui_window_is_widget (display->screen->ui, modified)) + return FALSE; + + switch (input_event->evtype) + { + case XI_Enter: + if (display->grab_op == META_GRAB_OP_COMPOSITOR) + break; + + /* Check if we've entered a window; do this even if window->has_focus to + * avoid races. + */ + if (window && !crossing_serial_is_ignored (display, serial) && + enter_event->mode != XINotifyGrab && + enter_event->mode != XINotifyUngrab && + enter_event->detail != XINotifyInferior && + meta_display_focus_sentinel_clear (display)) + { + meta_window_handle_enter (window, + enter_event->time, + enter_event->root_x, + enter_event->root_y); + + if (window->type == META_WINDOW_DOCK) + meta_window_raise (window); + } + break; + case XI_Leave: + if (display->grab_op == META_GRAB_OP_COMPOSITOR) + break; + + if (window != NULL) + { + if (window->type == META_WINDOW_DOCK && + enter_event->mode != XINotifyGrab && + enter_event->mode != XINotifyUngrab && + !window->has_focus) + meta_window_lower (window); + } + break; + case XI_FocusIn: + case XI_FocusOut: + handle_window_focus_event (display, window, enter_event, serial); + if (!window) + { + /* Check if the window is a root window. */ + if (enter_event->root != enter_event->event) + break; + + if (enter_event->evtype == XI_FocusIn && + enter_event->mode == XINotifyDetailNone) + { + meta_topic (META_DEBUG_FOCUS, + "Focus got set to None, probably due to " + "brain-damage in the X protocol (see bug " + "125492). Setting the default focus window.\n"); + meta_workspace_focus_default_window (screen->active_workspace, + NULL, + meta_display_get_current_time_roundtrip (display)); + } + else if (enter_event->evtype == XI_FocusIn && + enter_event->mode == XINotifyNormal && + enter_event->detail == XINotifyInferior) + { + meta_topic (META_DEBUG_FOCUS, + "Focus got set to root window, probably due to " + "gnome-session logout dialog usage (see bug " + "153220). Setting the default focus window.\n"); + meta_workspace_focus_default_window (screen->active_workspace, + NULL, + meta_display_get_current_time_roundtrip (display)); + } + + } + break; + } + + /* Don't pass these events through to Clutter / GTK+ */ + return TRUE; +} + +static void +reload_xkb_rules (MetaScreen *screen) +{ + MetaWaylandCompositor *compositor; + char **names; + int n_names; + gboolean ok; + const char *rules, *model, *layout, *variant, *options; + + compositor = meta_wayland_compositor_get_default (); + + ok = meta_prop_get_latin1_list (screen->display, screen->xroot, + screen->display->atom__XKB_RULES_NAMES, + &names, &n_names); + if (!ok) + return; + + if (n_names != 5) + goto out; + + rules = names[0]; + model = names[1]; + layout = names[2]; + variant = names[3]; + options = names[4]; + + meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard, + rules, model, layout, variant, options, + META_WAYLAND_KEYBOARD_SKIP_XCLIENTS); + + out: + g_strfreev (names); +} + +static void +process_request_frame_extents (MetaDisplay *display, + XEvent *event) +{ + /* The X window whose frame extents will be set. */ + Window xwindow = event->xclient.window; + unsigned long data[4] = { 0, 0, 0, 0 }; + + MotifWmHints *hints = NULL; + gboolean hints_set = FALSE; + + meta_verbose ("Setting frame extents for 0x%lx\n", xwindow); + + /* See if the window is decorated. */ + hints_set = meta_prop_get_motif_hints (display, + xwindow, + display->atom__MOTIF_WM_HINTS, + &hints); + if ((hints_set && hints->decorations) || !hints_set) + { + MetaFrameBorders borders; + + /* Return estimated frame extents for a normal window. */ + meta_ui_theme_get_frame_borders (display->screen->ui, + META_FRAME_TYPE_NORMAL, + 0, + &borders); + data[0] = borders.visible.left; + data[1] = borders.visible.right; + data[2] = borders.visible.top; + data[3] = borders.visible.bottom; + } + + meta_topic (META_DEBUG_GEOMETRY, + "Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx " + "to top = %lu, left = %lu, bottom = %lu, right = %lu\n", + xwindow, data[0], data[1], data[2], data[3]); + + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, xwindow, + display->atom__NET_FRAME_EXTENTS, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 4); + meta_error_trap_pop (display); + + meta_XFree (hints); +} + +/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ +static gboolean +convert_property (MetaDisplay *display, + MetaScreen *screen, + Window w, + Atom target, + Atom property) +{ +#define N_TARGETS 4 + Atom conversion_targets[N_TARGETS]; + long icccm_version[] = { 2, 0 }; + + conversion_targets[0] = display->atom_TARGETS; + conversion_targets[1] = display->atom_MULTIPLE; + conversion_targets[2] = display->atom_TIMESTAMP; + conversion_targets[3] = display->atom_VERSION; + + meta_error_trap_push (display); + if (target == display->atom_TARGETS) + XChangeProperty (display->xdisplay, w, property, + XA_ATOM, 32, PropModeReplace, + (unsigned char *)conversion_targets, N_TARGETS); + else if (target == display->atom_TIMESTAMP) + XChangeProperty (display->xdisplay, w, property, + XA_INTEGER, 32, PropModeReplace, + (unsigned char *)&screen->wm_sn_timestamp, 1); + else if (target == display->atom_VERSION) + XChangeProperty (display->xdisplay, w, property, + XA_INTEGER, 32, PropModeReplace, + (unsigned char *)icccm_version, 2); + else + { + meta_error_trap_pop_with_return (display); + return FALSE; + } + + if (meta_error_trap_pop_with_return (display) != Success) + return FALSE; + + /* Be sure the PropertyNotify has arrived so we + * can send SelectionNotify + */ + /* FIXME the error trap pop synced anyway, right? */ + meta_topic (META_DEBUG_SYNC, "Syncing on %s\n", G_STRFUNC); + XSync (display->xdisplay, False); + + return TRUE; +} + +/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */ +static void +process_selection_request (MetaDisplay *display, + XEvent *event) +{ + MetaScreen *screen = display->screen; + XSelectionEvent reply; + + if (screen->wm_sn_selection_window != event->xselectionrequest.owner || + screen->wm_sn_atom != event->xselectionrequest.selection) + { + char *str; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xselectionrequest.selection); + meta_error_trap_pop (display); + + meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize\n", + str ? str : "(bad atom)", event->xselectionrequest.owner); + + meta_XFree (str); + + return; + } + + reply.type = SelectionNotify; + reply.display = display->xdisplay; + reply.requestor = event->xselectionrequest.requestor; + reply.selection = event->xselectionrequest.selection; + reply.target = event->xselectionrequest.target; + reply.property = None; + reply.time = event->xselectionrequest.time; + + if (event->xselectionrequest.target == display->atom_MULTIPLE) + { + if (event->xselectionrequest.property != None) + { + Atom type, *adata; + int i, format; + unsigned long num, rest; + unsigned char *data; + + meta_error_trap_push (display); + if (XGetWindowProperty (display->xdisplay, + event->xselectionrequest.requestor, + event->xselectionrequest.property, 0, 256, False, + display->atom_ATOM_PAIR, + &type, &format, &num, &rest, &data) != Success) + { + meta_error_trap_pop_with_return (display); + return; + } + + if (meta_error_trap_pop_with_return (display) == Success) + { + /* FIXME: to be 100% correct, should deal with rest > 0, + * but since we have 4 possible targets, we will hardly ever + * meet multiple requests with a length > 8 + */ + adata = (Atom*)data; + i = 0; + while (i < (int) num) + { + if (!convert_property (display, screen, + event->xselectionrequest.requestor, + adata[i], adata[i+1])) + adata[i+1] = None; + i += 2; + } + + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, + event->xselectionrequest.requestor, + event->xselectionrequest.property, + display->atom_ATOM_PAIR, + 32, PropModeReplace, data, num); + meta_error_trap_pop (display); + meta_XFree (data); + } + } + } + else + { + if (event->xselectionrequest.property == None) + event->xselectionrequest.property = event->xselectionrequest.target; + + if (convert_property (display, screen, + event->xselectionrequest.requestor, + event->xselectionrequest.target, + event->xselectionrequest.property)) + reply.property = event->xselectionrequest.property; + } + + XSendEvent (display->xdisplay, + event->xselectionrequest.requestor, + False, 0L, (XEvent*)&reply); + + meta_verbose ("Handled selection request\n"); +} + +static void +process_selection_clear (MetaDisplay *display, + XEvent *event) +{ + MetaScreen *screen = display->screen; + + if (screen->wm_sn_selection_window != event->xselectionclear.window || + screen->wm_sn_atom != event->xselectionclear.selection) + { + char *str; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xselectionclear.selection); + meta_error_trap_pop (display); + + meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize\n", + str ? str : "(bad atom)", event->xselectionclear.window); + + meta_XFree (str); + + return; + } + + meta_verbose ("Got selection clear for screen %d on display %s\n", + screen->number, display->name); + + meta_display_unmanage_screen (display, display->screen, + event->xselectionclear.time); +} + +static gboolean +handle_other_xevent (MetaDisplay *display, + XEvent *event) +{ + Window modified; + MetaWindow *window; + MetaWindow *property_for_window; + gboolean frame_was_receiver; + gboolean bypass_gtk = FALSE; + + modified = event_get_modified_window (display, event); + window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL; + frame_was_receiver = (window && window->frame && modified == window->frame->xwindow); + + /* We only want to respond to _NET_WM_USER_TIME property notify + * events on _NET_WM_USER_TIME_WINDOW windows; in particular, + * responding to UnmapNotify events is kind of bad. + */ + property_for_window = NULL; + if (window && modified == window->user_time_window) + { + property_for_window = window; + window = NULL; + } + +#ifdef HAVE_XSYNC + if (META_DISPLAY_HAS_XSYNC (display) && + event->type == (display->xsync_event_base + XSyncAlarmNotify)) + { + MetaWindow *alarm_window = meta_display_lookup_sync_alarm (display, + ((XSyncAlarmNotifyEvent*)event)->alarm); + + if (alarm_window != NULL) + { + XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value; + gint64 new_counter_value; + new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32); + meta_window_update_sync_request_counter (alarm_window, new_counter_value); + bypass_gtk = TRUE; /* GTK doesn't want to see this really */ + } + else + meta_idle_monitor_xsync_handle_xevent_all (event); + + goto out; + } +#endif /* HAVE_XSYNC */ + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display) && + event->type == (display->shape_event_base + ShapeNotify)) + { + bypass_gtk = TRUE; /* GTK doesn't want to see this really */ + + if (window && !frame_was_receiver) + { + XShapeEvent *sev = (XShapeEvent*) event; + + if (sev->kind == ShapeBounding) + meta_window_x11_update_shape_region (window); + else if (sev->kind == ShapeInput) + meta_window_x11_update_input_region (window); + } + else + { + meta_topic (META_DEBUG_SHAPES, + "ShapeNotify not on a client window (window %s frame_was_receiver = %d)\n", + window ? window->desc : "(none)", + frame_was_receiver); + } + + goto out; + } +#endif /* HAVE_SHAPE */ + + switch (event->type) + { + case KeymapNotify: + break; + case Expose: + break; + case GraphicsExpose: + break; + case NoExpose: + break; + case VisibilityNotify: + break; + case CreateNotify: + { + if (event->xcreatewindow.parent == display->screen->xroot) + meta_stack_tracker_create_event (display->screen->stack_tracker, + &event->xcreatewindow); + } + break; + + case DestroyNotify: + { + if (event->xdestroywindow.event == display->screen->xroot) + meta_stack_tracker_destroy_event (display->screen->stack_tracker, + &event->xdestroywindow); + } + if (window) + { + /* FIXME: It sucks that DestroyNotify events don't come with + * a timestamp; could we do something better here? Maybe X + * will change one day? + */ + guint32 timestamp; + timestamp = meta_display_get_current_time_roundtrip (display); + + if (display->grab_op != META_GRAB_OP_NONE && + display->grab_window == window) + meta_display_end_grab_op (display, timestamp); + + if (frame_was_receiver) + { + meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or be considered a bug\n", + window->frame->xwindow); + meta_error_trap_push (display); + meta_window_destroy_frame (window->frame->window); + meta_error_trap_pop (display); + } + else + { + /* Unmanage destroyed window */ + meta_window_unmanage (window, timestamp); + window = NULL; + } + } + break; + case UnmapNotify: + if (window) + { + /* FIXME: It sucks that UnmapNotify events don't come with + * a timestamp; could we do something better here? Maybe X + * will change one day? + */ + guint32 timestamp; + timestamp = meta_display_get_current_time_roundtrip (display); + + if (display->grab_op != META_GRAB_OP_NONE && + display->grab_window == window && + window->frame == NULL) + meta_display_end_grab_op (display, timestamp); + + if (!frame_was_receiver) + { + if (window->unmaps_pending == 0) + { + meta_topic (META_DEBUG_WINDOW_STATE, + "Window %s withdrawn\n", + window->desc); + + /* Unmanage withdrawn window */ + window->withdrawn = TRUE; + meta_window_unmanage (window, timestamp); + window = NULL; + } + else + { + window->unmaps_pending -= 1; + meta_topic (META_DEBUG_WINDOW_STATE, + "Received pending unmap, %d now pending\n", + window->unmaps_pending); + } + } + } + break; + case MapNotify: + /* NB: override redirect windows wont cause a map request so we + * watch out for map notifies against any root windows too if a + * compositor is enabled: */ + if (window == NULL && event->xmap.event == display->screen->xroot) + { + window = meta_window_x11_new (display, event->xmap.window, + FALSE, META_COMP_EFFECT_CREATE); + } + break; + case MapRequest: + if (window == NULL) + { + window = meta_window_x11_new (display, event->xmaprequest.window, + FALSE, META_COMP_EFFECT_CREATE); + } + /* if frame was receiver it's some malicious send event or something */ + else if (!frame_was_receiver && window) + { + meta_verbose ("MapRequest on %s mapped = %d minimized = %d\n", + window->desc, window->mapped, window->minimized); + if (window->minimized) + { + meta_window_unminimize (window); + if (window->workspace != window->screen->active_workspace) + { + meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n", + window->mapped, window->minimized); + meta_window_change_workspace (window, + window->screen->active_workspace); + } + } + } + break; + case ReparentNotify: + { + if (event->xreparent.event == display->screen->xroot) + meta_stack_tracker_reparent_event (display->screen->stack_tracker, + &event->xreparent); + } + break; + case ConfigureNotify: + if (event->xconfigure.event != event->xconfigure.window) + { + if (event->xconfigure.event == display->screen->xroot) + meta_stack_tracker_configure_event (display->screen->stack_tracker, + &event->xconfigure); + } + + if (window && window->override_redirect) + meta_window_x11_configure_notify (window, &event->xconfigure); + + break; + case ConfigureRequest: + /* This comment and code is found in both twm and fvwm */ + /* + * According to the July 27, 1988 ICCCM draft, we should ignore size and + * position fields in the WM_NORMAL_HINTS property when we map a window. + * Instead, we'll read the current geometry. Therefore, we should respond + * to configuration requests for windows which have never been mapped. + */ + if (window == NULL) + { + unsigned int xwcm; + XWindowChanges xwc; + + xwcm = event->xconfigurerequest.value_mask & + (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); + + xwc.x = event->xconfigurerequest.x; + xwc.y = event->xconfigurerequest.y; + xwc.width = event->xconfigurerequest.width; + xwc.height = event->xconfigurerequest.height; + xwc.border_width = event->xconfigurerequest.border_width; + + meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)\n", + xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width); + meta_error_trap_push (display); + XConfigureWindow (display->xdisplay, event->xconfigurerequest.window, + xwcm, &xwc); + meta_error_trap_pop (display); + } + else + { + if (!frame_was_receiver) + meta_window_x11_configure_request (window, event); + } + break; + case GravityNotify: + break; + case ResizeRequest: + break; + case CirculateNotify: + break; + case CirculateRequest: + break; + case PropertyNotify: + { + MetaGroup *group; + + if (window && !frame_was_receiver) + meta_window_x11_property_notify (window, event); + else if (property_for_window && !frame_was_receiver) + meta_window_x11_property_notify (property_for_window, event); + + group = meta_display_lookup_group (display, + event->xproperty.window); + if (group != NULL) + meta_group_property_notify (group, event); + + if (event->xproperty.window == display->screen->xroot) + { + if (event->xproperty.atom == + display->atom__NET_DESKTOP_LAYOUT) + meta_screen_update_workspace_layout (display->screen); + else if (event->xproperty.atom == + display->atom__NET_DESKTOP_NAMES) + meta_screen_update_workspace_names (display->screen); + else if (meta_is_wayland_compositor () && + event->xproperty.atom == + display->atom__XKB_RULES_NAMES) + reload_xkb_rules (display->screen); +#if 0 + else if (event->xproperty.atom == + display->atom__NET_RESTACK_WINDOW) + handle_net_restack_window (display, event); +#endif + + /* we just use this property as a sentinel to avoid + * certain race conditions. See the comment for the + * sentinel_counter variable declaration in display.h + */ + if (event->xproperty.atom == + display->atom__MUTTER_SENTINEL) + { + meta_display_decrement_focus_sentinel (display); + } + } + } + break; + case SelectionClear: + /* do this here instead of at end of function + * so we can return + */ + + /* FIXME: Clearing display->current_time here makes no sense to + * me; who put this here and why? + */ + display->current_time = CurrentTime; + + process_selection_clear (display, event); + /* Note that processing that may have resulted in + * closing the display... so return right away. + */ + return FALSE; + case SelectionRequest: + process_selection_request (display, event); + break; + case SelectionNotify: + break; + case ColormapNotify: + break; + case ClientMessage: + if (window) + { + if (event->xclient.message_type == display->atom_WL_SURFACE_ID) + { + guint32 surface_id = event->xclient.data.l[0]; + meta_xwayland_handle_wl_surface_id (window, surface_id); + } + else if (!frame_was_receiver) + meta_window_x11_client_message (window, event); + } + else + { + if (event->xclient.window == display->screen->xroot) + { + if (event->xclient.message_type == + display->atom__NET_CURRENT_DESKTOP) + { + int space; + MetaWorkspace *workspace; + guint32 time; + + space = event->xclient.data.l[0]; + time = event->xclient.data.l[1]; + + meta_verbose ("Request to change current workspace to %d with " + "specified timestamp of %u\n", + space, time); + + workspace = meta_screen_get_workspace_by_index (display->screen, space); + + /* Handle clients using the older version of the spec... */ + if (time == 0 && workspace) + { + meta_warning ("Received a NET_CURRENT_DESKTOP message " + "from a broken (outdated) client who sent " + "a 0 timestamp\n"); + time = meta_display_get_current_time_roundtrip (display); + } + + if (workspace) + meta_workspace_activate (workspace, time); + else + meta_verbose ("Don't know about workspace %d\n", space); + } + else if (event->xclient.message_type == + display->atom__NET_NUMBER_OF_DESKTOPS) + { + int num_spaces; + + num_spaces = event->xclient.data.l[0]; + + meta_verbose ("Request to set number of workspaces to %d\n", + num_spaces); + + meta_prefs_set_num_workspaces (num_spaces); + } + else if (event->xclient.message_type == + display->atom__NET_SHOWING_DESKTOP) + { + gboolean showing_desktop; + guint32 timestamp; + + showing_desktop = event->xclient.data.l[0] != 0; + /* FIXME: Braindead protocol doesn't have a timestamp */ + timestamp = meta_display_get_current_time_roundtrip (display); + meta_verbose ("Request to %s desktop\n", + showing_desktop ? "show" : "hide"); + + if (showing_desktop) + meta_screen_show_desktop (display->screen, timestamp); + else + { + meta_screen_unshow_desktop (display->screen); + meta_workspace_focus_default_window (display->screen->active_workspace, NULL, timestamp); + } + } + else if (event->xclient.message_type == + display->atom_WM_PROTOCOLS) + { + meta_verbose ("Received WM_PROTOCOLS message\n"); + + if ((Atom)event->xclient.data.l[0] == display->atom__NET_WM_PING) + { + guint32 timestamp = event->xclient.data.l[1]; + + meta_display_pong_for_serial (display, timestamp); + + /* We don't want ping reply events going into + * the GTK+ event loop because gtk+ will treat + * them as ping requests and send more replies. + */ + bypass_gtk = TRUE; + } + } + } + + if (event->xclient.message_type == + display->atom__NET_REQUEST_FRAME_EXTENTS) + { + meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message\n"); + process_request_frame_extents (display, event); + } + } + break; + case MappingNotify: + { + gboolean ignore_current; + + ignore_current = FALSE; + + /* Check whether the next event is an identical MappingNotify + * event. If it is, ignore the current event, we'll update + * when we get the next one. + */ + if (XPending (display->xdisplay)) + { + XEvent next_event; + + XPeekEvent (display->xdisplay, &next_event); + + if (next_event.type == MappingNotify && + next_event.xmapping.request == event->xmapping.request) + ignore_current = TRUE; + } + + if (!ignore_current) + { + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&event->xmapping); + meta_display_process_mapping_event (display, event); + } + } + break; + default: +#ifdef HAVE_XKB + if (event->type == display->xkb_base_event_type) + { + XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event; + + switch (xkb_ev->xkb_type) + { + case XkbBellNotify: + if (XSERVER_TIME_IS_BEFORE(display->last_bell_time, + xkb_ev->time - 100)) + { + display->last_bell_time = xkb_ev->time; + meta_bell_notify (display, xkb_ev); + } + break; + case XkbNewKeyboardNotify: + case XkbMapNotify: + if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID) + meta_display_process_mapping_event (display, event); + break; + } + } +#endif + break; + } + + out: + return bypass_gtk; +} + +static gboolean +grab_op_should_block_mouse_events (MetaGrabOp op) +{ + switch (op) + { + case META_GRAB_OP_WAYLAND_CLIENT: + case META_GRAB_OP_COMPOSITOR: + return TRUE; + + default: + return FALSE; + } +} + +static gboolean +window_has_xwindow (MetaWindow *window, + Window xwindow) +{ + if (window->xwindow == xwindow) + return TRUE; + + if (window->frame && window->frame->xwindow == xwindow) + return TRUE; + + return FALSE; +} + +/** + * meta_display_handle_xevent: + * @display: The MetaDisplay that events are coming from + * @event: The event that just happened + * + * This is the most important function in the whole program. It is the heart, + * it is the nexus, it is the Grand Central Station of Mutter's world. + * When we create a #MetaDisplay, we ask GDK to pass *all* events for *all* + * windows to this function. So every time anything happens that we might + * want to know about, this function gets called. You see why it gets a bit + * busy around here. Most of this function is a ginormous switch statement + * dealing with all the kinds of events that might turn up. + */ +static gboolean +meta_display_handle_xevent (MetaDisplay *display, + XEvent *event) +{ + Window modified; + gboolean bypass_compositor = FALSE, bypass_gtk = FALSE; + XIEvent *input_event; + MetaMonitorManager *monitor; + +#if 0 + meta_spew_event (display, event); +#endif + +#ifdef HAVE_STARTUP_NOTIFICATION + if (sn_display_process_event (display->sn_display, event)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } +#endif + + /* Intercept XRandR events early and don't attempt any + processing for them. We still let them through to Gdk though, + so it can update its own internal state. + */ + monitor = meta_monitor_manager_get (); + if (meta_monitor_manager_handle_xevent (monitor, event)) + { + bypass_compositor = TRUE; + goto out; + } + + display->current_time = event_get_time (display, event); + display->monitor_cache_invalidated = TRUE; + + if (display->focused_by_us && + event->xany.serial > display->focus_serial && + display->focus_window && + !window_has_xwindow (display->focus_window, display->server_focus_window)) + { + meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n", + display->focus_window->desc); + meta_display_update_focus_window (display, + meta_display_lookup_x_window (display, display->server_focus_window), + display->server_focus_window, + display->server_focus_serial, + FALSE); + } + + if (event->xany.window == display->screen->xroot) + { + if (meta_screen_handle_xevent (display->screen, event)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } + } + + modified = event_get_modified_window (display, event); + + input_event = get_input_event (display, event); + + if (event->type == UnmapNotify) + { + if (meta_ui_window_should_not_cause_focus (display->xdisplay, + modified)) + { + meta_display_add_ignored_crossing_serial (display, event->xany.serial); + meta_topic (META_DEBUG_FOCUS, + "Adding EnterNotify serial %lu to ignored focus serials\n", + event->xany.serial); + } + } + else if (input_event && + input_event->evtype == XI_Leave && + ((XILeaveEvent *)input_event)->mode == XINotifyUngrab && + modified == display->ungrab_should_not_cause_focus_window) + { + meta_display_add_ignored_crossing_serial (display, event->xany.serial); + meta_topic (META_DEBUG_FOCUS, + "Adding LeaveNotify serial %lu to ignored focus serials\n", + event->xany.serial); + } + +#ifdef HAVE_XI23 + if (meta_display_process_barrier_event (display, input_event)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } +#endif /* HAVE_XI23 */ + + /* libXi does not properly copy the serial to XI2 events, so pull it + * from the parent XAnyEvent and pass it to handle_input_xevent. + * See: https://bugs.freedesktop.org/show_bug.cgi?id=64687 + */ + if (handle_input_xevent (display, input_event, event->xany.serial)) + { + bypass_gtk = bypass_compositor = TRUE; + goto out; + } + + if (handle_other_xevent (display, event)) + { + bypass_gtk = TRUE; + goto out; + } + + out: + if (!bypass_compositor) + { + MetaWindow *window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL; + + if (meta_compositor_process_event (display->compositor, event, window)) + bypass_gtk = TRUE; + } + + display->current_time = CurrentTime; + return bypass_gtk; +} + +static void +handle_idletime_for_event (const ClutterEvent *event) +{ + ClutterInputDevice *device, *source_device; + MetaIdleMonitor *core_monitor, *device_monitor; + int device_id; + + /* This is handled by XSync under X11. */ + if (!meta_is_wayland_compositor ()) + return; + + device = clutter_event_get_device (event); + if (device == NULL) + return; + + device_id = clutter_input_device_get_device_id (device); + + core_monitor = meta_idle_monitor_get_core (); + device_monitor = meta_idle_monitor_get_for_device (device_id); + + meta_idle_monitor_native_reset_idletime (core_monitor); + meta_idle_monitor_native_reset_idletime (device_monitor); + + source_device = clutter_event_get_source_device (event); + if (source_device != device) + { + device_id = clutter_input_device_get_device_id (device); + device_monitor = meta_idle_monitor_get_for_device (device_id); + meta_idle_monitor_native_reset_idletime (device_monitor); + } +} + +static gboolean +meta_display_handle_event (MetaDisplay *display, + const ClutterEvent *event) +{ + MetaWindow *window; + gboolean bypass_clutter = FALSE, bypass_wayland = FALSE; + MetaWaylandCompositor *compositor = NULL; + + if (meta_is_wayland_compositor ()) + { + compositor = meta_wayland_compositor_get_default (); + meta_wayland_compositor_update (compositor, event); + } + + handle_idletime_for_event (event); + + window = get_window_for_event (display, event); + + display->current_time = event->any.time; + + if (window && !window->override_redirect && + (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS)) + { + if (CurrentTime == display->current_time) + { + /* We can't use missing (i.e. invalid) timestamps to set user time, + * nor do we want to use them to sanity check other timestamps. + * See bug 313490 for more details. + */ + meta_warning ("Event has no timestamp! You may be using a broken " + "program such as xse. Please ask the authors of that " + "program to fix it.\n"); + } + else + { + meta_window_set_user_time (window, display->current_time); + meta_display_sanity_check_timestamps (display, display->current_time); + } + } + + switch (event->type) + { + case CLUTTER_BUTTON_PRESS: + if (grab_op_should_block_mouse_events (display->grab_op)) + break; + + display->overlay_key_only_pressed = FALSE; + + if ((window && + meta_grab_op_is_mouse (display->grab_op) && + (event->button.modifier_state & display->window_grab_modifiers) && + display->grab_button != (int) event->button.button && + display->grab_window == window) || + meta_grab_op_is_keyboard (display->grab_op)) + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Ending grab op %u on window %s due to button press\n", + display->grab_op, + (display->grab_window ? + display->grab_window->desc : + "none")); + meta_display_end_grab_op (display, event->any.time); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + else if (window && display->grab_op == META_GRAB_OP_NONE) + { + ClutterModifierType grab_mask; + gboolean unmodified; + gboolean fully_modified; + + grab_mask = display->window_grab_modifiers; + if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS")) + grab_mask |= CLUTTER_CONTROL_MASK; + + /* We have three passive button grabs: + * - on any button, without modifiers => focuses and maybe raises the window + * - on resize button, with modifiers => start an interactive resizing + * (normally middle) + * - on move button, with modifiers => start an interactive move + * (normally left) + * - on menu button, with modifiers => show the window menu + * (normally right) + * + * We may get here because we actually have a button + * grab on the window, or because we're a wayland + * compositor and thus we see all the events, so we + * need to check if the event is interesting. + * We want an event that is not modified, for a window + * that has (or would have, the wayland case) the + * button grab active. + * + * We may have other events on the window, for example + * a click on a frame button, but that's not for us to + * care about. Just let the event through. + */ + unmodified = (event->button.modifier_state & grab_mask) == 0; + fully_modified = grab_mask && (event->button.modifier_state & grab_mask) == grab_mask; + + if (unmodified && window && window->have_focus_click_grab) + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + else + meta_topic (META_DEBUG_FOCUS, + "Not raising window on click due to don't-raise-on-click option\n"); + + /* Don't focus panels--they must explicitly request focus. + * See bug 160470 + */ + if (window->type != META_WINDOW_DOCK) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing %s due to unmodified button %u press (display.c)\n", + window->desc, event->button.button); + meta_window_focus (window, event->any.time); + } + else + /* However, do allow terminals to lose focus due to new + * window mappings after the user clicks on a panel. + */ + display->allow_terminal_deactivation = TRUE; + + meta_verbose ("Allowing events time %u\n", + (unsigned int)event->button.time); + + XIAllowEvents (display->xdisplay, clutter_input_device_get_device_id (event->button.device), + XIReplayDevice, event->button.time); + bypass_clutter = TRUE; + } + else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_resize ()) + { + if (window->has_resize_func) + { + gboolean north, south; + gboolean west, east; + MetaRectangle frame_rect; + MetaGrabOp op; + + meta_window_get_frame_rect (window, &frame_rect); + + west = event->button.x < (frame_rect.x + 1 * frame_rect.width / 3); + east = event->button.x > (frame_rect.x + 2 * frame_rect.width / 3); + north = event->button.y < (frame_rect.y + 1 * frame_rect.height / 3); + south = event->button.y > (frame_rect.y + 2 * frame_rect.height / 3); + + if (north && west) + op = META_GRAB_OP_RESIZING_NW; + else if (north && east) + op = META_GRAB_OP_RESIZING_NE; + else if (south && west) + op = META_GRAB_OP_RESIZING_SW; + else if (south && east) + op = META_GRAB_OP_RESIZING_SE; + else if (north) + op = META_GRAB_OP_RESIZING_N; + else if (west) + op = META_GRAB_OP_RESIZING_W; + else if (east) + op = META_GRAB_OP_RESIZING_E; + else if (south) + op = META_GRAB_OP_RESIZING_S; + else /* Middle region is no-op to avoid user triggering wrong action */ + op = META_GRAB_OP_NONE; + + if (op != META_GRAB_OP_NONE) + meta_display_begin_grab_op (display, + window->screen, + window, + op, + TRUE, + FALSE, + event->button.button, + 0, + event->any.time, + event->button.x, + event->button.y); + } + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_menu ()) + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + meta_window_show_menu (window, + event->button.x, + event->button.y, + event->button.button, + event->any.time); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + else if (fully_modified && (int) event->button.button == 1) + { + if (window->has_move_func) + { + meta_display_begin_grab_op (display, + window->screen, + window, + META_GRAB_OP_MOVING, + TRUE, + FALSE, + event->button.button, + 0, + event->any.time, + event->button.x, + event->button.y); + } + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + } + break; + case CLUTTER_BUTTON_RELEASE: + if (grab_op_should_block_mouse_events (display->grab_op)) + break; + + display->overlay_key_only_pressed = FALSE; + + if (display->grab_window == window && + meta_grab_op_is_mouse (display->grab_op)) + { + meta_window_handle_mouse_grab_op_event (window, event); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + break; + case CLUTTER_MOTION: + if (grab_op_should_block_mouse_events (display->grab_op)) + break; + + if (display->grab_window == window && + meta_grab_op_is_mouse (display->grab_op)) + { + meta_window_handle_mouse_grab_op_event (window, event); + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + break; + + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + /* For key events, it's important to enforce single-handling, or + * we can get into a confused state. So if a keybinding is + * handled (because it's one of our hot-keys, or because we are + * in a keyboard-grabbed mode like moving a window, we don't + * want to pass the key event to the compositor or Wayland at all. + */ + if (meta_display_process_key_event (display, window, (ClutterKeyEvent *) event)) + { + bypass_clutter = TRUE; + bypass_wayland = TRUE; + } + + default: + break; + } + + /* If the compositor has a grab, don't pass that through to Wayland */ + if (display->grab_op == META_GRAB_OP_COMPOSITOR) + bypass_wayland = TRUE; + + /* If a Wayland client has a grab, don't pass that through to Clutter */ + if (display->grab_op == META_GRAB_OP_WAYLAND_CLIENT) + bypass_clutter = TRUE; + + if (compositor && !bypass_wayland) + { + if (meta_wayland_compositor_handle_event (compositor, event)) + bypass_clutter = TRUE; + } + + return bypass_clutter; +} + +static GdkFilterReturn +xevent_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + MetaDisplay *display = data; + + if (meta_display_handle_xevent (display, xevent)) + return GDK_FILTER_REMOVE; + else + return GDK_FILTER_CONTINUE; +} + +static gboolean +event_callback (const ClutterEvent *event, + gpointer data) +{ + MetaDisplay *display = data; + + return meta_display_handle_event (display, event); +} + +void +meta_display_init_events (MetaDisplay *display) +{ + gdk_window_add_filter (NULL, xevent_filter, display); + display->clutter_event_filter = clutter_event_add_filter (NULL, + event_callback, + NULL, + display); +} + +void +meta_display_free_events (MetaDisplay *display) +{ + gdk_window_remove_filter (NULL, xevent_filter, display); + clutter_event_remove_filter (display->clutter_event_filter); + display->clutter_event_filter = 0; +} diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/events.h similarity index 61% rename from src/core/meta-cursor-tracker-private.h rename to src/core/events.h index 55c09c440..66a34caa2 100644 --- a/src/core/meta-cursor-tracker-private.h +++ b/src/core/events.h @@ -1,7 +1,10 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* - * Copyright (C) 2013 Red Hat, Inc. + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. + * Copyright (C) 2003, 2004 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,18 +18,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . - * - * Author: Giovanni Campagna */ -#ifndef META_CURSOR_TRACKER_PRIVATE_H -#define META_CURSOR_TRACKER_PRIVATE_H +#include -#include +#ifndef META_EVENTS_H +#define META_EVENTS_H -gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, - XEvent *xevent); +void meta_display_init_events (MetaDisplay *display); +void meta_display_free_events (MetaDisplay *display); -void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, - MetaCursor cursor); #endif + diff --git a/src/core/frame.c b/src/core/frame.c index ed7e3cb59..350493c59 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -35,8 +35,7 @@ ButtonPressMask | ButtonReleaseMask | \ PointerMotionMask | PointerMotionHintMask | \ EnterWindowMask | LeaveWindowMask | \ - FocusChangeMask | \ - ColormapChangeMask) + FocusChangeMask) void meta_window_ensure_frame (MetaWindow *window) @@ -45,6 +44,7 @@ meta_window_ensure_frame (MetaWindow *window) XSetWindowAttributes attrs; Visual *visual; gulong create_serial; + MetaStackWindow stack_window; if (window->frame) return; @@ -100,8 +100,10 @@ meta_window_ensure_frame (MetaWindow *window) frame->rect.height, frame->window->screen->number, &create_serial); + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = frame->xwindow; meta_stack_tracker_record_add (window->screen->stack_tracker, - frame->xwindow, + &stack_window, create_serial); meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); @@ -125,8 +127,9 @@ meta_window_ensure_frame (MetaWindow *window) window->rect.x = 0; window->rect.y = 0; + stack_window.x11.xwindow = window->xwindow; meta_stack_tracker_record_remove (window->screen->stack_tracker, - window->xwindow, + &stack_window, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, @@ -161,6 +164,7 @@ meta_window_destroy_frame (MetaWindow *window) { MetaFrame *frame; MetaFrameBorders borders; + MetaStackWindow stack_window; if (window->frame == NULL) return; @@ -187,8 +191,10 @@ meta_window_destroy_frame (MetaWindow *window) "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc); window->unmaps_pending += 1; } + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = window->xwindow; meta_stack_tracker_record_add (window->screen->stack_tracker, - window->xwindow, + &stack_window, XNextRequest (window->display->xdisplay)); XReparentWindow (window->display->xdisplay, window->xwindow, diff --git a/src/core/keybindings-private.h b/src/core/keybindings-private.h index ffc40f100..15c1700bd 100644 --- a/src/core/keybindings-private.h +++ b/src/core/keybindings-private.h @@ -104,9 +104,9 @@ gboolean meta_window_grab_all_keys (MetaWindow *window, guint32 timestamp); void meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp); -gboolean meta_display_process_key_event (MetaDisplay *display, - MetaWindow *window, - XIDeviceEvent *event); +gboolean meta_display_process_key_event (MetaDisplay *display, + MetaWindow *window, + ClutterKeyEvent *event); void meta_display_process_mapping_event (MetaDisplay *display, XEvent *event); @@ -122,7 +122,3 @@ void meta_prefs_get_overlay_binding (MetaKeyCombo *combo); const char *meta_prefs_get_iso_next_group_option (void); #endif - - - - diff --git a/src/core/keybindings.c b/src/core/keybindings.c index 83b2f7096..8aa247af0 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -28,7 +28,6 @@ */ #define _GNU_SOURCE -#define _XOPEN_SOURCE /* for putenv() */ #include #include "keybindings-private.h" @@ -42,18 +41,26 @@ #include "screen-private.h" #include #include "util-private.h" +#include "meta-accel-parse.h" -#include #include #include #include +#include + +#include + #ifdef HAVE_XKB #include #endif +#include "wayland/meta-wayland.h" +#include "meta-backend.h" + #define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings" #define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings" +#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings" static gboolean add_builtin_keybinding (MetaDisplay *display, const char *name, @@ -109,23 +116,20 @@ meta_key_binding_is_builtin (MetaKeyBinding *binding) * handler functions and have some kind of flag to say they're unbindable. */ -static gboolean process_mouse_move_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym); +static gboolean process_mouse_move_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event); -static gboolean process_keyboard_move_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym); +static gboolean process_keyboard_move_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event); -static gboolean process_keyboard_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym); +static gboolean process_keyboard_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event); static void grab_key_bindings (MetaDisplay *display); static void ungrab_key_bindings (MetaDisplay *display); @@ -182,10 +186,6 @@ reload_keymap (MetaDisplay *display) if (display->keymap) meta_XFree (display->keymap); - /* This is expensive to compute, so we'll lazily load if and when we first - * need it */ - display->above_tab_keycode = 0; - display->keymap = XGetKeyboardMapping (display->xdisplay, display->min_keycode, display->max_keycode - @@ -193,24 +193,27 @@ reload_keymap (MetaDisplay *display) &display->keysyms_per_keycode); } +static const char * +keysym_name (xkb_keysym_t keysym) +{ + static char name[32] = ""; + xkb_keysym_get_name (keysym, name, sizeof (name)); + return name; +} + static void reload_modmap (MetaDisplay *display) { XModifierKeymap *modmap; int map_size; int i; - - if (display->modmap) - XFreeModifiermap (display->modmap); + int num_lock_mask = 0; + int scroll_lock_mask = 0; modmap = XGetModifierMapping (display->xdisplay); - display->modmap = modmap; - display->ignored_modifier_mask = 0; /* Multiple bits may get set in each of these */ - display->num_lock_mask = 0; - display->scroll_lock_mask = 0; display->meta_mask = 0; display->hyper_mask = 0; display->super_mask = 0; @@ -238,40 +241,37 @@ reload_modmap (MetaDisplay *display) { if (syms[j] != 0) { - const char *str; - - str = XKeysymToString (syms[j]); meta_topic (META_DEBUG_KEYBINDINGS, "Keysym %s bound to modifier 0x%x\n", - str ? str : "none", + keysym_name (syms[j]), (1 << ( i / modmap->max_keypermod))); } - if (syms[j] == XK_Num_Lock) + if (syms[j] == XKB_KEY_Num_Lock) { /* Mod1Mask is 1 << 3 for example, i.e. the * fourth modifier, i / keyspermod is the modifier * index */ - display->num_lock_mask |= (1 << ( i / modmap->max_keypermod)); + num_lock_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Scroll_Lock) + else if (syms[j] == XKB_KEY_Scroll_Lock) { - display->scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); + scroll_lock_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Super_L || - syms[j] == XK_Super_R) + else if (syms[j] == XKB_KEY_Super_L || + syms[j] == XKB_KEY_Super_R) { display->super_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Hyper_L || - syms[j] == XK_Hyper_R) + else if (syms[j] == XKB_KEY_Hyper_L || + syms[j] == XKB_KEY_Hyper_R) { display->hyper_mask |= (1 << ( i / modmap->max_keypermod)); } - else if (syms[j] == XK_Meta_L || - syms[j] == XK_Meta_R) + else if (syms[j] == XKB_KEY_Meta_L || + syms[j] == XKB_KEY_Meta_R) { display->meta_mask |= (1 << ( i / modmap->max_keypermod)); } @@ -283,18 +283,20 @@ reload_modmap (MetaDisplay *display) ++i; } - display->ignored_modifier_mask = (display->num_lock_mask | - display->scroll_lock_mask | + display->ignored_modifier_mask = (num_lock_mask | + scroll_lock_mask | LockMask); meta_topic (META_DEBUG_KEYBINDINGS, "Ignoring modmask 0x%x num lock 0x%x scroll lock 0x%x hyper 0x%x super 0x%x meta 0x%x\n", display->ignored_modifier_mask, - display->num_lock_mask, - display->scroll_lock_mask, + num_lock_mask, + scroll_lock_mask, display->hyper_mask, display->super_mask, display->meta_mask); + + XFreeModifiermap (modmap); } /* Original code from gdk_x11_keymap_get_entries_for_keyval() in @@ -310,6 +312,14 @@ get_keycodes_for_keysym (MetaDisplay *display, retval = g_array_new (FALSE, FALSE, sizeof (int)); + /* Special-case: Fake mutter keysym */ + if (keysym == META_KEY_ABOVE_TAB) + { + keycode = KEY_GRAVE + 8; + g_array_append_val (retval, keycode); + goto out; + } + keycode = display->min_keycode; while (keycode <= display->max_keycode) { @@ -327,12 +337,31 @@ get_keycodes_for_keysym (MetaDisplay *display, ++keycode; } + out: n_keycodes = retval->len; *keycodes = (int*) g_array_free (retval, n_keycodes == 0 ? TRUE : FALSE); - return n_keycodes; } +static guint +get_first_keycode_for_keysym (MetaDisplay *display, + guint keysym) +{ + int *keycodes; + int n_keycodes; + int keycode; + + n_keycodes = get_keycodes_for_keysym (display, keysym, &keycodes); + + if (n_keycodes > 0) + keycode = keycodes[0]; + else + keycode = 0; + + g_free (keycodes); + return keycode; +} + static void reload_iso_next_group_combos (MetaDisplay *display) { @@ -350,7 +379,7 @@ reload_iso_next_group_combos (MetaDisplay *display) if (iso_next_group_option == NULL) return; - n_keycodes = get_keycodes_for_keysym (display, XK_ISO_Next_Group, &keycodes); + n_keycodes = get_keycodes_for_keysym (display, XKB_KEY_ISO_Next_Group, &keycodes); if (g_str_equal (iso_next_group_option, "toggle") || g_str_equal (iso_next_group_option, "lalt_toggle") || @@ -369,7 +398,7 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = 0; } @@ -382,7 +411,7 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = ShiftMask; } @@ -395,7 +424,7 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = Mod1Mask; } @@ -409,11 +438,11 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = ShiftMask; - combos[i + n_keycodes].keysym = XK_ISO_Next_Group; + combos[i + n_keycodes].keysym = XKB_KEY_ISO_Next_Group; combos[i + n_keycodes].keycode = keycodes[i]; combos[i + n_keycodes].modifiers = ControlMask; } @@ -425,11 +454,11 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = Mod1Mask; - combos[i + n_keycodes].keysym = XK_ISO_Next_Group; + combos[i + n_keycodes].keysym = XKB_KEY_ISO_Next_Group; combos[i + n_keycodes].keycode = keycodes[i]; combos[i + n_keycodes].modifiers = ControlMask; } @@ -442,11 +471,11 @@ reload_iso_next_group_combos (MetaDisplay *display) for (i = 0; i < n_keycodes; ++i) { - combos[i].keysym = XK_ISO_Next_Group; + combos[i].keysym = XKB_KEY_ISO_Next_Group; combos[i].keycode = keycodes[i]; combos[i].modifiers = Mod1Mask; - combos[i + n_keycodes].keysym = XK_ISO_Next_Group; + combos[i + n_keycodes].keysym = XKB_KEY_ISO_Next_Group; combos[i + n_keycodes].keycode = keycodes[i]; combos[i + n_keycodes].modifiers = ShiftMask; } @@ -463,16 +492,6 @@ reload_iso_next_group_combos (MetaDisplay *display) display->iso_next_group_combos = combos; } -static guint -keysym_to_keycode (MetaDisplay *display, - guint keysym) -{ - if (keysym == META_KEY_ABOVE_TAB) - return meta_display_get_above_tab_keycode (display); - else - return XKeysymToKeycode (display->xdisplay, keysym); -} - static void binding_reload_keycode_foreach (gpointer key, gpointer value, @@ -482,7 +501,7 @@ binding_reload_keycode_foreach (gpointer key, MetaKeyBinding *binding = value; if (binding->keysym) - binding->keycode = keysym_to_keycode (display, binding->keysym); + binding->keycode = get_first_keycode_for_keysym (display, binding->keysym); } static void @@ -494,7 +513,7 @@ reload_keycodes (MetaDisplay *display) if (display->overlay_key_combo.keysym != 0) { display->overlay_key_combo.keycode = - keysym_to_keycode (display, display->overlay_key_combo.keysym); + get_first_keycode_for_keysym (display, display->overlay_key_combo.keysym); } else { @@ -686,15 +705,7 @@ ungrab_key_bindings (MetaDisplay *display) meta_error_trap_push (display); /* for efficiency push outer trap */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_ungrab_keys (screen); - - tmp = tmp->next; - } + meta_screen_ungrab_keys (display->screen); windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; @@ -719,15 +730,7 @@ grab_key_bindings (MetaDisplay *display) meta_error_trap_push (display); /* for efficiency push outer trap */ - tmp = display->screens; - while (tmp != NULL) - { - MetaScreen *screen = tmp->data; - - meta_screen_grab_keys (screen); - - tmp = tmp->next; - } + meta_screen_grab_keys (display->screen); windows = meta_display_list_windows (display, META_LIST_DEFAULT); tmp = windows; @@ -758,7 +761,8 @@ display_get_keybinding (MetaDisplay *display, } static guint -next_dynamic_keybinding_action () { +next_dynamic_keybinding_action (void) +{ static guint num_dynamic_bindings = 0; return META_KEYBINDING_ACTION_LAST + (++num_dynamic_bindings); } @@ -1014,25 +1018,10 @@ meta_display_shutdown_keys (MetaDisplay *display) if (display->keymap) meta_XFree (display->keymap); - if (display->modmap) - XFreeModifiermap (display->modmap); - g_hash_table_destroy (display->key_bindings_index); g_hash_table_destroy (display->key_bindings); } -static const char* -keysym_name (int keysym) -{ - const char *name; - - name = XKeysymToString (keysym); - if (name == NULL) - name = "(unknown)"; - - return name; -} - /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */ static void meta_change_keygrab (MetaDisplay *display, @@ -1081,7 +1070,7 @@ meta_change_keygrab (MetaDisplay *display, mods = (XIGrabModifiers) { modmask | ignored_mask, 0 }; if (meta_is_debugging ()) - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); if (grab) XIGrabKeycode (display->xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID, @@ -1102,7 +1091,7 @@ meta_change_keygrab (MetaDisplay *display, if (grab && result != Success) { if (result == BadAccess) - meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask); + meta_warning ("Some other program is already using the key %s with modifiers %x as a binding\n", keysym_name (keysym), modmask | ignored_mask); else meta_topic (META_DEBUG_KEYBINDINGS, "Failed to grab key %s with modifiers %x\n", @@ -1275,17 +1264,17 @@ meta_window_ungrab_keys (MetaWindow *window) } static void -handle_external_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer user_data) +handle_external_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer user_data) { guint action = meta_display_get_keybinding_action (display, binding->keycode, binding->mask); - meta_display_accelerator_activate (display, action, event->deviceid, event->time); + meta_display_accelerator_activate (display, action, event); } @@ -1299,19 +1288,18 @@ meta_display_grab_accelerator (MetaDisplay *display, guint keycode = 0; guint mask = 0; MetaVirtualModifier modifiers = 0; - GSList *l; - if (!meta_ui_parse_accelerator (accelerator, &keysym, &keycode, &modifiers)) + if (!meta_parse_accelerator (accelerator, &keysym, &keycode, &modifiers)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse accelerator\n"); - meta_warning (_("\"%s\" is not a valid accelerator\n"), accelerator); + meta_warning ("\"%s\" is not a valid accelerator\n", accelerator); return META_KEYBINDING_ACTION_NONE; } meta_display_devirtualize_modifiers (display, modifiers, &mask); - keycode = keysym_to_keycode (display, keysym); + keycode = get_first_keycode_for_keysym (display, keysym); if (keycode == 0) return META_KEYBINDING_ACTION_NONE; @@ -1319,11 +1307,7 @@ meta_display_grab_accelerator (MetaDisplay *display, if (display_get_keybinding (display, keycode, mask)) return META_KEYBINDING_ACTION_NONE; - for (l = display->screens; l; l = l->next) - { - MetaScreen *screen = l->data; - meta_change_keygrab (display, screen->xroot, TRUE, keysym, keycode, mask); - } + meta_change_keygrab (display, display->screen->xroot, TRUE, keysym, keycode, mask); grab = g_new0 (MetaKeyGrab, 1); grab->action = next_dynamic_keybinding_action (); @@ -1367,22 +1351,17 @@ meta_display_ungrab_accelerator (MetaDisplay *display, return FALSE; meta_display_devirtualize_modifiers (display, grab->combo->modifiers, &mask); - keycode = keysym_to_keycode (display, grab->combo->keysym); + keycode = get_first_keycode_for_keysym (display, grab->combo->keysym); binding = display_get_keybinding (display, keycode, mask); if (binding) { guint32 index_key; - GSList *l; - for (l = display->screens; l; l = l->next) - { - MetaScreen *screen = l->data; - meta_change_keygrab (display, screen->xroot, FALSE, - binding->keysym, - binding->keycode, - binding->mask); - } + meta_change_keygrab (display, display->screen->xroot, FALSE, + binding->keysym, + binding->keycode, + binding->mask); index_key = key_binding_key (binding->keycode, binding->mask); g_hash_table_remove (display->key_bindings_index, GINT_TO_POINTER (index_key)); @@ -1436,7 +1415,7 @@ grab_keyboard (MetaDisplay *display, /* Grab the keyboard, so we get key releases and all key * presses */ - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); /* Strictly, we only need to set grab_mode on the keyboard device * while the pointer should always be XIGrabModeAsync. Unfortunately @@ -1541,6 +1520,10 @@ meta_window_grab_all_keys (MetaWindow *window, Window grabwindow; gboolean retval; + /* We don't need to grab Wayland clients */ + if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + return TRUE; + if (window->all_keys_grabbed) return FALSE; @@ -1613,38 +1596,37 @@ meta_display_unfreeze_keyboard (MetaDisplay *display, guint32 timestamp) } static gboolean -is_modifier (MetaDisplay *display, - unsigned int keycode) +is_modifier (xkb_keysym_t keysym) { - int i; - int map_size; - gboolean retval = FALSE; - - g_assert (display->modmap); - - map_size = 8 * display->modmap->max_keypermod; - i = 0; - while (i < map_size) + switch (keysym) { - if (keycode == display->modmap->modifiermap[i]) - { - retval = TRUE; - break; - } - ++i; + case XKB_KEY_Shift_L: + case XKB_KEY_Shift_R: + case XKB_KEY_Control_L: + case XKB_KEY_Control_R: + case XKB_KEY_Caps_Lock: + case XKB_KEY_Shift_Lock: + case XKB_KEY_Meta_L: + case XKB_KEY_Meta_R: + case XKB_KEY_Alt_L: + case XKB_KEY_Alt_R: + case XKB_KEY_Super_L: + case XKB_KEY_Super_R: + case XKB_KEY_Hyper_L: + case XKB_KEY_Hyper_R: + return TRUE; + default: + return FALSE; } - - return retval; } static void -invoke_handler (MetaDisplay *display, - MetaScreen *screen, - MetaKeyHandler *handler, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding) - +invoke_handler (MetaDisplay *display, + MetaScreen *screen, + MetaKeyHandler *handler, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding) { if (handler->func) (* handler->func) (display, screen, @@ -1666,33 +1648,26 @@ static gboolean process_event (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, - XIDeviceEvent *event, - gboolean on_window) + ClutterKeyEvent *event) { MetaKeyBinding *binding; /* we used to have release-based bindings but no longer. */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return FALSE; binding = display_get_keybinding (display, - event->detail, - event->mods.effective); + event->hardware_keycode, + event->modifier_state); if (!binding || - (!on_window && binding->flags & META_KEY_BINDING_PER_WINDOW) || - meta_compositor_filter_keybinding (display->compositor, screen, binding)) + (!window && binding->flags & META_KEY_BINDING_PER_WINDOW)) goto not_found; - /* - * window must be non-NULL for on_window to be true, - * and so also window must be non-NULL if we get here and - * this is a META_KEY_BINDING_PER_WINDOW binding. - */ - - meta_topic (META_DEBUG_KEYBINDINGS, - "Binding keycode 0x%x mask 0x%x matches event 0x%x state 0x%x\n", - binding->keycode, binding->mask, - event->detail, event->mods.effective); + /* If the compositor filtered out the keybindings, that + * means they don't want the binding to trigger, so we do + * the same thing as if the binding didn't exist. */ + if (meta_compositor_filter_keybinding (display->compositor, binding)) + goto not_found; if (binding->handler == NULL) meta_bug ("Binding %s has no handler\n", binding->name); @@ -1720,12 +1695,12 @@ process_event (MetaDisplay *display, static gboolean process_overlay_key (MetaDisplay *display, MetaScreen *screen, - XIDeviceEvent *event, - KeySym keysym) + ClutterKeyEvent *event, + MetaWindow *window) { if (display->overlay_key_only_pressed) { - if (event->detail != (int)display->overlay_key_combo.keycode) + if (event->hardware_keycode != (int)display->overlay_key_combo.keycode) { display->overlay_key_only_pressed = FALSE; @@ -1741,38 +1716,42 @@ process_overlay_key (MetaDisplay *display, * the event. Other clients with global grabs will be out of * luck. */ - if (process_event (display, screen, NULL, event, FALSE)) + if (process_event (display, screen, window, event)) { /* As normally, after we've handled a global key * binding, we unfreeze the keyboard but keep the grab * (this is important for something like cycling * windows */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); } else { /* Replay the event so it gets delivered to our * per-window key bindings or to the application */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIReplayDevice, event->time); } } - else if (event->evtype == XI_KeyRelease) + else if (event->type == CLUTTER_KEY_RELEASE) { MetaKeyBinding *binding; display->overlay_key_only_pressed = FALSE; + /* We want to unfreeze events, but keep the grab so that if the user * starts typing into the overlay we get all the keys */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); binding = display_get_keybinding (display, display->overlay_key_combo.keycode, - display->grab_mask); + 0); if (binding && - meta_compositor_filter_keybinding (display->compositor, screen, binding)) + meta_compositor_filter_keybinding (display->compositor, binding)) return TRUE; meta_display_overlay_key_activate (display); } @@ -1790,19 +1769,21 @@ process_overlay_key (MetaDisplay *display, * * https://bugzilla.gnome.org/show_bug.cgi?id=666101 */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); } return TRUE; } - else if (event->evtype == XI_KeyPress && - event->detail == (int)display->overlay_key_combo.keycode) + else if (event->type == CLUTTER_KEY_PRESS && + event->hardware_keycode == (int)display->overlay_key_combo.keycode) { display->overlay_key_only_pressed = TRUE; /* We keep the keyboard frozen - this allows us to use ReplayKeyboard * on the next event if it's not the release of the overlay key */ - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XISyncDevice, event->time); return TRUE; @@ -1814,29 +1795,27 @@ process_overlay_key (MetaDisplay *display, static gboolean process_iso_next_group (MetaDisplay *display, MetaScreen *screen, - XIDeviceEvent *event, - KeySym keysym) + ClutterKeyEvent *event) { gboolean activate; - unsigned int mods; int i; - if (event->evtype != XI_KeyPress) + if (event->type == CLUTTER_KEY_RELEASE) return FALSE; activate = FALSE; - mods = (event->mods.effective & 0xff & ~(display->ignored_modifier_mask)); for (i = 0; i < display->n_iso_next_group_combos; ++i) { - if (event->detail == (int)display->iso_next_group_combos[i].keycode && - mods == display->iso_next_group_combos[i].modifiers) + if (event->hardware_keycode == display->iso_next_group_combos[i].keycode && + event->modifier_state == (unsigned int)display->iso_next_group_combos[i].modifiers) { /* If the signal handler returns TRUE the keyboard will remain frozen. It's the signal handler's responsibility to unfreeze it. */ if (!meta_display_modifiers_accelerator_activate (display)) - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); activate = TRUE; break; @@ -1861,57 +1840,33 @@ process_iso_next_group (MetaDisplay *display, * (and help us solve the other fixmes). */ gboolean -meta_display_process_key_event (MetaDisplay *display, - MetaWindow *window, - XIDeviceEvent *event) +meta_display_process_key_event (MetaDisplay *display, + MetaWindow *window, + ClutterKeyEvent *event) { - KeySym keysym; gboolean keep_grab; gboolean all_keys_grabbed; gboolean handled; - const char *str; MetaScreen *screen; - /* if key event was on root window, we have a shortcut */ - screen = meta_display_screen_for_root (display, event->event); - - /* else round-trip to server */ - if (screen == NULL) - screen = meta_display_screen_for_xwindow (display, event->event); - - if (screen == NULL) - return FALSE; /* event window is destroyed */ - - /* ignore key events on popup menus and such. */ - if (meta_ui_window_is_widget (screen->ui, event->event)) - return FALSE; - /* window may be NULL */ - keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0); - - str = XKeysymToString (keysym); - - /* was topic */ - meta_topic (META_DEBUG_KEYBINDINGS, - "Processing key %s event, keysym: %s state: 0x%x window: %s\n", - event->evtype == XI_KeyPress ? "press" : "release", - str ? str : "none", event->mods.effective, - window ? window->desc : "(no window)"); + screen = display->screen; all_keys_grabbed = window ? window->all_keys_grabbed : screen->all_keys_grabbed; if (!all_keys_grabbed) { - handled = process_overlay_key (display, screen, event, keysym); + handled = process_overlay_key (display, screen, event, window); if (handled) return TRUE; - handled = process_iso_next_group (display, screen, event, keysym); + handled = process_iso_next_group (display, screen, event); if (handled) return TRUE; } - XIAllowEvents (display->xdisplay, event->deviceid, + XIAllowEvents (display->xdisplay, + clutter_input_device_get_device_id (event->device), XIAsyncDevice, event->time); keep_grab = TRUE; @@ -1923,8 +1878,7 @@ meta_display_process_key_event (MetaDisplay *display, * we're in some special keyboard mode such as window move * mode. */ - if (window ? (window == display->grab_window) : - (screen == display->grab_screen)) + if ((window && window == display->grab_window) || !window) { switch (display->grab_op) { @@ -1940,16 +1894,14 @@ meta_display_process_key_event (MetaDisplay *display, meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for mouse-only move/resize\n"); g_assert (window != NULL); - keep_grab = process_mouse_move_resize_grab (display, screen, - window, event, keysym); + keep_grab = process_mouse_move_resize_grab (display, screen, window, event); break; case META_GRAB_OP_KEYBOARD_MOVING: meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for keyboard move\n"); g_assert (window != NULL); - keep_grab = process_keyboard_move_grab (display, screen, - window, event, keysym); + keep_grab = process_keyboard_move_grab (display, screen, window, event); break; case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: @@ -1964,8 +1916,7 @@ meta_display_process_key_event (MetaDisplay *display, meta_topic (META_DEBUG_KEYBINDINGS, "Processing event for keyboard resize\n"); g_assert (window != NULL); - keep_grab = process_keyboard_resize_grab (display, screen, - window, event, keysym); + keep_grab = process_keyboard_resize_grab (display, screen, window, event); break; default: @@ -1973,33 +1924,26 @@ meta_display_process_key_event (MetaDisplay *display, } } if (!keep_grab) - { - meta_topic (META_DEBUG_KEYBINDINGS, - "Ending grab op %u on key event sym %s\n", - display->grab_op, XKeysymToString (keysym)); - meta_display_end_grab_op (display, event->time); - } + meta_display_end_grab_op (display, event->time); return TRUE; } /* Do the normal keybindings */ - return process_event (display, screen, window, event, - !all_keys_grabbed && window); + return process_event (display, screen, window, event); } static gboolean -process_mouse_move_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_mouse_move_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { /* don't care about releases, but eat them, don't end grab */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return TRUE; - if (keysym == XK_Escape) + if (event->keyval == CLUTTER_KEY_Escape) { /* Hide the tiling preview if necessary */ if (window->tile_mode != META_TILE_NONE) @@ -2034,11 +1978,10 @@ process_mouse_move_resize_grab (MetaDisplay *display, } static gboolean -process_keyboard_move_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_keyboard_move_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { gboolean handled; int x, y; @@ -2048,28 +1991,28 @@ process_keyboard_move_grab (MetaDisplay *display, handled = FALSE; /* don't care about releases, but eat them, don't end grab */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return TRUE; /* don't end grab on modifier key presses */ - if (is_modifier (display, event->detail)) + if (is_modifier (event->keyval)) return TRUE; meta_window_get_position (window, &x, &y); - smart_snap = (event->mods.effective & ShiftMask) != 0; + smart_snap = (event->modifier_state & CLUTTER_SHIFT_MASK) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 if (smart_snap) incr = 1; - else if (event->mods.effective & ControlMask) + else if (event->modifier_state & CLUTTER_CONTROL_MASK) incr = SMALL_INCREMENT; else incr = NORMAL_INCREMENT; - if (keysym == XK_Escape) + if (event->keyval == CLUTTER_KEY_Escape) { /* End move and restore to original state. If the window was a * maximized window that had been "shaken loose" we need to @@ -2092,37 +2035,37 @@ process_keyboard_move_grab (MetaDisplay *display, * Shift + arrow to snap is sort of a hidden feature. This way * people using just arrows shouldn't get too frustrated. */ - switch (keysym) + switch (event->keyval) { - case XK_KP_Home: - case XK_KP_Prior: - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_KP_Home: + case CLUTTER_KEY_KP_Prior: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: y -= incr; handled = TRUE; break; - case XK_KP_End: - case XK_KP_Next: - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_KP_End: + case CLUTTER_KEY_KP_Next: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: y += incr; handled = TRUE; break; } - switch (keysym) + switch (event->keyval) { - case XK_KP_Home: - case XK_KP_End: - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_KP_Home: + case CLUTTER_KEY_KP_End: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: x -= incr; handled = TRUE; break; - case XK_KP_Prior: - case XK_KP_Next: - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_KP_Prior: + case CLUTTER_KEY_KP_Next: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: x += incr; handled = TRUE; break; @@ -2154,11 +2097,10 @@ process_keyboard_move_grab (MetaDisplay *display, } static gboolean -process_keyboard_resize_grab_op_change (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_keyboard_resize_grab_op_change (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { gboolean handled; @@ -2166,25 +2108,25 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, switch (display->grab_op) { case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN: - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; handled = TRUE; break; - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; handled = TRUE; break; @@ -2192,15 +2134,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_S: - switch (keysym) + switch (event->keyval) { - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; handled = TRUE; break; @@ -2208,15 +2150,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_N: - switch (keysym) + switch (event->keyval) { - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W; handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E; handled = TRUE; break; @@ -2224,15 +2166,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_W: - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; handled = TRUE; break; @@ -2240,15 +2182,15 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, break; case META_GRAB_OP_KEYBOARD_RESIZING_E: - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N; handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S; handled = TRUE; break; @@ -2276,11 +2218,10 @@ process_keyboard_resize_grab_op_change (MetaDisplay *display, } static gboolean -process_keyboard_resize_grab (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - KeySym keysym) +process_keyboard_resize_grab (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event) { gboolean handled; int height_inc; @@ -2292,14 +2233,14 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = FALSE; /* don't care about releases, but eat them, don't end grab */ - if (event->evtype == XI_KeyRelease) + if (event->type == CLUTTER_KEY_RELEASE) return TRUE; /* don't end grab on modifier key presses */ - if (is_modifier (display, event->detail)) + if (is_modifier (event->keyval)) return TRUE; - if (keysym == XK_Escape) + if (event->keyval == CLUTTER_KEY_Escape) { /* End resize and restore to original state. */ meta_window_move_resize (display->grab_window, @@ -2312,8 +2253,7 @@ process_keyboard_resize_grab (MetaDisplay *display, return FALSE; } - if (process_keyboard_resize_grab_op_change (display, screen, window, - event, keysym)) + if (process_keyboard_resize_grab_op_change (display, screen, window, event)) return TRUE; width = window->rect.width; @@ -2321,7 +2261,7 @@ process_keyboard_resize_grab (MetaDisplay *display, gravity = meta_resize_gravity_from_grab_op (display->grab_op); - smart_snap = (event->mods.effective & ShiftMask) != 0; + smart_snap = (event->modifier_state & CLUTTER_SHIFT_MASK) != 0; #define SMALL_INCREMENT 1 #define NORMAL_INCREMENT 10 @@ -2331,7 +2271,7 @@ process_keyboard_resize_grab (MetaDisplay *display, height_inc = 1; width_inc = 1; } - else if (event->mods.effective & ControlMask) + else if (event->modifier_state & CLUTTER_CONTROL_MASK) { width_inc = SMALL_INCREMENT; height_inc = SMALL_INCREMENT; @@ -2350,10 +2290,10 @@ process_keyboard_resize_grab (MetaDisplay *display, if (window->size_hints.height_inc > 1) height_inc = window->size_hints.height_inc; - switch (keysym) + switch (event->keyval) { - case XK_Up: - case XK_KP_Up: + case CLUTTER_KEY_Up: + case CLUTTER_KEY_KP_Up: switch (gravity) { case NorthGravity: @@ -2380,8 +2320,8 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = TRUE; break; - case XK_Down: - case XK_KP_Down: + case CLUTTER_KEY_Down: + case CLUTTER_KEY_KP_Down: switch (gravity) { case NorthGravity: @@ -2408,8 +2348,8 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = TRUE; break; - case XK_Left: - case XK_KP_Left: + case CLUTTER_KEY_Left: + case CLUTTER_KEY_KP_Left: switch (gravity) { case EastGravity: @@ -2436,8 +2376,8 @@ process_keyboard_resize_grab (MetaDisplay *display, handled = TRUE; break; - case XK_Right: - case XK_KP_Right: + case CLUTTER_KEY_Right: + case CLUTTER_KEY_KP_Right: switch (gravity) { case EastGravity: @@ -2512,12 +2452,12 @@ process_keyboard_resize_grab (MetaDisplay *display, } static void -handle_switch_to_workspace (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_switch_to_workspace (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint which = binding->handler->data; MetaWorkspace *workspace; @@ -2536,12 +2476,12 @@ handle_switch_to_workspace (MetaDisplay *display, static void -handle_maximize_vertically (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_maximize_vertically (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_resize_func) { @@ -2553,12 +2493,12 @@ handle_maximize_vertically (MetaDisplay *display, } static void -handle_maximize_horizontally (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_maximize_horizontally (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_resize_func) { @@ -2570,12 +2510,12 @@ handle_maximize_horizontally (MetaDisplay *display, } static void -handle_always_on_top (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_always_on_top (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->wm_state_above == FALSE) meta_window_make_above (window); @@ -2631,100 +2571,100 @@ handle_move_to_corner_backend (MetaDisplay *display, } static void -handle_move_to_corner_nw (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_nw (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, FALSE, dummy); } static void -handle_move_to_corner_ne (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_ne (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, FALSE, dummy); } static void -handle_move_to_corner_sw (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_sw (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, TRUE, dummy); } static void -handle_move_to_corner_se (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_corner_se (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, TRUE, dummy); } static void -handle_move_to_side_n (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_n (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, FALSE, dummy); } static void -handle_move_to_side_s (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_s (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, TRUE, dummy); } static void -handle_move_to_side_e (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_e (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, TRUE, FALSE, dummy); } static void -handle_move_to_side_w (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_side_w (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, FALSE, FALSE, dummy); } static void -handle_move_to_center (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_center (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { MetaRectangle work_area; MetaRectangle frame_rect; @@ -2747,12 +2687,12 @@ handle_move_to_center (MetaDisplay *display, } static void -handle_show_desktop (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_show_desktop (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (screen->active_workspace->showing_desktop) { @@ -2766,12 +2706,12 @@ handle_show_desktop (MetaDisplay *display, } static void -handle_panel (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_panel (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { MetaKeyBindingAction action = binding->handler->data; Atom action_atom; @@ -2799,7 +2739,7 @@ handle_panel (MetaDisplay *display, ev.data.l[1] = event->time; meta_topic (META_DEBUG_KEYBINDINGS, - "Sending panel message with timestamp %lu, and turning mouse_mode " + "Sending panel message with timestamp %u, and turning mouse_mode " "off due to keybinding press\n", event->time); display->mouse_mode = FALSE; @@ -2818,12 +2758,12 @@ handle_panel (MetaDisplay *display, } static void -handle_activate_window_menu (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_activate_window_menu (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (display->focus_window) { @@ -2843,12 +2783,12 @@ handle_activate_window_menu (MetaDisplay *display, } static void -do_choose_window (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gboolean backward) +do_choose_window (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gboolean backward) { MetaTabList type = binding->handler->data; MetaWindow *initial_selection; @@ -2857,12 +2797,11 @@ do_choose_window (MetaDisplay *display, "Tab list = %u\n", type); /* reverse direction if shift is down */ - if (event->mods.effective & ShiftMask) + if (event->modifier_state & CLUTTER_SHIFT_MASK) backward = !backward; initial_selection = meta_display_get_tab_next (display, type, - screen, screen->active_workspace, NULL, backward); @@ -2871,36 +2810,36 @@ do_choose_window (MetaDisplay *display, } static void -handle_switch (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_switch (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0; do_choose_window (display, screen, event_window, event, binding, backwards); } static void -handle_cycle (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *event_window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_cycle (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *event_window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0; do_choose_window (display, screen, event_window, event, binding, backwards); } static void -handle_toggle_fullscreen (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_fullscreen (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->fullscreen) meta_window_unmake_fullscreen (window); @@ -2909,12 +2848,12 @@ handle_toggle_fullscreen (MetaDisplay *display, } static void -handle_toggle_above (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_above (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->wm_state_above) meta_window_unmake_above (window); @@ -2923,12 +2862,12 @@ handle_toggle_above (MetaDisplay *display, } static void -handle_toggle_tiled (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_tiled (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { MetaTileMode mode = binding->handler->data; @@ -2961,12 +2900,12 @@ handle_toggle_tiled (MetaDisplay *display, } static void -handle_toggle_maximized (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_maximized (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (META_WINDOW_MAXIMIZED (window)) meta_window_unmaximize (window, META_MAXIMIZE_BOTH); @@ -2975,36 +2914,36 @@ handle_toggle_maximized (MetaDisplay *display, } static void -handle_maximize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_maximize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_maximize_func) meta_window_maximize (window, META_MAXIMIZE_BOTH); } static void -handle_unmaximize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_unmaximize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->maximized_vertically || window->maximized_horizontally) meta_window_unmaximize (window, META_MAXIMIZE_BOTH); } static void -handle_toggle_shaded (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_shaded (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->shaded) meta_window_unshade (window, event->time); @@ -3013,36 +2952,36 @@ handle_toggle_shaded (MetaDisplay *display, } static void -handle_close (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_close (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_close_func) meta_window_delete (window, event->time); } static void -handle_minimize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_minimize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_minimize_func) meta_window_minimize (window); } static void -handle_begin_move (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_begin_move (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_move_func) { @@ -3054,12 +2993,12 @@ handle_begin_move (MetaDisplay *display, } static void -handle_begin_resize (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_begin_resize (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->has_resize_func) { @@ -3071,12 +3010,12 @@ handle_begin_resize (MetaDisplay *display, } static void -handle_toggle_on_all_workspaces (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_toggle_on_all_workspaces (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { if (window->on_all_workspaces_requested) meta_window_unstick (window); @@ -3085,12 +3024,12 @@ handle_toggle_on_all_workspaces (MetaDisplay *display, } static void -handle_move_to_workspace (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_move_to_workspace (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { gint which = binding->handler->data; gboolean flip = (which < 0); @@ -3143,7 +3082,7 @@ static void handle_move_to_monitor (MetaDisplay *display, MetaScreen *screen, MetaWindow *window, - XIDeviceEvent *event, + ClutterKeyEvent *event, MetaKeyBinding *binding, gpointer dummy) { @@ -3160,12 +3099,12 @@ handle_move_to_monitor (MetaDisplay *display, } static void -handle_raise_or_lower (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_raise_or_lower (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { /* Get window at pointer */ @@ -3207,38 +3146,56 @@ handle_raise_or_lower (MetaDisplay *display, } static void -handle_raise (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_raise (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { meta_window_raise (window); } static void -handle_lower (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_lower (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { meta_window_lower (window); } static void -handle_set_spew_mark (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer dummy) +handle_set_spew_mark (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) { meta_verbose ("-- MARK MARK MARK MARK --\n"); } +static void +handle_switch_vt (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer dummy) +{ + gint vt = binding->handler->data; + GError *error = NULL; + + if (!meta_activate_vt (vt, &error)) + { + g_warning ("Failed to switch VT: %s", error->message); + g_error_free (error); + } +} + /** * meta_keybindings_set_custom_handler: * @name: The name of the keybinding to set @@ -3280,6 +3237,7 @@ init_builtin_key_bindings (MetaDisplay *display) META_KEY_BINDING_IS_REVERSED) GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS); GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS); + GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS); add_builtin_keybinding (display, "switch-to-workspace-1", @@ -3521,6 +3479,58 @@ init_builtin_key_bindings (MetaDisplay *display) META_KEYBINDING_ACTION_SET_SPEW_MARK, handle_set_spew_mark, 0); + if (meta_is_wayland_compositor ()) + { + add_builtin_keybinding (display, + "switch-to-session-1", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 1); + + add_builtin_keybinding (display, + "switch-to-session-2", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 2); + + add_builtin_keybinding (display, + "switch-to-session-3", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 3); + + add_builtin_keybinding (display, + "switch-to-session-4", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 4); + + add_builtin_keybinding (display, + "switch-to-session-5", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 5); + + add_builtin_keybinding (display, + "switch-to-session-6", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 6); + + add_builtin_keybinding (display, + "switch-to-session-7", + mutter_wayland_keybindings, + META_KEY_BINDING_NONE, + META_KEYBINDING_ACTION_NONE, + handle_switch_vt, 7); + } + #undef REVERSES_AND_REVERSED /************************ PER WINDOW BINDINGS ************************/ @@ -3874,6 +3884,7 @@ init_builtin_key_bindings (MetaDisplay *display) g_object_unref (common_keybindings); g_object_unref (mutter_keybindings); + g_object_unref (mutter_wayland_keybindings); } void @@ -3884,12 +3895,9 @@ meta_display_init_keys (MetaDisplay *display) /* Keybindings */ display->keymap = NULL; display->keysyms_per_keycode = 0; - display->modmap = NULL; display->min_keycode = 0; display->max_keycode = 0; display->ignored_modifier_mask = 0; - display->num_lock_mask = 0; - display->scroll_lock_mask = 0; display->hyper_mask = 0; display->super_mask = 0; display->meta_mask = 0; diff --git a/src/core/main.c b/src/core/main.c index 3f5f3c5a0..a3d000e0a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -50,12 +50,11 @@ #include "display-private.h" #include #include "ui.h" -#include "session.h" #include #include #include -#include +#include #include #include @@ -71,12 +70,16 @@ #include #include -#include #ifdef HAVE_INTROSPECTION #include #endif +#include "x11/session.h" + +#include "wayland/meta-wayland.h" +#include "backends/meta-backend.h" + /* * The exit code we'll return to our parent process when we eventually die. */ @@ -187,6 +190,8 @@ static gchar *opt_client_id; static gboolean opt_replace_wm; static gboolean opt_disable_sm; static gboolean opt_sync; +static gboolean opt_wayland; +static gboolean opt_display_server; static GOptionEntry meta_options[] = { { @@ -224,6 +229,17 @@ static GOptionEntry meta_options[] = { N_("Make X calls synchronous"), NULL }, + { + "wayland", 0, 0, G_OPTION_ARG_NONE, + &opt_wayland, + N_("Run as a wayland compositor"), + NULL + }, + { + "display-server", 0, 0, G_OPTION_ARG_NONE, + &opt_display_server, + N_("Run as a full display server, rather than nested") + }, {NULL} }; @@ -247,78 +263,9 @@ meta_get_option_context (void) ctx = g_option_context_new (NULL); g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE); - g_option_context_add_group (ctx, clutter_get_option_group_without_init ()); - g_option_context_add_group (ctx, cogl_get_option_group ()); - return ctx; } -/* Mutter is responsible for pulling events off the X queue, so Clutter - * doesn't need (and shouldn't) run its normal event source which polls - * the X fd, but we do have to deal with dispatching events that accumulate - * in the clutter queue. This happens, for example, when clutter generate - * enter/leave events on mouse motion - several events are queued in the - * clutter queue but only one dispatched. It could also happen because of - * explicit calls to clutter_event_put(). We add a very simple custom - * event loop source which is simply responsible for pulling events off - * of the queue and dispatching them before we block for new events. - */ - -static gboolean -event_prepare (GSource *source, - gint *timeout_) -{ - *timeout_ = -1; - - return clutter_events_pending (); -} - -static gboolean -event_check (GSource *source) -{ - return clutter_events_pending (); -} - -static gboolean -event_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - ClutterEvent *event = clutter_event_get (); - - if (event) - { - clutter_do_event (event); - clutter_event_free (event); - } - - return TRUE; -} - -static GSourceFuncs event_funcs = { - event_prepare, - event_check, - event_dispatch -}; - -static void -meta_clutter_init (void) -{ - clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); - clutter_x11_disable_event_retrieval (); - - if (CLUTTER_INIT_SUCCESS == clutter_init (NULL, NULL)) - { - GSource *source = g_source_new (&event_funcs, sizeof (GSource)); - g_source_attach (source, NULL); - g_source_unref (source); - } - else - { - meta_fatal ("Unable to initialize Clutter.\n"); - } -} - /** * meta_select_display: * @@ -328,16 +275,17 @@ meta_clutter_init (void) * also is %NULL, use the default - :0.0 */ static void -meta_select_display (gchar *display_name) +meta_select_display (char *display_arg) { - gchar *envVar = ""; + const char *display_name; + + if (display_arg) + display_name = (const char *) display_arg; + else + display_name = g_getenv ("MUTTER_DISPLAY"); + if (display_name) - envVar = g_strconcat ("DISPLAY=", display_name, NULL); - else if (g_getenv ("MUTTER_DISPLAY")) - envVar = g_strconcat ("DISPLAY=", - g_getenv ("MUTTER_DISPLAY"), NULL); - /* DO NOT FREE envVar, putenv() sucks */ - putenv (envVar); + g_setenv ("DISPLAY", display_name, TRUE); } static void @@ -348,28 +296,17 @@ meta_finalize (void) if (display) meta_display_close (display, CurrentTime); /* I doubt correct timestamps matter here */ -} -static int sigterm_pipe_fds[2] = { -1, -1 }; - -static void -sigterm_handler (int signum) -{ - if (sigterm_pipe_fds[1] >= 0) - { - int G_GNUC_UNUSED dummy; - - dummy = write (sigterm_pipe_fds[1], "", 1); - close (sigterm_pipe_fds[1]); - sigterm_pipe_fds[1] = -1; - } + if (meta_is_wayland_compositor ()) + meta_wayland_finalize (); } static gboolean -on_sigterm (void) +on_sigterm (gpointer user_data) { - meta_quit (META_EXIT_SUCCESS); - return FALSE; + meta_quit (EXIT_SUCCESS); + + return G_SOURCE_REMOVE; } /** @@ -383,9 +320,8 @@ meta_init (void) { struct sigaction act; sigset_t empty_mask; - GIOChannel *channel; ClutterSettings *clutter_settings; - + sigemptyset (&empty_mask); act.sa_handler = SIG_IGN; act.sa_mask = empty_mask; @@ -399,26 +335,18 @@ meta_init (void) g_strerror (errno)); #endif - if (pipe (sigterm_pipe_fds) != 0) - g_printerr ("Failed to create SIGTERM pipe: %s\n", - g_strerror (errno)); - - channel = g_io_channel_unix_new (sigterm_pipe_fds[0]); - g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); - g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL); - g_io_channel_set_close_on_unref (channel, TRUE); - g_io_channel_unref (channel); - - act.sa_handler = &sigterm_handler; - if (sigaction (SIGTERM, &act, NULL) < 0) - g_printerr ("Failed to register SIGTERM handler: %s\n", - g_strerror (errno)); + g_unix_signal_add (SIGTERM, on_sigterm, NULL); if (g_getenv ("MUTTER_VERBOSE")) meta_set_verbose (TRUE); if (g_getenv ("MUTTER_DEBUG")) meta_set_debugging (TRUE); + if (opt_display_server) + clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL); + + meta_set_is_wayland_compositor (opt_wayland); + if (g_get_home_dir ()) if (chdir (g_get_home_dir ()) < 0) meta_warning ("Could not change to home directory %s.\n", @@ -430,9 +358,16 @@ meta_init (void) g_irepository_prepend_search_path (MUTTER_PKGLIBDIR); #endif - meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); + if (meta_is_wayland_compositor ()) + { + /* NB: When running as a hybrid wayland compositor we run our own headless X + * server so the user can't control the X display to connect too. */ + meta_wayland_init (); + } + else + meta_select_display (opt_display_name); - meta_select_display (opt_display_name); + meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); if (opt_replace_wm) meta_set_replace_current_wm (TRUE); @@ -441,13 +376,20 @@ meta_init (void) meta_fatal ("Can't specify both SM save file and SM client id\n"); meta_main_loop = g_main_loop_new (NULL, FALSE); - + meta_ui_init (); - /* - * Clutter can only be initialized after the UI. - */ - meta_clutter_init (); + /* If we are running with wayland then we don't wait until we have + * an X connection before initializing clutter we instead initialize + * it earlier since we need to initialize the GL driver so the driver + * can register any needed wayland extensions. */ + if (!meta_is_wayland_compositor ()) + { + /* + * Clutter can only be initialized after the UI. + */ + meta_clutter_init (); + } /* * XXX: We cannot handle high dpi scaling yet, so fix the scale to 1 diff --git a/src/core/meta-accel-parse.c b/src/core/meta-accel-parse.c new file mode 100644 index 000000000..e9d30540b --- /dev/null +++ b/src/core/meta-accel-parse.c @@ -0,0 +1,355 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "meta-accel-parse.h" + +#include +#include +#include + +/* This is copied from GTK+ and modified to work with mutter's + * internal structures. Originating code comes from gtk/gtkaccelgroup.c + */ + +static inline gboolean +is_alt (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'a' || string[1] == 'A') && + (string[2] == 'l' || string[2] == 'L') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == '>')); +} + +static inline gboolean +is_ctl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'l' || string[3] == 'L') && + (string[4] == '>')); +} + +static inline gboolean +is_modx (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'd' || string[3] == 'D') && + (string[4] >= '1' && string[4] <= '5') && + (string[5] == '>')); +} + +static inline gboolean +is_ctrl (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 't' || string[2] == 'T') && + (string[3] == 'r' || string[3] == 'R') && + (string[4] == 'l' || string[4] == 'L') && + (string[5] == '>')); +} + +static inline gboolean +is_shft (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'f' || string[3] == 'F') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == '>')); +} + +static inline gboolean +is_shift (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'h' || string[2] == 'H') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'f' || string[4] == 'F') && + (string[5] == 't' || string[5] == 'T') && + (string[6] == '>')); +} + +static inline gboolean +is_control (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'c' || string[1] == 'C') && + (string[2] == 'o' || string[2] == 'O') && + (string[3] == 'n' || string[3] == 'N') && + (string[4] == 't' || string[4] == 'T') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == 'o' || string[6] == 'O') && + (string[7] == 'l' || string[7] == 'L') && + (string[8] == '>')); +} + +static inline gboolean +is_meta (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'm' || string[1] == 'M') && + (string[2] == 'e' || string[2] == 'E') && + (string[3] == 't' || string[3] == 'T') && + (string[4] == 'a' || string[4] == 'A') && + (string[5] == '>')); +} + +static inline gboolean +is_super (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 's' || string[1] == 'S') && + (string[2] == 'u' || string[2] == 'U') && + (string[3] == 'p' || string[3] == 'P') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +static inline gboolean +is_hyper (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'h' || string[1] == 'H') && + (string[2] == 'y' || string[2] == 'Y') && + (string[3] == 'p' || string[3] == 'P') && + (string[4] == 'e' || string[4] == 'E') && + (string[5] == 'r' || string[5] == 'R') && + (string[6] == '>')); +} + +static inline gboolean +is_primary (const gchar *string) +{ + return ((string[0] == '<') && + (string[1] == 'p' || string[1] == 'P') && + (string[2] == 'r' || string[2] == 'R') && + (string[3] == 'i' || string[3] == 'I') && + (string[4] == 'm' || string[4] == 'M') && + (string[5] == 'a' || string[5] == 'A') && + (string[6] == 'r' || string[6] == 'R') && + (string[7] == 'y' || string[7] == 'Y') && + (string[8] == '>')); +} + +static inline gboolean +is_keycode (const gchar *string) +{ + return (string[0] == '0' && + string[1] == 'x' && + g_ascii_isxdigit (string[2]) && + g_ascii_isxdigit (string[3])); +} + +static gboolean +accelerator_parse (const gchar *accelerator, + guint *accelerator_key, + guint *accelerator_keycode, + MetaVirtualModifier *accelerator_mods) +{ + gboolean error = FALSE; + guint keyval, keycode; + MetaVirtualModifier mods; + gint len; + + if (accelerator_key) + *accelerator_key = 0; + if (accelerator_keycode) + *accelerator_keycode = 0; + if (accelerator_mods) + *accelerator_mods = 0; + + if (accelerator == NULL) + { + error = TRUE; + goto out; + } + + keyval = 0; + mods = 0; + len = strlen (accelerator); + while (len) + { + if (*accelerator == '<') + { + if (len >= 9 && is_primary (accelerator)) + { + /* Primary is treated the same as Control */ + accelerator += 9; + len -= 9; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 9 && is_control (accelerator)) + { + accelerator += 9; + len -= 9; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 7 && is_shift (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= META_VIRTUAL_SHIFT_MASK; + } + else if (len >= 6 && is_shft (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= META_VIRTUAL_SHIFT_MASK; + } + else if (len >= 6 && is_ctrl (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 6 && is_modx (accelerator)) + { + static const guint mod_vals[] = { + META_VIRTUAL_ALT_MASK, + META_VIRTUAL_MOD2_MASK, + META_VIRTUAL_MOD3_MASK, + META_VIRTUAL_MOD4_MASK, + META_VIRTUAL_MOD5_MASK, + }; + + len -= 6; + accelerator += 4; + mods |= mod_vals[*accelerator - '1']; + accelerator += 2; + } + else if (len >= 5 && is_ctl (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= META_VIRTUAL_CONTROL_MASK; + } + else if (len >= 5 && is_alt (accelerator)) + { + accelerator += 5; + len -= 5; + mods |= META_VIRTUAL_ALT_MASK; + } + else if (len >= 6 && is_meta (accelerator)) + { + accelerator += 6; + len -= 6; + mods |= META_VIRTUAL_META_MASK; + } + else if (len >= 7 && is_hyper (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= META_VIRTUAL_HYPER_MASK; + } + else if (len >= 7 && is_super (accelerator)) + { + accelerator += 7; + len -= 7; + mods |= META_VIRTUAL_SUPER_MASK; + } + else + { + gchar last_ch; + + last_ch = *accelerator; + while (last_ch && last_ch != '>') + { + last_ch = *accelerator; + accelerator += 1; + len -= 1; + } + } + } + else + { + if (len >= 4 && is_keycode (accelerator)) + { + keycode = strtoul (accelerator, NULL, 16); + goto out; + } + else if (strcmp (accelerator, "Above_Tab") == 0) + { + keyval = META_KEY_ABOVE_TAB; + goto out; + } + else + { + keyval = xkb_keysym_from_name (accelerator, XKB_KEYSYM_CASE_INSENSITIVE); + if (keyval == XKB_KEY_NoSymbol) + { + error = TRUE; + goto out; + } + } + + accelerator += len; + len -= len; + } + } + +out: + if (error) + return FALSE; + + if (accelerator_key) + *accelerator_key = keyval; + if (accelerator_keycode) + *accelerator_keycode = keycode; + if (accelerator_mods) + *accelerator_mods = mods; + + return TRUE; +} + +gboolean +meta_parse_accelerator (const char *accel, + unsigned int *keysym, + unsigned int *keycode, + MetaVirtualModifier *mask) +{ + if (!accel[0] || strcmp (accel, "disabled") == 0) + return TRUE; + + return accelerator_parse (accel, keysym, keycode, mask); +} + +gboolean +meta_parse_modifier (const char *accel, + MetaVirtualModifier *mask) +{ + if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0) + return TRUE; + + return accelerator_parse (accel, NULL, NULL, mask); +} diff --git a/src/core/meta-accel-parse.h b/src/core/meta-accel-parse.h new file mode 100644 index 000000000..1d58375e6 --- /dev/null +++ b/src/core/meta-accel-parse.h @@ -0,0 +1,43 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef META_ACCEL_PARSE_H +#define META_ACCEL_PARSE_H + +#include +#include + +/* Not a real key symbol but means "key above the tab key"; this is + * used as the default keybinding for cycle_group. + * 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are + * randomly chosen */ +#define META_KEY_ABOVE_TAB 0x2f7259c9 + +gboolean meta_parse_accelerator (const char *accel, + unsigned int *keysym, + unsigned int *keycode, + MetaVirtualModifier *mask); +gboolean meta_parse_modifier (const char *accel, + MetaVirtualModifier *mask); + +#endif /* META_ACCEL_PARSE_H */ diff --git a/src/core/meta-cursor-tracker.c b/src/core/meta-cursor-tracker.c deleted file mode 100644 index bf6bd6966..000000000 --- a/src/core/meta-cursor-tracker.c +++ /dev/null @@ -1,412 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright 2013 Red Hat, Inc. - * - * 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, see . - * - * Author: Giovanni Campagna - */ - -/** - * SECTION:cursor-tracker - * @title: MetaCursorTracker - * @short_description: Mutter cursor tracking helper - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -#include "meta-cursor-tracker-private.h" -#include "screen-private.h" - -#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7 -#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4 - -struct _MetaCursorTracker { - GObject parent_instance; - - MetaScreen *screen; - - gboolean is_showing; - - CoglTexture2D *sprite; - int hot_x, hot_y; -}; - -struct _MetaCursorTrackerClass { - GObjectClass parent_class; -}; - -G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); - -enum { - CURSOR_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -static void -translate_meta_cursor (MetaCursor cursor, - guint *glyph_out, - const char **name_out) -{ - guint glyph = XC_num_glyphs; - const char *name = NULL; - - switch (cursor) - { - case META_CURSOR_DEFAULT: - glyph = XC_left_ptr; - break; - case META_CURSOR_NORTH_RESIZE: - glyph = XC_top_side; - break; - case META_CURSOR_SOUTH_RESIZE: - glyph = XC_bottom_side; - break; - case META_CURSOR_WEST_RESIZE: - glyph = XC_left_side; - break; - case META_CURSOR_EAST_RESIZE: - glyph = XC_right_side; - break; - case META_CURSOR_SE_RESIZE: - glyph = XC_bottom_right_corner; - break; - case META_CURSOR_SW_RESIZE: - glyph = XC_bottom_left_corner; - break; - case META_CURSOR_NE_RESIZE: - glyph = XC_top_right_corner; - break; - case META_CURSOR_NW_RESIZE: - glyph = XC_top_left_corner; - break; - case META_CURSOR_MOVE_OR_RESIZE_WINDOW: - glyph = XC_fleur; - break; - case META_CURSOR_BUSY: - glyph = XC_watch; - break; - case META_CURSOR_DND_IN_DRAG: - name = "dnd-none"; - break; - case META_CURSOR_DND_MOVE: - name = "dnd-move"; - break; - case META_CURSOR_DND_COPY: - name = "dnd-copy"; - break; - case META_CURSOR_DND_UNSUPPORTED_TARGET: - name = "dnd-none"; - break; - case META_CURSOR_POINTING_HAND: - glyph = XC_hand2; - break; - case META_CURSOR_CROSSHAIR: - glyph = XC_crosshair; - break; - case META_CURSOR_IBEAM: - glyph = XC_xterm; - break; - - default: - g_assert_not_reached (); - glyph = 0; /* silence compiler */ - break; - } - - *glyph_out = glyph; - *name_out = name; -} - -static Cursor -load_cursor_on_server (MetaDisplay *display, - MetaCursor cursor) -{ - Cursor xcursor; - guint glyph; - const char *name; - - translate_meta_cursor (cursor, &glyph, &name); - - if (name != NULL) - xcursor = XcursorLibraryLoadCursor (display->xdisplay, name); - else - xcursor = XCreateFontCursor (display->xdisplay, glyph); - - return xcursor; -} - -Cursor -meta_display_create_x_cursor (MetaDisplay *display, - MetaCursor cursor) -{ - return load_cursor_on_server (display, cursor); -} - -static void -meta_cursor_tracker_init (MetaCursorTracker *self) -{ - /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of - * detecting if the system mouse cursor is showing or not. - * - * On wayland we start with the cursor showing - */ - self->is_showing = TRUE; -} - -static void -meta_cursor_tracker_finalize (GObject *object) -{ - MetaCursorTracker *self = META_CURSOR_TRACKER (object); - - if (self->sprite) - cogl_object_unref (self->sprite); - - G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object); -} - -static void -meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = meta_cursor_tracker_finalize; - - signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); -} - -static MetaCursorTracker * -make_x11_cursor_tracker (MetaScreen *screen) -{ - MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL); - self->screen = screen; - - XFixesSelectCursorInput (screen->display->xdisplay, - screen->xroot, - XFixesDisplayCursorNotifyMask); - - return self; -} - -/** - * meta_cursor_tracker_get_for_screen: - * @screen: the #MetaScreen - * - * Retrieves the cursor tracker object for @screen. - * - * Returns: (transfer none): - */ -MetaCursorTracker * -meta_cursor_tracker_get_for_screen (MetaScreen *screen) -{ - MetaCursorTracker *self; - - if (screen->cursor_tracker) - return screen->cursor_tracker; - - self = make_x11_cursor_tracker (screen); - - screen->cursor_tracker = self; - return self; -} - -gboolean -meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker, - XEvent *xevent) -{ - XFixesCursorNotifyEvent *notify_event; - - if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify) - return FALSE; - - notify_event = (XFixesCursorNotifyEvent *)xevent; - if (notify_event->subtype != XFixesDisplayCursorNotify) - return FALSE; - - g_clear_pointer (&tracker->sprite, cogl_object_unref); - g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); - - return TRUE; -} - -static void -ensure_xfixes_cursor (MetaCursorTracker *tracker) -{ - XFixesCursorImage *cursor_image; - CoglTexture2D *sprite; - guint8 *cursor_data; - gboolean free_cursor_data; - CoglContext *ctx; - - if (tracker->sprite) - return; - - cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay); - if (!cursor_image) - return; - - /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit - * quantities as arrays of long; we need to convert on 64 bit */ - if (sizeof(long) == 4) - { - cursor_data = (guint8 *)cursor_image->pixels; - free_cursor_data = FALSE; - } - else - { - int i, j; - guint32 *cursor_words; - gulong *p; - guint32 *q; - - cursor_words = g_new (guint32, cursor_image->width * cursor_image->height); - cursor_data = (guint8 *)cursor_words; - - p = cursor_image->pixels; - q = cursor_words; - for (j = 0; j < cursor_image->height; j++) - for (i = 0; i < cursor_image->width; i++) - *(q++) = *(p++); - - free_cursor_data = TRUE; - } - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - sprite = cogl_texture_2d_new_from_data (ctx, - cursor_image->width, - cursor_image->height, - CLUTTER_CAIRO_FORMAT_ARGB32, - cursor_image->width * 4, /* stride */ - cursor_data, - NULL); - - if (free_cursor_data) - g_free (cursor_data); - - if (sprite != NULL) - { - tracker->sprite = sprite; - tracker->hot_x = cursor_image->xhot; - tracker->hot_y = cursor_image->yhot; - } - XFree (cursor_image); -} - -/** - * meta_cursor_tracker_get_sprite: - * - * Returns: (transfer none): - */ -CoglTexture * -meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker) -{ - g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL); - - ensure_xfixes_cursor (tracker); - - return COGL_TEXTURE (tracker->sprite); -} - -/** - * meta_cursor_tracker_get_hot: - * @tracker: - * @x: (out): - * @y: (out): - * - */ -void -meta_cursor_tracker_get_hot (MetaCursorTracker *tracker, - int *x, - int *y) -{ - g_return_if_fail (META_IS_CURSOR_TRACKER (tracker)); - - ensure_xfixes_cursor (tracker); - - if (x) - *x = tracker->hot_x; - if (y) - *y = tracker->hot_y; -} - -void -meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, - MetaCursor cursor) -{ - Cursor xcursor; - MetaDisplay *display = tracker->screen->display; - - /* First create a cursor for X11 applications that don't specify their own */ - xcursor = meta_display_create_x_cursor (display, cursor); - - XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor); - XFlush (display->xdisplay); - XFreeCursor (display->xdisplay, xcursor); -} - -void -meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, - int *x, - int *y, - ClutterModifierType *mods) -{ - GdkDeviceManager *gmanager; - GdkDevice *gdevice; - GdkScreen *gscreen; - - gmanager = gdk_display_get_device_manager (gdk_display_get_default ()); - gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID); - - gdk_device_get_position (gdevice, &gscreen, x, y); - gdk_device_get_state (gdevice, - gdk_screen_get_root_window (gscreen), - NULL, (GdkModifierType*)mods); -} - -void -meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, - gboolean visible) -{ - if (visible == tracker->is_showing) - return; - tracker->is_showing = visible; - - if (visible) - XFixesShowCursor (tracker->screen->display->xdisplay, - tracker->screen->xroot); - else - XFixesHideCursor (tracker->screen->display->xdisplay, - tracker->screen->xroot); -} diff --git a/src/core/meta-idle-monitor.c b/src/core/meta-idle-monitor.c deleted file mode 100644 index edc3c61ab..000000000 --- a/src/core/meta-idle-monitor.c +++ /dev/null @@ -1,889 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright 2013 Red Hat, Inc. - * - * 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, see . - * - * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and - * from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c - */ - -/** - * SECTION:idle-monitor - * @title: MetaIdleMonitor - * @short_description: Mutter idle counter (similar to X's IDLETIME) - */ - -#include "config.h" - -#include -#include -#include -#include - -#include -#include -#include -#include "display-private.h" -#include "meta-idle-monitor-private.h" -#include "meta-dbus-idle-monitor.h" - -G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer)); - -struct _MetaIdleMonitor -{ - GObject parent_instance; - - GHashTable *watches; - GHashTable *alarms; - int device_id; - - /* X11 implementation */ - Display *display; - int sync_event_base; - XSyncCounter counter; - XSyncAlarm user_active_alarm; -}; - -struct _MetaIdleMonitorClass -{ - GObjectClass parent_class; -}; - -typedef struct -{ - MetaIdleMonitor *monitor; - guint id; - MetaIdleMonitorWatchFunc callback; - gpointer user_data; - GDestroyNotify notify; - guint64 timeout_msec; - - /* x11 */ - XSyncAlarm xalarm; - int idle_source_id; -} MetaIdleMonitorWatch; - -enum -{ - PROP_0, - PROP_DEVICE_ID, - PROP_LAST, -}; - -static GParamSpec *obj_props[PROP_LAST]; - -G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT) - -static MetaIdleMonitor *device_monitors[256]; -static int device_id_max; - -static gint64 -_xsyncvalue_to_int64 (XSyncValue value) -{ - return ((guint64) XSyncValueHigh32 (value)) << 32 - | (guint64) XSyncValueLow32 (value); -} - -#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32) - -static void -fire_watch (MetaIdleMonitorWatch *watch) -{ - MetaIdleMonitor *monitor; - guint id; - gboolean is_user_active_watch; - - monitor = watch->monitor; - g_object_ref (monitor); - - if (watch->idle_source_id) - { - g_source_remove (watch->idle_source_id); - watch->idle_source_id = 0; - } - - id = watch->id; - is_user_active_watch = (watch->timeout_msec == 0); - - if (watch->callback) - watch->callback (monitor, id, watch->user_data); - - if (is_user_active_watch) - meta_idle_monitor_remove_watch (monitor, id); - - g_object_unref (monitor); -} - -static XSyncAlarm -_xsync_alarm_set (MetaIdleMonitor *monitor, - XSyncTestType test_type, - guint64 interval, - gboolean want_events) -{ - XSyncAlarmAttributes attr; - XSyncValue delta; - guint flags; - - flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | - XSyncCAValue | XSyncCADelta | XSyncCAEvents; - - XSyncIntToValue (&delta, 0); - attr.trigger.counter = monitor->counter; - attr.trigger.value_type = XSyncAbsolute; - attr.delta = delta; - attr.events = want_events; - - GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value); - attr.trigger.test_type = test_type; - return XSyncCreateAlarm (monitor->display, flags, &attr); -} - -static void -ensure_alarm_rescheduled (Display *dpy, - XSyncAlarm alarm) -{ - XSyncAlarmAttributes attr; - - /* Some versions of Xorg have an issue where alarms aren't - * always rescheduled. Calling XSyncChangeAlarm, even - * without any attributes, will reschedule the alarm. */ - XSyncChangeAlarm (dpy, alarm, 0, &attr); -} - -static void -set_alarm_enabled (Display *dpy, - XSyncAlarm alarm, - gboolean enabled) -{ - XSyncAlarmAttributes attr; - attr.events = enabled; - XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr); -} - -static void -check_x11_watch (gpointer data, - gpointer user_data) -{ - MetaIdleMonitorWatch *watch = data; - XSyncAlarm alarm = (XSyncAlarm) user_data; - - if (watch->xalarm != alarm) - return; - - fire_watch (watch); -} - -static void -meta_idle_monitor_handle_xevent (MetaIdleMonitor *monitor, - XSyncAlarmNotifyEvent *alarm_event) -{ - XSyncAlarm alarm; - GList *watches; - gboolean has_alarm; - - if (alarm_event->state != XSyncAlarmActive) - return; - - alarm = alarm_event->alarm; - - has_alarm = FALSE; - - if (alarm == monitor->user_active_alarm) - { - set_alarm_enabled (monitor->display, - alarm, - FALSE); - has_alarm = TRUE; - } - else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm)) - { - ensure_alarm_rescheduled (monitor->display, - alarm); - has_alarm = TRUE; - } - - if (has_alarm) - { - watches = g_hash_table_get_values (monitor->watches); - - g_list_foreach (watches, check_x11_watch, (gpointer) alarm); - g_list_free (watches); - } -} - -void -meta_idle_monitor_handle_xevent_all (XEvent *xevent) -{ - int i; - - for (i = 0; i <= device_id_max; i++) - if (device_monitors[i]) - meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent); -} - -static char * -counter_name_for_device (int device_id) -{ - if (device_id > 0) - return g_strdup_printf ("DEVICEIDLETIME %d", device_id); - - return g_strdup ("IDLETIME"); -} - -static XSyncCounter -find_idletime_counter (MetaIdleMonitor *monitor) -{ - int i; - int ncounters; - XSyncSystemCounter *counters; - XSyncCounter counter = None; - char *counter_name; - - counter_name = counter_name_for_device (monitor->device_id); - counters = XSyncListSystemCounters (monitor->display, &ncounters); - for (i = 0; i < ncounters; i++) - { - if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0) - { - counter = counters[i].counter; - break; - } - } - XSyncFreeSystemCounterList (counters); - g_free (counter_name); - - return counter; -} - -static guint32 -get_next_watch_serial (void) -{ - static guint32 serial = 0; - g_atomic_int_inc (&serial); - return serial; -} - -static void -idle_monitor_watch_free (MetaIdleMonitorWatch *watch) -{ - MetaIdleMonitor *monitor; - - if (watch == NULL) - return; - - monitor = watch->monitor; - g_object_ref (monitor); - - if (watch->idle_source_id) - { - g_source_remove (watch->idle_source_id); - watch->idle_source_id = 0; - } - - if (watch->notify != NULL) - watch->notify (watch->user_data); - - if (watch->xalarm != monitor->user_active_alarm && - watch->xalarm != None) - { - XSyncDestroyAlarm (monitor->display, watch->xalarm); - g_hash_table_remove (monitor->alarms, (gpointer) watch->xalarm); - } - - g_object_unref (monitor); - g_slice_free (MetaIdleMonitorWatch, watch); -} - -static void -init_xsync (MetaIdleMonitor *monitor) -{ - monitor->counter = find_idletime_counter (monitor); - /* IDLETIME counter not found? */ - if (monitor->counter == None) - { - meta_warning ("IDLETIME counter not found\n"); - return; - } - - monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE); -} - -static void -meta_idle_monitor_dispose (GObject *object) -{ - MetaIdleMonitor *monitor; - - monitor = META_IDLE_MONITOR (object); - - g_clear_pointer (&monitor->watches, g_hash_table_destroy); - g_clear_pointer (&monitor->alarms, g_hash_table_destroy); - - if (monitor->user_active_alarm != None) - { - XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm); - monitor->user_active_alarm = None; - } - - G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object); -} - -static void -meta_idle_monitor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - - switch (prop_id) - { - case PROP_DEVICE_ID: - g_value_set_int (value, monitor->device_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_idle_monitor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - switch (prop_id) - { - case PROP_DEVICE_ID: - monitor->device_id = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_idle_monitor_constructed (GObject *object) -{ - MetaIdleMonitor *monitor = META_IDLE_MONITOR (object); - - monitor->display = meta_get_display ()->xdisplay; - init_xsync (monitor); -} - -static void -meta_idle_monitor_class_init (MetaIdleMonitorClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = meta_idle_monitor_dispose; - object_class->constructed = meta_idle_monitor_constructed; - object_class->get_property = meta_idle_monitor_get_property; - object_class->set_property = meta_idle_monitor_set_property; - - /** - * MetaIdleMonitor:device_id: - * - * The device to listen to idletime on. - */ - obj_props[PROP_DEVICE_ID] = - g_param_spec_int ("device-id", - "Device ID", - "The device to listen to idletime on", - 0, 255, 0, - G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]); -} - -static void -meta_idle_monitor_init (MetaIdleMonitor *monitor) -{ - monitor->watches = g_hash_table_new_full (NULL, - NULL, - NULL, - (GDestroyNotify)idle_monitor_watch_free); - - monitor->alarms = g_hash_table_new (NULL, NULL); -} - -static void -ensure_device_monitor (int device_id) -{ - if (device_monitors[device_id]) - return; - - device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL); - device_id_max = MAX (device_id_max, device_id); -} - -/** - * meta_idle_monitor_get_core: - * - * Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global - * idletime for all devices. To track device-specific idletime, - * use meta_idle_monitor_get_for_device(). - */ -MetaIdleMonitor * -meta_idle_monitor_get_core (void) -{ - ensure_device_monitor (0); - return device_monitors[0]; -} - -/** - * meta_idle_monitor_get_for_device: - * @device_id: the device to get the idle time for. - * - * Returns: (transfer none): a new #MetaIdleMonitor that tracks the - * device-specific idletime for @device. To track server-global idletime - * for all devices, use meta_idle_monitor_get_core(). - */ -MetaIdleMonitor * -meta_idle_monitor_get_for_device (int device_id) -{ - g_return_val_if_fail (device_id > 0 && device_id < 256, NULL); - - ensure_device_monitor (device_id); - return device_monitors[device_id]; -} - -static gboolean -fire_watch_idle (gpointer data) -{ - MetaIdleMonitorWatch *watch = data; - - watch->idle_source_id = 0; - fire_watch (watch); - - return FALSE; -} - -static MetaIdleMonitorWatch * -make_watch (MetaIdleMonitor *monitor, - guint64 timeout_msec, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) -{ - MetaIdleMonitorWatch *watch; - - watch = g_slice_new0 (MetaIdleMonitorWatch); - watch->monitor = monitor; - watch->id = get_next_watch_serial (); - watch->callback = callback; - watch->user_data = user_data; - watch->notify = notify; - watch->timeout_msec = timeout_msec; - - if (timeout_msec != 0) - { - watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE); - - g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm); - - if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec) - watch->idle_source_id = g_idle_add (fire_watch_idle, watch); - } - else if (monitor->user_active_alarm != None) - { - watch->xalarm = monitor->user_active_alarm; - - set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE); - } - - g_hash_table_insert (monitor->watches, - GUINT_TO_POINTER (watch->id), - watch); - return watch; -} - -/** - * meta_idle_monitor_add_idle_watch: - * @monitor: A #MetaIdleMonitor - * @interval_msec: The idletime interval, in milliseconds - * @callback: (allow-none): The callback to call when the user has - * accumulated @interval_msec milliseconds of idle time. - * @user_data: (allow-none): The user data to pass to the callback - * @notify: A #GDestroyNotify - * - * Returns: a watch id - * - * Adds a watch for a specific idle time. The callback will be called - * when the user has accumulated @interval_msec milliseconds of idle time. - * This function will return an ID that can either be passed to - * meta_idle_monitor_remove_watch(), or can be used to tell idle time - * watches apart if you have more than one. - * - * Also note that this function will only care about positive transitions - * (user's idle time exceeding a certain time). If you want to know about - * when the user has become active, use - * meta_idle_monitor_add_user_active_watch(). - */ -guint -meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor, - guint64 interval_msec, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) -{ - MetaIdleMonitorWatch *watch; - - g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); - g_return_val_if_fail (interval_msec > 0, 0); - - watch = make_watch (monitor, - interval_msec, - callback, - user_data, - notify); - - return watch->id; -} - -/** - * meta_idle_monitor_add_user_active_watch: - * @monitor: A #MetaIdleMonitor - * @callback: (allow-none): The callback to call when the user is - * active again. - * @user_data: (allow-none): The user data to pass to the callback - * @notify: A #GDestroyNotify - * - * Returns: a watch id - * - * Add a one-time watch to know when the user is active again. - * Note that this watch is one-time and will de-activate after the - * function is called, for efficiency purposes. It's most convenient - * to call this when an idle watch, as added by - * meta_idle_monitor_add_idle_watch(), has triggered. - */ -guint -meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor, - MetaIdleMonitorWatchFunc callback, - gpointer user_data, - GDestroyNotify notify) -{ - MetaIdleMonitorWatch *watch; - - g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0); - - watch = make_watch (monitor, - 0, - callback, - user_data, - notify); - - return watch->id; -} - -/** - * meta_idle_monitor_remove_watch: - * @monitor: A #MetaIdleMonitor - * @id: A watch ID - * - * Removes an idle time watcher, previously added by - * meta_idle_monitor_add_idle_watch() or - * meta_idle_monitor_add_user_active_watch(). - */ -void -meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor, - guint id) -{ - g_return_if_fail (META_IS_IDLE_MONITOR (monitor)); - - g_object_ref (monitor); - g_hash_table_remove (monitor->watches, - GUINT_TO_POINTER (id)); - g_object_unref (monitor); -} - -/** - * meta_idle_monitor_get_idletime: - * @monitor: A #MetaIdleMonitor - * - * Returns: The current idle time, in milliseconds, or -1 for not supported - */ -gint64 -meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor) -{ - XSyncValue value; - - if (!XSyncQueryCounter (monitor->display, monitor->counter, &value)) - return -1; - - return _xsyncvalue_to_int64 (value); -} - -static gboolean -handle_get_idletime (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - MetaIdleMonitor *monitor) -{ - guint64 idletime; - - idletime = meta_idle_monitor_get_idletime (monitor); - meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime); - - return TRUE; -} - -typedef struct { - MetaDBusIdleMonitor *dbus_monitor; - MetaIdleMonitor *monitor; - char *dbus_name; - guint watch_id; - guint name_watcher_id; -} DBusWatch; - -static void -destroy_dbus_watch (gpointer data) -{ - DBusWatch *watch = data; - - g_object_unref (watch->dbus_monitor); - g_object_unref (watch->monitor); - g_free (watch->dbus_name); - g_bus_unwatch_name (watch->name_watcher_id); - - g_slice_free (DBusWatch, watch); -} - -static void -dbus_idle_callback (MetaIdleMonitor *monitor, - guint watch_id, - gpointer user_data) -{ - DBusWatch *watch = user_data; - GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor); - - g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), - watch->dbus_name, - g_dbus_interface_skeleton_get_object_path (skeleton), - "org.gnome.Mutter.IdleMonitor", - "WatchFired", - g_variant_new ("(u)", watch_id), - NULL); -} - -static void -name_vanished_callback (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - DBusWatch *watch = user_data; - - meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id); -} - -static DBusWatch * -make_dbus_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - MetaIdleMonitor *monitor) -{ - DBusWatch *watch; - - watch = g_slice_new (DBusWatch); - watch->dbus_monitor = g_object_ref (skeleton); - watch->monitor = g_object_ref (monitor); - watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation)); - watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation), - watch->dbus_name, - G_BUS_NAME_WATCHER_FLAGS_NONE, - NULL, /* appeared */ - name_vanished_callback, - watch, NULL); - - return watch; -} - -static gboolean -handle_add_idle_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - guint64 interval, - MetaIdleMonitor *monitor) -{ - DBusWatch *watch; - - watch = make_dbus_watch (skeleton, invocation, monitor); - watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval, - dbus_idle_callback, watch, destroy_dbus_watch); - - meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id); - - return TRUE; -} - -static gboolean -handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - MetaIdleMonitor *monitor) -{ - DBusWatch *watch; - - watch = make_dbus_watch (skeleton, invocation, monitor); - watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor, - dbus_idle_callback, watch, - destroy_dbus_watch); - - meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id); - - return TRUE; -} - -static gboolean -handle_remove_watch (MetaDBusIdleMonitor *skeleton, - GDBusMethodInvocation *invocation, - guint id, - MetaIdleMonitor *monitor) -{ - meta_idle_monitor_remove_watch (monitor, id); - meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation); - - return TRUE; -} - -static void -create_monitor_skeleton (GDBusObjectManagerServer *manager, - MetaIdleMonitor *monitor, - const char *path) -{ - MetaDBusIdleMonitor *skeleton; - MetaDBusObjectSkeleton *object; - - skeleton = meta_dbus_idle_monitor_skeleton_new (); - g_signal_connect_object (skeleton, "handle-add-idle-watch", - G_CALLBACK (handle_add_idle_watch), monitor, 0); - g_signal_connect_object (skeleton, "handle-add-user-active-watch", - G_CALLBACK (handle_add_user_active_watch), monitor, 0); - g_signal_connect_object (skeleton, "handle-remove-watch", - G_CALLBACK (handle_remove_watch), monitor, 0); - g_signal_connect_object (skeleton, "handle-get-idletime", - G_CALLBACK (handle_get_idletime), monitor, 0); - - object = meta_dbus_object_skeleton_new (path); - meta_dbus_object_skeleton_set_idle_monitor (object, skeleton); - - g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); -} - -static void -on_device_added (ClutterDeviceManager *device_manager, - ClutterInputDevice *device, - GDBusObjectManagerServer *manager) -{ - - MetaIdleMonitor *monitor; - int device_id; - char *path; - - device_id = clutter_input_device_get_device_id (device); - monitor = meta_idle_monitor_get_for_device (device_id); - path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); - - create_monitor_skeleton (manager, monitor, path); - g_free (path); -} - -static void -on_device_removed (ClutterDeviceManager *device_manager, - ClutterInputDevice *device, - GDBusObjectManagerServer *manager) -{ - int device_id; - char *path; - - device_id = clutter_input_device_get_device_id (device); - path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); - g_dbus_object_manager_server_unexport (manager, path); - g_free (path); - - g_clear_object (&device_monitors[device_id]); - if (device_id == device_id_max) - device_id_max--; -} - -static void -on_bus_acquired (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - GDBusObjectManagerServer *manager; - ClutterDeviceManager *device_manager; - MetaIdleMonitor *monitor; - GSList *devices, *iter; - char *path; - - manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor"); - - /* We never clear the core monitor, as that's supposed to cumulate idle times from - all devices */ - monitor = meta_idle_monitor_get_core (); - path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core"); - create_monitor_skeleton (manager, monitor, path); - g_free (path); - - device_manager = clutter_device_manager_get_default (); - devices = clutter_device_manager_list_devices (device_manager); - - for (iter = devices; iter; iter = iter->next) - on_device_added (device_manager, iter->data, manager); - - g_slist_free (devices); - - g_signal_connect_object (device_manager, "device-added", - G_CALLBACK (on_device_added), manager, 0); - g_signal_connect_object (device_manager, "device-removed", - G_CALLBACK (on_device_removed), manager, 0); - - g_dbus_object_manager_server_set_connection (manager, connection); -} - -static void -on_name_acquired (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - meta_verbose ("Acquired name %s\n", name); -} - -static void -on_name_lost (GDBusConnection *connection, - const char *name, - gpointer user_data) -{ - meta_verbose ("Lost or failed to acquire name %s\n", name); -} - -void -meta_idle_monitor_init_dbus (void) -{ - static int dbus_name_id; - - if (dbus_name_id > 0) - return; - - dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, - "org.gnome.Mutter.IdleMonitor", - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | - (meta_get_replace_current_wm () ? - G_BUS_NAME_OWNER_FLAGS_REPLACE : 0), - on_bus_acquired, - on_name_acquired, - on_name_lost, - NULL, NULL); -} - diff --git a/src/core/place.c b/src/core/place.c index 8894114d6..6c0efc128 100644 --- a/src/core/place.c +++ b/src/core/place.c @@ -344,7 +344,7 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window, /* denied_focus_and_not_transient is only set when focus_window != NULL */ if (window->denied_focus_and_not_transient && - window->wm_state_modal && /* FIXME: Maybe do this for all transients? */ + window->type == META_WINDOW_MODAL_DIALOG && meta_window_same_application (window, focus_window) && window_overlaps_focus_window (window)) { @@ -610,7 +610,7 @@ meta_window_place (MetaWindow *window, meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc); windows = NULL; - + switch (window->type) { /* Run placement algorithm on these. */ @@ -638,7 +638,7 @@ meta_window_place (MetaWindow *window, case META_WINDOW_OVERRIDE_OTHER: goto done_no_constraints; } - + if (meta_prefs_get_disable_workarounds ()) { switch (window->type) @@ -699,18 +699,11 @@ meta_window_place (MetaWindow *window, goto done_no_constraints; } } - - if ((window->type == META_WINDOW_DIALOG || - window->type == META_WINDOW_MODAL_DIALOG) && - window->xtransient_for != None) - { - /* Center horizontally, at top of parent vertically */ - MetaWindow *parent; - - parent = - meta_display_lookup_x_window (window->display, - window->xtransient_for); + if (window->type == META_WINDOW_DIALOG || + window->type == META_WINDOW_MODAL_DIALOG) + { + MetaWindow *parent = meta_window_get_transient_for (window); if (parent) { diff --git a/src/core/prefs.c b/src/core/prefs.c index 772069526..98d62eed7 100644 --- a/src/core/prefs.c +++ b/src/core/prefs.c @@ -36,6 +36,7 @@ #include #include #include "keybindings-private.h" +#include "meta-accel-parse.h" /* If you add a key, it needs updating in init() and in the gsettings * notify listener and of course in the .schemas file. @@ -1187,8 +1188,8 @@ maybe_give_disable_workarounds_warning (void) { first_disable = FALSE; - meta_warning (_("Workarounds for broken applications disabled. " - "Some applications may not behave properly.\n")); + meta_warning ("Workarounds for broken applications disabled. " + "Some applications may not behave properly.\n"); } } @@ -1262,8 +1263,8 @@ titlebar_handler (GVariant *value, if (desc == NULL) { - meta_warning (_("Could not parse font description " - "\"%s\" from GSettings key %s\n"), + meta_warning ("Could not parse font description " + "\"%s\" from GSettings key %s\n", string_value ? string_value : "(null)", KEY_TITLEBAR_FONT); return FALSE; @@ -1323,13 +1324,13 @@ mouse_button_mods_handler (GVariant *value, *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); - if (!string_value || !meta_ui_parse_modifier (string_value, &mods)) + if (!string_value || !meta_parse_modifier (string_value, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); - meta_warning (_("\"%s\" found in configuration database is " - "not a valid value for mouse button modifier\n"), + meta_warning ("\"%s\" found in configuration database is " + "not a valid value for mouse button modifier\n", string_value); return FALSE; @@ -1627,9 +1628,9 @@ overlay_key_handler (GVariant *value, *result = NULL; /* ignored */ string_value = g_variant_get_string (value, NULL); - if (string_value && meta_ui_parse_accelerator (string_value, &combo.keysym, - &combo.keycode, - &combo.modifiers)) + if (string_value && meta_parse_accelerator (string_value, &combo.keysym, + &combo.keycode, + &combo.modifiers)) ; else { @@ -1887,11 +1888,11 @@ update_binding (MetaKeyPref *binding, keycode = 0; mods = 0; - if (!meta_ui_parse_accelerator (strokes[i], &keysym, &keycode, &mods)) + if (!meta_parse_accelerator (strokes[i], &keysym, &keycode, &mods)) { meta_topic (META_DEBUG_KEYBINDINGS, "Failed to parse new GSettings value\n"); - meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"), + meta_warning ("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n", strokes[i], binding->name); /* Value is kept and will thus be removed next time we save the key. diff --git a/src/core/screen-private.h b/src/core/screen-private.h index f6d465c21..ef279e580 100644 --- a/src/core/screen-private.h +++ b/src/core/screen-private.h @@ -36,7 +36,7 @@ #include #include "stack-tracker.h" #include "ui.h" -#include "monitor-private.h" +#include "meta-monitor-manager.h" typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window, gpointer user_data); @@ -82,8 +82,6 @@ struct _MetaScreen MetaCursorTracker *cursor_tracker; MetaCursor current_cursor; - Window flash_window; - Window wm_sn_selection_window; Atom wm_sn_atom; guint32 wm_sn_timestamp; @@ -118,9 +116,6 @@ struct _MetaScreen guint all_keys_grabbed : 1; int closing; - - /* Managed by compositor.c */ - gpointer compositor_data; /* Instead of unmapping withdrawn windows we can leave them mapped * and restack them below a guard window. When using a compositor @@ -223,12 +218,14 @@ void meta_screen_workspace_switched (MetaScreen *screen, void meta_screen_set_active_workspace_hint (MetaScreen *screen); +void meta_screen_create_guard_window (MetaScreen *screen); + +gboolean meta_screen_handle_xevent (MetaScreen *screen, + XEvent *xevent); + int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen, int index); int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, int index); -gboolean meta_screen_handle_xevent (MetaScreen *screen, - XEvent *xevent); - #endif diff --git a/src/core/screen.c b/src/core/screen.c index ec368b81e..2250dee40 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -39,7 +39,6 @@ #include "workspace-private.h" #include "keybindings-private.h" #include "stack.h" -#include "xprops.h" #include #include "mutter-enum-types.h" #include "core.h" @@ -53,6 +52,8 @@ #include #include +#include "x11/xprops.h" + static char* get_screen_name (MetaDisplay *display, int number); @@ -454,6 +455,7 @@ create_guard_window (Display *xdisplay, MetaScreen *screen) XSetWindowAttributes attributes; Window guard_window; gulong create_serial; + MetaStackWindow stack_window; attributes.event_mask = NoEventMask; attributes.override_redirect = True; @@ -488,12 +490,14 @@ create_guard_window (Display *xdisplay, MetaScreen *screen) XISelectEvents (xdisplay, guard_window, &mask, 1); } + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = guard_window; meta_stack_tracker_record_add (screen->stack_tracker, - guard_window, + &stack_window, create_serial); meta_stack_tracker_record_lower (screen->stack_tracker, - guard_window, + &stack_window, XNextRequest (xdisplay)); XLowerWindow (xdisplay, guard_window); XMapWindow (xdisplay, guard_window); @@ -559,7 +563,7 @@ meta_screen_new (MetaDisplay *display, } /* We want to find out when the current selection owner dies */ - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); attrs.event_mask = StructureNotifyMask; XChangeWindowAttributes (xdisplay, current_wm_sn_owner, CWEventMask, &attrs); @@ -579,7 +583,7 @@ meta_screen_new (MetaDisplay *display, if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner) { - meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"), + meta_warning ("Could not acquire window manager selection on screen %d display \"%s\"\n", number, display->name); XDestroyWindow (xdisplay, new_wm_sn_owner); @@ -618,7 +622,7 @@ meta_screen_new (MetaDisplay *display, } /* select our root window events */ - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); /* We need to or with the existing event mask since * gtk+ may be interested in other events. @@ -674,8 +678,9 @@ meta_screen_new (MetaDisplay *display, screen->xscreen = ScreenOfDisplay (xdisplay, number); screen->xroot = xroot; screen->rect.x = screen->rect.y = 0; - - meta_monitor_manager_initialize (); + + if (!meta_is_wayland_compositor ()) + meta_monitor_manager_initialize (); manager = meta_monitor_manager_get (); g_signal_connect (manager, "monitors-changed", @@ -688,7 +693,6 @@ meta_screen_new (MetaDisplay *display, screen->current_cursor = -1; /* invalid/unset */ screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); screen->default_depth = DefaultDepthOfScreen (screen->xscreen); - screen->flash_window = None; screen->wm_sn_selection_window = new_wm_sn_owner; screen->wm_sn_atom = wm_sn_atom; @@ -706,7 +710,6 @@ meta_screen_new (MetaDisplay *display, screen->columns_of_workspaces = -1; screen->vertical_workspaces = FALSE; screen->starting_corner = META_SCREEN_TOPLEFT; - screen->compositor_data = NULL; screen->guard_window = None; reload_monitor_infos (screen); @@ -807,11 +810,7 @@ meta_screen_free (MetaScreen *screen, meta_display_grab (display); - if (screen->display->compositor) - { - meta_compositor_unmanage_screen (screen->display->compositor, - screen); - } + meta_compositor_unmanage (screen->display->compositor); meta_display_unmanage_windows_for_screen (display, screen, timestamp); @@ -842,10 +841,10 @@ meta_screen_free (MetaScreen *screen, meta_stack_free (screen->stack); meta_stack_tracker_free (screen->stack_tracker); - meta_error_trap_push_with_return (screen->display); + meta_error_trap_push (screen->display); XSelectInput (screen->display->xdisplay, screen->xroot, 0); if (meta_error_trap_pop_with_return (screen->display) != Success) - meta_warning (_("Could not release screen %d on display \"%s\"\n"), + meta_warning ("Could not release screen %d on display \"%s\"\n", screen->number, screen->display->name); unset_wm_check_hint (screen); @@ -872,55 +871,36 @@ meta_screen_free (MetaScreen *screen, meta_display_ungrab (display); } +void +meta_screen_create_guard_window (MetaScreen *screen) +{ + if (screen->guard_window == None) + screen->guard_window = create_guard_window (screen->display->xdisplay, screen); +} + void meta_screen_manage_all_windows (MetaScreen *screen) { - Window *_children; - Window *children; + MetaStackWindow *_children; + MetaStackWindow *children; int n_children, i; - if (screen->guard_window == None) - screen->guard_window = create_guard_window (screen->display->xdisplay, - screen); - meta_stack_freeze (screen->stack); meta_stack_tracker_get_stack (screen->stack_tracker, &_children, &n_children); /* Copy the stack as it will be modified as part of the loop */ - children = g_memdup (_children, sizeof (Window) * n_children); + children = g_memdup (_children, sizeof (MetaStackWindow) * n_children); for (i = 0; i < n_children; ++i) { - meta_window_new (screen->display, children[i], TRUE, - META_COMP_EFFECT_NONE); + meta_window_x11_new (screen->display, children[i].x11.xwindow, TRUE, + META_COMP_EFFECT_NONE); } g_free (children); meta_stack_thaw (screen->stack); } -/** - * meta_screen_for_x_screen: - * @xscreen: an X screen structure. - * - * Gets the #MetaScreen corresponding to an X screen structure. - * - * Return value: (transfer none): the #MetaScreen for the X screen - * %NULL if Metacity is not managing the screen. - */ -MetaScreen* -meta_screen_for_x_screen (Screen *xscreen) -{ - MetaDisplay *display; - - display = meta_display_for_x_display (DisplayOfScreen (xscreen)); - - if (display == NULL) - return NULL; - - return meta_display_screen_for_x_screen (display, xscreen); -} - static void prefs_changed_callback (MetaPreference pref, gpointer data) @@ -1404,6 +1384,26 @@ update_focus_mode (MetaScreen *screen) /* nothing to do anymore */ ; } +void +meta_screen_update_cursor (MetaScreen *screen) +{ + MetaDisplay *display = screen->display; + MetaCursor cursor = screen->current_cursor; + Cursor xcursor; + MetaCursorReference *cursor_ref; + + cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor); + meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor_ref); + meta_cursor_reference_unref (cursor_ref); + + /* Set a cursor for X11 applications that don't specify their own */ + xcursor = meta_display_create_x_cursor (display, cursor); + + XDefineCursor (display->xdisplay, screen->xroot, xcursor); + XFlush (display->xdisplay); + XFreeCursor (display->xdisplay, xcursor); +} + void meta_screen_set_cursor (MetaScreen *screen, MetaCursor cursor) @@ -1412,14 +1412,7 @@ meta_screen_set_cursor (MetaScreen *screen, return; screen->current_cursor = cursor; - meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor); -} - -void -meta_screen_update_cursor (MetaScreen *screen) -{ - meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, - screen->current_cursor); + meta_screen_update_cursor (screen); } static gboolean @@ -1460,11 +1453,10 @@ meta_screen_update_tile_preview_timeout (gpointer data) monitor = meta_window_get_current_tile_monitor_number (window); meta_window_get_current_tile_area (window, &tile_rect); meta_compositor_show_tile_preview (screen->display->compositor, - screen, window, &tile_rect, monitor); + window, &tile_rect, monitor); } else - meta_compositor_hide_tile_preview (screen->display->compositor, - screen); + meta_compositor_hide_tile_preview (screen->display->compositor); return FALSE; } @@ -1500,8 +1492,7 @@ meta_screen_hide_tile_preview (MetaScreen *screen) if (screen->tile_preview_timeout_id > 0) g_source_remove (screen->tile_preview_timeout_id); - meta_compositor_hide_tile_preview (screen->display->compositor, - screen); + meta_compositor_hide_tile_preview (screen->display->compositor); } MetaWindow* @@ -1509,38 +1500,19 @@ meta_screen_get_mouse_window (MetaScreen *screen, MetaWindow *not_this_one) { MetaWindow *window; - Window root_return, child_return; - double root_x_return, root_y_return; - double win_x_return, win_y_return; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; + int x, y; if (not_this_one) meta_topic (META_DEBUG_FOCUS, "Focusing mouse window excluding %s\n", not_this_one->desc); - meta_error_trap_push (screen->display); - XIQueryPointer (screen->display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - screen->xroot, - &root_return, - &child_return, - &root_x_return, - &root_y_return, - &win_x_return, - &win_y_return, - &buttons, - &mods, - &group); - meta_error_trap_pop (screen->display); - free (buttons.mask); + meta_cursor_tracker_get_pointer (screen->cursor_tracker, + &x, &y, NULL); window = meta_stack_get_default_focus_window_at_point (screen->stack, screen->active_workspace, not_this_one, - root_x_return, - root_y_return); + x, y); return window; } @@ -1822,28 +1794,11 @@ meta_screen_get_current_monitor (MetaScreen *screen) if (screen->display->monitor_cache_invalidated) { - Window root_return, child_return; - double win_x_return, win_y_return; - double root_x_return, root_y_return; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; + int x, y; - XIQueryPointer (screen->display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - screen->xroot, - &root_return, - &child_return, - &root_x_return, - &root_y_return, - &win_x_return, - &win_y_return, - &buttons, - &mods, - &group); - free (buttons.mask); - - meta_screen_get_current_monitor_for_pos (screen, root_x_return, root_y_return); + meta_cursor_tracker_get_pointer (screen->cursor_tracker, + &x, &y, NULL); + meta_screen_get_current_monitor_for_pos (screen, x, y); } return screen->last_monitor_index; @@ -2554,10 +2509,8 @@ on_monitors_changed (MetaMonitorManager *manager, &changes); } - if (screen->display->compositor) - meta_compositor_sync_screen_size (screen->display->compositor, - screen, - screen->rect.width, screen->rect.height); + meta_compositor_sync_screen_size (screen->display->compositor, + screen->rect.width, screen->rect.height); /* Queue a resize on all the windows */ meta_screen_foreach_window (screen, meta_screen_resize_func, 0); @@ -3097,24 +3050,6 @@ meta_screen_get_size (MetaScreen *screen, *height = screen->rect.height; } -/** - * meta_screen_get_compositor_data: (skip) - * @screen: A #MetaScreen - * - */ -gpointer -meta_screen_get_compositor_data (MetaScreen *screen) -{ - return screen->compositor_data; -} - -void -meta_screen_set_compositor_data (MetaScreen *screen, - gpointer compositor) -{ - screen->compositor_data = compositor; -} - void meta_screen_set_cm_selection (MetaScreen *screen) { @@ -3373,10 +3308,6 @@ gboolean meta_screen_handle_xevent (MetaScreen *screen, XEvent *xevent) { - /* Go through our helpers and see if they want this event. - Currently, only MetaCursorTracker. - */ - if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent)) return TRUE; diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c index 17979e38a..77266a088 100644 --- a/src/core/stack-tracker.c +++ b/src/core/stack-tracker.c @@ -96,28 +96,29 @@ union _MetaStackOp struct { MetaStackOpType type; gulong serial; + MetaStackWindow window; } any; struct { MetaStackOpType type; gulong serial; - Window window; + MetaStackWindow window; } add; struct { MetaStackOpType type; gulong serial; - Window window; + MetaStackWindow window; } remove; struct { MetaStackOpType type; gulong serial; - Window window; - Window sibling; + MetaStackWindow window; + MetaStackWindow sibling; } raise_above; struct { MetaStackOpType type; gulong serial; - Window window; - Window sibling; + MetaStackWindow window; + MetaStackWindow sibling; } lower_below; }; @@ -128,20 +129,25 @@ struct _MetaStackTracker /* This is the last state of the stack as based on events received * from the X server. */ - GArray *server_stack; + GArray *xserver_stack; /* This is the serial of the last request we made that was reflected - * in server_stack + * in xserver_stack */ - gulong server_serial; + gulong xserver_serial; + + /* A combined stack containing X and Wayland windows but without + * any unverified operations applied. */ + GArray *verified_stack; /* This is a queue of requests we've made to change the stacking order, * where we haven't yet gotten a reply back from the server. */ - GQueue *queued_requests; + GQueue *unverified_predictions; - /* This is how we think the stack is, based on server_stack, and - * on requests we've made subsequent to server_stack + /* This is how we think the stack is, based on verified_stack, and + * on the unverified_predictions we've made subsequent to + * verified_stack. */ GArray *predicted_stack; @@ -151,36 +157,81 @@ struct _MetaStackTracker guint sync_stack_later; }; +static gboolean +meta_stack_window_is_set (const MetaStackWindow *window) +{ + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + return window->x11.xwindow == None ? FALSE : TRUE; + else + return window->wayland.meta_window ? TRUE : FALSE; +} + +gboolean +meta_stack_window_equal (const MetaStackWindow *a, + const MetaStackWindow *b) +{ + if (a->any.type == b->any.type) + { + if (a->any.type == META_WINDOW_CLIENT_TYPE_X11) + return a->x11.xwindow == b->x11.xwindow; + else + return a->wayland.meta_window == b->wayland.meta_window; + } + else + return FALSE; +} + +static char * +get_window_id (MetaStackWindow *window) +{ + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + return g_strdup_printf ("X11:%lx", window->x11.xwindow); + else + return g_strdup_printf ("Wayland:%p", window->wayland.meta_window); +} + static void meta_stack_op_dump (MetaStackOp *op, const char *prefix, const char *suffix) { + char *window_id = get_window_id (&op->any.window); + switch (op->any.type) { case STACK_OP_ADD: - meta_topic (META_DEBUG_STACK, "%sADD(%#lx; %ld)%s", - prefix, op->add.window, op->any.serial, suffix); + meta_topic (META_DEBUG_STACK, "%sADD(%s; %ld)%s", + prefix, window_id, op->any.serial, suffix); break; case STACK_OP_REMOVE: - meta_topic (META_DEBUG_STACK, "%sREMOVE(%#lx; %ld)%s", - prefix, op->add.window, op->any.serial, suffix); + meta_topic (META_DEBUG_STACK, "%sREMOVE(%s; %ld)%s", + prefix, window_id, op->any.serial, suffix); break; case STACK_OP_RAISE_ABOVE: - meta_topic (META_DEBUG_STACK, "%sRAISE_ABOVE(%#lx, %#lx; %ld)%s", - prefix, - op->raise_above.window, op->raise_above.sibling, - op->any.serial, - suffix); - break; + { + char *sibling_id = get_window_id (&op->raise_above.sibling); + meta_topic (META_DEBUG_STACK, "%sRAISE_ABOVE(%s, %s; %ld)%s", + prefix, + window_id, sibling_id, + op->any.serial, + suffix); + g_free (sibling_id); + break; + } case STACK_OP_LOWER_BELOW: - meta_topic (META_DEBUG_STACK, "%sLOWER_BELOW(%#lx, %#lx; %ld)%s", - prefix, - op->lower_below.window, op->lower_below.sibling, - op->any.serial, - suffix); - break; + { + char *sibling_id = get_window_id (&op->lower_below.sibling); + meta_topic (META_DEBUG_STACK, "%sLOWER_BELOW(%s, %s; %ld)%s", + prefix, + window_id, sibling_id, + op->any.serial, + suffix); + g_free (sibling_id); + break; + } } + + g_free (window_id); } static void @@ -191,23 +242,42 @@ meta_stack_tracker_dump (MetaStackTracker *tracker) meta_topic (META_DEBUG_STACK, "MetaStackTracker state (screen=%d)\n", tracker->screen->number); meta_push_no_msg_prefix (); - meta_topic (META_DEBUG_STACK, " server_serial: %ld\n", tracker->server_serial); - meta_topic (META_DEBUG_STACK, " server_stack: "); - for (i = 0; i < tracker->server_stack->len; i++) - meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->server_stack, Window, i)); - if (tracker->predicted_stack) + meta_topic (META_DEBUG_STACK, " xserver_serial: %ld\n", tracker->xserver_serial); + meta_topic (META_DEBUG_STACK, " xserver_stack: "); + for (i = 0; i < tracker->xserver_stack->len; i++) { - meta_topic (META_DEBUG_STACK, "\n predicted_stack: "); - for (i = 0; i < tracker->predicted_stack->len; i++) - meta_topic (META_DEBUG_STACK, " %#lx", g_array_index (tracker->predicted_stack, Window, i)); + MetaStackWindow *window = &g_array_index (tracker->xserver_stack, MetaStackWindow, i); + char *window_id = get_window_id (window); + meta_topic (META_DEBUG_STACK, " %s", window_id); + g_free (window_id); } - meta_topic (META_DEBUG_STACK, "\n queued_requests: ["); - for (l = tracker->queued_requests->head; l; l = l->next) + meta_topic (META_DEBUG_STACK, "\n verfied_stack: "); + for (i = 0; i < tracker->verified_stack->len; i++) + { + MetaStackWindow *window = &g_array_index (tracker->verified_stack, MetaStackWindow, i); + char *window_id = get_window_id (window); + meta_topic (META_DEBUG_STACK, " %s", window_id); + g_free (window_id); + } + meta_topic (META_DEBUG_STACK, "\n unverified_predictions: ["); + for (l = tracker->unverified_predictions->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_dump (op, "", l->next ? ", " : ""); } meta_topic (META_DEBUG_STACK, "]\n"); + if (tracker->predicted_stack) + { + meta_topic (META_DEBUG_STACK, "\n predicted_stack: "); + for (i = 0; i < tracker->predicted_stack->len; i++) + { + MetaStackWindow *window = &g_array_index (tracker->predicted_stack, MetaStackWindow, i); + char *window_id = get_window_id (window); + meta_topic (META_DEBUG_STACK, " %s", window_id); + g_free (window_id); + } + } + meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); } @@ -218,42 +288,57 @@ meta_stack_op_free (MetaStackOp *op) } static int -find_window (GArray *stack, - Window window) +find_window (GArray *window_stack, + MetaStackWindow *window) { guint i; - for (i = 0; i < stack->len; i++) - if (g_array_index (stack, Window, i) == window) - return i; + for (i = 0; i < window_stack->len; i++) + { + MetaStackWindow *current = &g_array_index (window_stack, MetaStackWindow, i); + if (current->any.type == window->any.type) + { + if (current->any.type == META_WINDOW_CLIENT_TYPE_X11 && + current->x11.xwindow == window->x11.xwindow) + return i; + else + if (current->wayland.meta_window == window->wayland.meta_window) + return i; + } + } return -1; } /* Returns TRUE if stack was changed */ static gboolean -move_window_above (GArray *stack, - Window window, - int old_pos, - int above_pos) +move_window_above (GArray *stack, + MetaStackWindow *window, + int old_pos, + int above_pos) { + /* Copy the window by-value before we start shifting things around + * in the stack in case window points into the stack itself. */ + MetaStackWindow window_val = *window; int i; if (old_pos < above_pos) { for (i = old_pos; i < above_pos; i++) - g_array_index (stack, Window, i) = g_array_index (stack, Window, i + 1); + g_array_index (stack, MetaStackWindow, i) = + g_array_index (stack, MetaStackWindow, i + 1); - g_array_index (stack, Window, above_pos) = window; + g_array_index (stack, MetaStackWindow, above_pos) = window_val; return TRUE; } else if (old_pos > above_pos + 1) { for (i = old_pos; i > above_pos + 1; i--) - g_array_index (stack, Window, i) = g_array_index (stack, Window, i - 1); + g_array_index (stack, MetaStackWindow, i) = + g_array_index (stack, MetaStackWindow, i - 1); - g_array_index (stack, Window, above_pos + 1) = window; + g_array_index (stack, MetaStackWindow, above_pos + 1) = window_val; return TRUE; } @@ -270,11 +355,13 @@ meta_stack_op_apply (MetaStackOp *op, { case STACK_OP_ADD: { - int old_pos = find_window (stack, op->add.window); + int old_pos = find_window (stack, &op->add.window); if (old_pos >= 0) { - g_warning ("STACK_OP_ADD: window %#lx already in stack", - op->add.window); + char *window_id = get_window_id (&op->add.window); + g_warning ("STACK_OP_ADD: window %s already in stack", + window_id); + g_free (window_id); return FALSE; } @@ -283,11 +370,13 @@ meta_stack_op_apply (MetaStackOp *op, } case STACK_OP_REMOVE: { - int old_pos = find_window (stack, op->remove.window); + int old_pos = find_window (stack, &op->remove.window); if (old_pos < 0) { - g_warning ("STACK_OP_REMOVE: window %#lx not in stack", - op->remove.window); + char *window_id = get_window_id (&op->remove.window); + g_warning ("STACK_OP_REMOVE: window %s not in stack", + window_id); + g_free (window_id); return FALSE; } @@ -296,22 +385,26 @@ meta_stack_op_apply (MetaStackOp *op, } case STACK_OP_RAISE_ABOVE: { - int old_pos = find_window (stack, op->raise_above.window); + int old_pos = find_window (stack, &op->raise_above.window); int above_pos; if (old_pos < 0) { - g_warning ("STACK_OP_RAISE_ABOVE: window %#lx not in stack", - op->raise_above.window); + char *window_id = get_window_id (&op->raise_above.window); + g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack", + window_id); + g_free (window_id); return FALSE; } - if (op->raise_above.sibling != None) + if (meta_stack_window_is_set (&op->raise_above.sibling)) { - above_pos = find_window (stack, op->raise_above.sibling); + above_pos = find_window (stack, &op->raise_above.sibling); if (above_pos < 0) { - g_warning ("STACK_OP_RAISE_ABOVE: sibling window %#lx not in stack", - op->raise_above.sibling); + char *sibling_id = get_window_id (&op->raise_above.sibling); + g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack", + sibling_id); + g_free (sibling_id); return FALSE; } } @@ -320,26 +413,30 @@ meta_stack_op_apply (MetaStackOp *op, above_pos = -1; } - return move_window_above (stack, op->raise_above.window, old_pos, above_pos); + return move_window_above (stack, &op->raise_above.window, old_pos, above_pos); } case STACK_OP_LOWER_BELOW: { - int old_pos = find_window (stack, op->lower_below.window); + int old_pos = find_window (stack, &op->lower_below.window); int above_pos; if (old_pos < 0) { - g_warning ("STACK_OP_LOWER_BELOW: window %#lx not in stack", - op->lower_below.window); + char *window_id = get_window_id (&op->lower_below.window); + g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack", + window_id); + g_free (window_id); return FALSE; } - if (op->lower_below.sibling != None) + if (meta_stack_window_is_set (&op->lower_below.sibling)) { - int below_pos = find_window (stack, op->lower_below.sibling); + int below_pos = find_window (stack, &op->lower_below.sibling); if (below_pos < 0) { - g_warning ("STACK_OP_LOWER_BELOW: sibling window %#lx not in stack", - op->lower_below.sibling); + char *sibling_id = get_window_id (&op->lower_below.sibling); + g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack", + sibling_id); + g_free (sibling_id); return FALSE; } @@ -350,7 +447,7 @@ meta_stack_op_apply (MetaStackOp *op, above_pos = stack->len - 1; } - return move_window_above (stack, op->lower_below.window, old_pos, above_pos); + return move_window_above (stack, &op->lower_below.window, old_pos, above_pos); } } @@ -359,37 +456,65 @@ meta_stack_op_apply (MetaStackOp *op, } static GArray * -copy_stack (Window *windows, - guint n_windows) +copy_stack (GArray *stack) { - GArray *stack = g_array_new (FALSE, FALSE, sizeof (Window)); + GArray *copy = g_array_sized_new (FALSE, FALSE, sizeof (MetaStackWindow), stack->len); - g_array_set_size (stack, n_windows); - memcpy (stack->data, windows, sizeof (Window) * n_windows); + g_array_set_size (copy, stack->len); - return stack; + memcpy (copy->data, stack->data, sizeof (MetaStackWindow) * stack->len); + + return copy; +} + +static void +requery_xserver_stack (MetaStackTracker *tracker) +{ + MetaScreen *screen = tracker->screen; + Window ignored1, ignored2; + Window *children; + guint n_children; + guint i; + + if (tracker->xserver_stack) + g_array_free (tracker->xserver_stack, TRUE); + + tracker->xserver_serial = XNextRequest (screen->display->xdisplay); + + XQueryTree (screen->display->xdisplay, + screen->xroot, + &ignored1, &ignored2, &children, &n_children); + + tracker->xserver_stack = + g_array_sized_new (FALSE, FALSE, sizeof (MetaStackWindow), n_children); + g_array_set_size (tracker->xserver_stack, n_children); + + for (i = 0; i < n_children; i++) + { + MetaStackWindow *window = + &g_array_index (tracker->xserver_stack, MetaStackWindow, i); + window->any.type = META_WINDOW_CLIENT_TYPE_X11; + window->x11.xwindow = children[i]; + } + + XFree (children); } MetaStackTracker * meta_stack_tracker_new (MetaScreen *screen) { MetaStackTracker *tracker; - Window ignored1, ignored2; - Window *children; - guint n_children; tracker = g_new0 (MetaStackTracker, 1); tracker->screen = screen; - tracker->server_serial = XNextRequest (screen->display->xdisplay); + requery_xserver_stack (tracker); - XQueryTree (screen->display->xdisplay, - screen->xroot, - &ignored1, &ignored2, &children, &n_children); - tracker->server_stack = copy_stack (children, n_children); - XFree (children); + tracker->verified_stack = copy_stack (tracker->xserver_stack); - tracker->queued_requests = g_queue_new (); + tracker->unverified_predictions = g_queue_new (); + + meta_stack_tracker_dump (tracker); return tracker; } @@ -400,23 +525,38 @@ meta_stack_tracker_free (MetaStackTracker *tracker) if (tracker->sync_stack_later) meta_later_remove (tracker->sync_stack_later); - g_array_free (tracker->server_stack, TRUE); + g_array_free (tracker->xserver_stack, TRUE); + g_array_free (tracker->verified_stack, TRUE); if (tracker->predicted_stack) g_array_free (tracker->predicted_stack, TRUE); - g_queue_foreach (tracker->queued_requests, (GFunc)meta_stack_op_free, NULL); - g_queue_free (tracker->queued_requests); - tracker->queued_requests = NULL; + g_queue_foreach (tracker->unverified_predictions, (GFunc)meta_stack_op_free, NULL); + g_queue_free (tracker->unverified_predictions); + tracker->unverified_predictions = NULL; g_free (tracker); } static void -stack_tracker_queue_request (MetaStackTracker *tracker, - MetaStackOp *op) +stack_tracker_apply_prediction (MetaStackTracker *tracker, + MetaStackOp *op) { - meta_stack_op_dump (op, "Queueing: ", "\n"); - g_queue_push_tail (tracker->queued_requests, op); + /* If this is a wayland operation then it's implicitly verified so + * we can apply it immediately so long as it doesn't depend on any + * unverified X operations... + */ + if (op->any.window.any.type == META_WINDOW_CLIENT_TYPE_WAYLAND && + tracker->unverified_predictions->length == 0) + { + if (meta_stack_op_apply (op, tracker->verified_stack)) + meta_stack_tracker_queue_sync_stack (tracker); + } + else + { + meta_stack_op_dump (op, "Predicting: ", "\n"); + g_queue_push_tail (tracker->unverified_predictions, op); + } + if (!tracker->predicted_stack || meta_stack_op_apply (op, tracker->predicted_stack)) meta_stack_tracker_queue_sync_stack (tracker); @@ -425,44 +565,50 @@ stack_tracker_queue_request (MetaStackTracker *tracker, } void -meta_stack_tracker_record_add (MetaStackTracker *tracker, - Window window, - gulong serial) +meta_stack_tracker_record_add (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_ADD; op->any.serial = serial; - op->add.window = window; + op->any.window = *window; - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_remove (MetaStackTracker *tracker, - Window window, - gulong serial) +meta_stack_tracker_record_remove (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_REMOVE; op->any.serial = serial; - op->remove.window = window; + op->any.window = *window; - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, - Window *windows, - int n_windows, - gulong serial) +meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, + const MetaStackWindow *windows, + int n_windows, + gulong serial) { int i; + int n_x_windows = 0; /* XRestackWindows() isn't actually a X requests - it's broken down * by XLib into a series of XConfigureWindow(StackMode=below); we - * mirror that exactly here. + * mirror that here. + * + * Since there may be a mixture of X and wayland windows in the + * stack it's ambiguous which operations we should associate with an + * X serial number. One thing we do know though is that there will + * be (n_x_window - 1) X requests made. * * Aside: Having a separate StackOp for this would be possible to * get some extra efficiency in memory allocation and in applying @@ -471,79 +617,406 @@ meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, * events with intermediate serials, set n_complete rather than * removing the op from the queue. */ + if (n_windows && windows[0].any.type == META_WINDOW_CLIENT_TYPE_X11) + n_x_windows++; for (i = 0; i < n_windows - 1; i++) - meta_stack_tracker_record_lower_below (tracker, windows[i + 1], windows[i], - serial + i); + { + const MetaStackWindow *lower = &windows[i + 1]; + gboolean involves_x = FALSE; + + if (lower->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + n_x_windows++; + + /* Since the first X window is a reference point we only + * assoicate a serial number with the operations involving + * later X windows. */ + if (n_x_windows > 1) + involves_x = TRUE; + } + + meta_stack_tracker_record_lower_below (tracker, lower, &windows[i], + involves_x ? serial++ : 0); + } } void -meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial) +meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_RAISE_ABOVE; op->any.serial = serial; - op->raise_above.window = window; - op->raise_above.sibling = sibling; + op->any.window = *window; + if (sibling) + op->raise_above.sibling = *sibling; + else + { + op->raise_above.sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + op->raise_above.sibling.x11.xwindow = None; + } - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial) +meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial) { MetaStackOp *op = g_slice_new (MetaStackOp); op->any.type = STACK_OP_LOWER_BELOW; op->any.serial = serial; - op->lower_below.window = window; - op->lower_below.sibling = sibling; + op->any.window = *window; + if (sibling) + op->lower_below.sibling = *sibling; + else + { + op->lower_below.sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + op->lower_below.sibling.x11.xwindow = None; + } - stack_tracker_queue_request (tracker, op); + stack_tracker_apply_prediction (tracker, op); } void -meta_stack_tracker_record_lower (MetaStackTracker *tracker, - Window window, - gulong serial) +meta_stack_tracker_record_lower (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial) { - meta_stack_tracker_record_raise_above (tracker, window, None, serial); + meta_stack_tracker_record_raise_above (tracker, window, NULL, serial); } -static void -stack_tracker_event_received (MetaStackTracker *tracker, - MetaStackOp *op) +/* @op is an operation derived from an X event from the server and we + * want to verify that our predicted operations are consistent with + * what's being reported by the X server. + * + * NB: Since our stack may actually be a mixture of X and Wayland + * clients we can't simply apply these operations derived from X + * events onto our stack and discard old predictions because these + * operations aren't aware of wayland windows. + * + * This function applies all the unverified predicted operations up to + * the given @serial onto the verified_stack so that we can check the + * stack for consistency with the given X operation. + * + * Return value: %TRUE if the predicted state is consistent with + * receiving the given @op from X, else %FALSE. + * + * @modified will be set to %TRUE if tracker->verified_stack is + * changed by applying any newly validated operations, else %FALSE. + */ +static gboolean +stack_tracker_verify_predictions (MetaStackTracker *tracker, + MetaStackOp *op, + gboolean *modified) { - gboolean need_sync = FALSE; + GArray *tmp_predicted_stack = NULL; + GArray *predicted_stack; + gboolean modified_stack = FALSE; - meta_stack_op_dump (op, "Stack op event received: ", "\n"); + /* Wayland operations don't need to be verified and shouldn't end up + * passed to this api. */ + g_return_val_if_fail (op->any.window.any.type == META_WINDOW_CLIENT_TYPE_X11, FALSE); - if (op->any.serial < tracker->server_serial) - return; - - tracker->server_serial = op->any.serial; - - if (meta_stack_op_apply (op, tracker->server_stack)) - need_sync = TRUE; - - while (tracker->queued_requests->head) + if (tracker->unverified_predictions->length) { - MetaStackOp *queued_op = tracker->queued_requests->head->data; + GList *l; + + tmp_predicted_stack = predicted_stack = copy_stack (tracker->verified_stack); + + for (l = tracker->unverified_predictions->head; l; l = l->next) + { + MetaStackOp *current_op = l->data; + + if (current_op->any.serial > op->any.serial) + break; + + modified_stack |= meta_stack_op_apply (current_op, predicted_stack); + } + } + else + predicted_stack = tracker->verified_stack; + + switch (op->any.type) + { + case STACK_OP_ADD: + if (!find_window (predicted_stack, &op->any.window)) + { + char *window_id = get_window_id (&op->any.window); + meta_topic (META_DEBUG_STACK, "Verify STACK_OP_ADD: window %s not found\n", + window_id); + g_free (window_id); + goto not_verified; + } + break; + case STACK_OP_REMOVE: + if (find_window (predicted_stack, &op->any.window)) + { + char *window_id = get_window_id (&op->any.window); + meta_topic (META_DEBUG_STACK, "Verify STACK_OP_REMOVE: window %s was unexpectedly found\n", + window_id); + g_free (window_id); + goto not_verified; + } + break; + case STACK_OP_RAISE_ABOVE: + { + Window last_xwindow = None; + char *window_id; + unsigned int i; + + /* This code is only intended for verifying operations based + * on XEvents where we can assume the sibling refers to + * another X window... */ + g_return_val_if_fail (op->raise_above.sibling.any.type == + META_WINDOW_CLIENT_TYPE_X11, FALSE); + + for (i = 0; i < predicted_stack->len; i++) + { + MetaStackWindow *window = &g_array_index (predicted_stack, MetaStackWindow, i); + + if (meta_stack_window_equal (window, &op->any.window)) + { + if (last_xwindow == op->raise_above.sibling.x11.xwindow) + goto verified; + else + goto not_verified; + } + + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + last_xwindow = window->x11.xwindow; + } + + window_id = get_window_id (&op->any.window); + meta_topic (META_DEBUG_STACK, "Verify STACK_OP_RAISE_ABOVE: window %s not found\n", + window_id); + g_free (window_id); + goto not_verified; + } + case STACK_OP_LOWER_BELOW: + g_warn_if_reached (); /* No X events currently lead to this path */ + goto not_verified; + } + +verified: + + /* We can free the operations which we have now verified... */ + while (tracker->unverified_predictions->head) + { + MetaStackOp *queued_op = tracker->unverified_predictions->head->data; + if (queued_op->any.serial > op->any.serial) break; - g_queue_pop_head (tracker->queued_requests); + g_queue_pop_head (tracker->unverified_predictions); meta_stack_op_free (queued_op); - need_sync = TRUE; } - if (need_sync) + *modified = modified_stack; + if (modified_stack) + { + g_array_free (tracker->verified_stack, TRUE); + tracker->verified_stack = predicted_stack; + } + else if (tmp_predicted_stack) + g_array_free (tmp_predicted_stack, TRUE); + + return TRUE; + +not_verified: + + if (tmp_predicted_stack) + g_array_free (tmp_predicted_stack, TRUE); + + if (tracker->predicted_stack) + { + g_array_free (tracker->predicted_stack, TRUE); + tracker->predicted_stack = NULL; + } + + *modified = FALSE; + + return FALSE; +} + +/* If we find that our predicted state is not consistent with what the + * X server is reporting to us then this function can re-query and + * re-synchronize verified_stack with the X server stack while + * hopefully not disrupting the relative stacking of Wayland windows. + * + * Return value: %TRUE if the verified stack was modified with respect + * to the predicted stack else %FALSE. + * + * Note: ->predicted_stack will be cleared by this function if + * ->verified_stack had to be modified when re-synchronizing. + */ +static gboolean +resync_verified_stack_with_xserver_stack (MetaStackTracker *tracker) +{ + GList *l; + unsigned int i, j; + MetaStackWindow *expected_xwindow; + gboolean modified_stack; + + /* Overview of the algorithm: + * + * - Re-query the complete X window stack from the X server via + * XQueryTree() and update xserver_stack. + * + * - Apply all operations in unverified_predictions to + * verified_stack so we have a predicted stack including Wayland + * windows and free the queue of unverified_predictions. + * + * - Iterate through the x windows listed in verified_stack at the + * same time as iterating the windows in xserver_list. (Stop + * when we reach the end of the xserver_list) + * - If the window found doesn't match the window expected + * according to the order of xserver_list then: + * - Look ahead for the window we were expecting and restack + * that above the previous X window. If we fail to find the + * expected window then create a new entry for it and stack + * that. + * + * - Continue to iterate through verified_stack for any remaining + * X windows that we now know aren't in the xserver_list and + * remove them. + * + * - Free ->predicted_stack if any. + */ + + meta_topic (META_DEBUG_STACK, "Fully re-synchronizing X stack with verified stack\n"); + + requery_xserver_stack (tracker); + + for (l = tracker->unverified_predictions->head; l; l = l->next) + meta_stack_op_apply (l->data, tracker->verified_stack); + g_queue_clear (tracker->unverified_predictions); + + j = 0; + expected_xwindow = + &g_array_index (tracker->xserver_stack, MetaStackWindow, j); + + for (i = 0; + i < tracker->verified_stack->len; + ) + { + MetaStackWindow *current = + &g_array_index (tracker->verified_stack, MetaStackWindow, i); + + if (current->any.type != META_WINDOW_CLIENT_TYPE_X11) + { + /* Progress i but not j */ + i++; + continue; + } + + if (current->x11.xwindow != expected_xwindow->x11.xwindow) + { + MetaStackWindow new; + MetaStackWindow *expected; + int expected_index; + + /* If the current window corresponds to a window that's not + * in xserver_stack any more then the least disruptive thing + * we can do is to simply remove it and take another look at + * the same index. + * + * Note: we didn't used to do this and instead relied on + * removed windows getting pushed to the end of the list so + * they could all be removed together but this also resulted + * in pushing Wayland windows to the end too, disrupting + * their positioning relative to X windows too much. + * + * Technically we only need to look forward from j if we + * wanted to optimize this a bit... + */ + if (find_window (tracker->xserver_stack, current) < 0) + { + g_array_remove_index (tracker->verified_stack, i); + continue; + } + + /* Technically we only need to look forward from i if we + * wanted to optimize this a bit... */ + expected_index = + find_window (tracker->verified_stack, expected_xwindow); + + if (expected_index >= 0) + { + expected = &g_array_index (tracker->verified_stack, + MetaStackWindow, expected_index); + } + else + { + new.any.type = META_WINDOW_CLIENT_TYPE_X11; + new.x11.xwindow = expected_xwindow->x11.xwindow; + + g_array_append_val (tracker->verified_stack, new); + + expected = &new; + expected_index = tracker->verified_stack->len - 1; + } + + /* Note: that this move will effectively bump the index of + * the current window. + * + * We want to continue by re-checking this window against + * the next expected window though so we don't have to + * update i to compensate here. + */ + move_window_above (tracker->verified_stack, expected, + expected_index, /* current index */ + i - 1); /* above */ + modified_stack = TRUE; + } + + /* NB: we want to make sure that if we break the loop because j + * reaches the end of xserver_stack that i has also been + * incremented already so that we can run a final loop to remove + * remaining windows based on the i index. */ + i++; + + j++; + expected_xwindow = + &g_array_index (tracker->xserver_stack, MetaStackWindow, j); + + if (j >= tracker->xserver_stack->len) + break; + } + + /* We now know that any remaining X windows aren't listed in the + * xserver_stack and so we can remove them. */ + while (i < tracker->verified_stack->len) + { + MetaStackWindow *current = + &g_array_index (tracker->verified_stack, MetaStackWindow, i); + + if (current->any.type == META_WINDOW_CLIENT_TYPE_X11) + g_array_remove_index (tracker->verified_stack, i); + else + i++; + + modified_stack = TRUE; + } + + /* If we get to the end of verified_list and there are any remaining + * entries in xserver_list then append them all to the end */ + for (; j < tracker->xserver_stack->len; j++) + { + MetaStackWindow *current = + &g_array_index (tracker->xserver_stack, MetaStackWindow, j); + g_array_append_val (tracker->verified_stack, *current); + + modified_stack = TRUE; + } + + if (modified_stack) { if (tracker->predicted_stack) { @@ -554,6 +1027,47 @@ stack_tracker_event_received (MetaStackTracker *tracker, meta_stack_tracker_queue_sync_stack (tracker); } + return modified_stack; +} + +static void +stack_tracker_event_received (MetaStackTracker *tracker, + MetaStackOp *op) +{ + gboolean need_sync = FALSE; + gboolean verified; + + meta_stack_op_dump (op, "Stack op event received: ", "\n"); + + if (op->any.serial < tracker->xserver_serial) + { + /* g_warning ("Spurious X event received affecting stack; doing full re-query"); */ + resync_verified_stack_with_xserver_stack (tracker); + meta_stack_tracker_dump (tracker); + return; + } + + tracker->xserver_serial = op->any.serial; + + /* XXX: With the design we have ended up with it looks like we've + * ended up making it unnecessary to maintain tracker->xserver_stack + * since we only need an xserver_stack during the + * resync_verified_stack_with_xserver_stack() at which point we are + * going to query the full stack from the X server using + * XQueryTree() anyway. + * + * TODO: remove tracker->xserver_stack. + */ + meta_stack_op_apply (op, tracker->xserver_stack); + + verified = stack_tracker_verify_predictions (tracker, op, &need_sync); + if (!verified) + { + resync_verified_stack_with_xserver_stack (tracker); + meta_stack_tracker_dump (tracker); + return; + } + meta_stack_tracker_dump (tracker); } @@ -565,7 +1079,8 @@ meta_stack_tracker_create_event (MetaStackTracker *tracker, op.any.type = STACK_OP_ADD; op.any.serial = event->serial; - op.add.window = event->window; + op.add.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.add.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -578,7 +1093,8 @@ meta_stack_tracker_destroy_event (MetaStackTracker *tracker, op.any.type = STACK_OP_REMOVE; op.any.serial = event->serial; - op.remove.window = event->window; + op.remove.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.remove.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -593,7 +1109,8 @@ meta_stack_tracker_reparent_event (MetaStackTracker *tracker, op.any.type = STACK_OP_ADD; op.any.serial = event->serial; - op.add.window = event->window; + op.add.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.add.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -603,7 +1120,8 @@ meta_stack_tracker_reparent_event (MetaStackTracker *tracker, op.any.type = STACK_OP_REMOVE; op.any.serial = event->serial; - op.remove.window = event->window; + op.remove.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.remove.window.x11.xwindow = event->window; stack_tracker_event_received (tracker, &op); } @@ -617,8 +1135,10 @@ meta_stack_tracker_configure_event (MetaStackTracker *tracker, op.any.type = STACK_OP_RAISE_ABOVE; op.any.serial = event->serial; - op.raise_above.window = event->window; - op.raise_above.sibling = event->above; + op.raise_above.window.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.raise_above.window.x11.xwindow = event->window; + op.raise_above.sibling.any.type = META_WINDOW_CLIENT_TYPE_X11; + op.raise_above.sibling.x11.xwindow = event->above; stack_tracker_event_received (tracker, &op); } @@ -642,14 +1162,14 @@ meta_stack_tracker_configure_event (MetaStackTracker *tracker, */ void meta_stack_tracker_get_stack (MetaStackTracker *tracker, - Window **windows, + MetaStackWindow **windows, int *n_windows) { GArray *stack; - if (tracker->queued_requests->length == 0) + if (tracker->unverified_predictions->length == 0) { - stack = tracker->server_stack; + stack = tracker->verified_stack; } else { @@ -657,9 +1177,8 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker, { GList *l; - tracker->predicted_stack = copy_stack ((Window *)tracker->server_stack->data, - tracker->server_stack->len); - for (l = tracker->queued_requests->head; l; l = l->next) + tracker->predicted_stack = copy_stack (tracker->verified_stack); + for (l = tracker->unverified_predictions->head; l; l = l->next) { MetaStackOp *op = l->data; meta_stack_op_apply (op, tracker->predicted_stack); @@ -669,8 +1188,11 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker, stack = tracker->predicted_stack; } + meta_topic (META_DEBUG_STACK, "Get Stack\n"); + meta_stack_tracker_dump (tracker); + if (windows) - *windows = (Window *)stack->data; + *windows = (MetaStackWindow *)stack->data; if (n_windows) *n_windows = stack->len; } @@ -685,8 +1207,8 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker, void meta_stack_tracker_sync_stack (MetaStackTracker *tracker) { + MetaStackWindow *windows; GList *meta_windows; - Window *windows; int n_windows; int i; @@ -701,26 +1223,30 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker) meta_windows = NULL; for (i = 0; i < n_windows; i++) { - MetaWindow *meta_window; + MetaStackWindow *window = &windows[i]; - meta_window = meta_display_lookup_x_window (tracker->screen->display, - windows[i]); - /* When mapping back from xwindow to MetaWindow we have to be a bit careful; - * children of the root could include unmapped windows created by toolkits - * for internal purposes, including ones that we have registered in our - * XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; - * see window-prop.c:reload_net_wm_user_time_window() for registration.) - */ - if (meta_window && - (windows[i] == meta_window->xwindow || - (meta_window->frame && windows[i] == meta_window->frame->xwindow))) - meta_windows = g_list_prepend (meta_windows, meta_window); + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + MetaWindow *meta_window = + meta_display_lookup_x_window (tracker->screen->display, windows[i].x11.xwindow); + + /* When mapping back from xwindow to MetaWindow we have to be a bit careful; + * children of the root could include unmapped windows created by toolkits + * for internal purposes, including ones that we have registered in our + * XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; + * see window-prop.c:reload_net_wm_user_time_window() for registration.) + */ + if (meta_window && + (windows[i].x11.xwindow == meta_window->xwindow || + (meta_window->frame && windows[i].x11.xwindow == meta_window->frame->xwindow))) + meta_windows = g_list_prepend (meta_windows, meta_window); + } + else + meta_windows = g_list_prepend (meta_windows, window->wayland.meta_window); } - if (tracker->screen->display->compositor) - meta_compositor_sync_stack (tracker->screen->display->compositor, - tracker->screen, - meta_windows); + meta_compositor_sync_stack (tracker->screen->display->compositor, + meta_windows); g_list_free (meta_windows); meta_screen_restacked (tracker->screen); diff --git a/src/core/stack-tracker.h b/src/core/stack-tracker.h index 36d5251d4..f74400efa 100644 --- a/src/core/stack-tracker.h +++ b/src/core/stack-tracker.h @@ -35,36 +35,55 @@ #define META_STACK_TRACKER_H #include +#include typedef struct _MetaStackTracker MetaStackTracker; +typedef union _MetaStackWindow +{ + struct { + MetaWindowClientType type; + } any; + struct { + MetaWindowClientType type; + Window xwindow; + } x11; + struct { + MetaWindowClientType type; + MetaWindow *meta_window; + } wayland; +} MetaStackWindow; + +gboolean meta_stack_window_equal (const MetaStackWindow *a, + const MetaStackWindow *b); + MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen); void meta_stack_tracker_free (MetaStackTracker *tracker); /* These functions are called when we make an X call that changes the * stacking order; this allows MetaStackTracker to predict stacking * order before it receives events back from the X server */ -void meta_stack_tracker_record_add (MetaStackTracker *tracker, - Window window, - gulong serial); -void meta_stack_tracker_record_remove (MetaStackTracker *tracker, - Window window, - gulong serial); -void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, - Window *windows, - int n_windows, - gulong serial); -void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial); -void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, - Window window, - Window sibling, - gulong serial); -void meta_stack_tracker_record_lower (MetaStackTracker *tracker, - Window window, - gulong serial); +void meta_stack_tracker_record_add (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial); +void meta_stack_tracker_record_remove (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial); +void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker, + const MetaStackWindow *windows, + int n_windows, + gulong serial); +void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial); +void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker, + const MetaStackWindow *window, + const MetaStackWindow *sibling, + gulong serial); +void meta_stack_tracker_record_lower (MetaStackTracker *tracker, + const MetaStackWindow *window, + gulong serial); /* These functions are used to update the stack when we get events * reflecting changes to the stacking order */ @@ -77,9 +96,9 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker, void meta_stack_tracker_configure_event (MetaStackTracker *tracker, XConfigureEvent *event); -void meta_stack_tracker_get_stack (MetaStackTracker *tracker, - Window **windows, - int *n_windows); +void meta_stack_tracker_get_stack (MetaStackTracker *tracker, + MetaStackWindow **windows, + int *n_entries); void meta_stack_tracker_sync_stack (MetaStackTracker *tracker); void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker); diff --git a/src/core/stack.c b/src/core/stack.c index 18f1d7e56..68400e2ba 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -36,6 +36,8 @@ #include +#include "x11/group-private.h" + #define WINDOW_HAS_TRANSIENT_TYPE(w) \ (w->type == META_WINDOW_DIALOG || \ w->type == META_WINDOW_MODAL_DIALOG || \ @@ -50,7 +52,7 @@ #define WINDOW_IN_STACK(w) (w->stack_position >= 0) -static void stack_sync_to_server (MetaStack *stack); +static void stack_sync_to_xserver (MetaStack *stack); static void meta_window_set_stack_position_no_sync (MetaWindow *window, int position); static void stack_do_window_deletions (MetaStack *stack); @@ -69,14 +71,14 @@ meta_stack_new (MetaScreen *screen) stack = g_new (MetaStack, 1); stack->screen = screen; - stack->windows = g_array_new (FALSE, FALSE, sizeof (Window)); + stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); stack->sorted = NULL; stack->added = NULL; stack->removed = NULL; stack->freeze_count = 0; - stack->last_root_children_stacked = NULL; + stack->last_all_root_children_stacked = NULL; stack->n_positions = 0; @@ -87,17 +89,24 @@ meta_stack_new (MetaScreen *screen) return stack; } +static void +free_last_all_root_children_stacked_cache (MetaStack *stack) +{ + g_array_free (stack->last_all_root_children_stacked, TRUE); + stack->last_all_root_children_stacked = NULL; +} + void meta_stack_free (MetaStack *stack) { - g_array_free (stack->windows, TRUE); + g_array_free (stack->xwindows, TRUE); g_list_free (stack->sorted); g_list_free (stack->added); g_list_free (stack->removed); - if (stack->last_root_children_stacked) - g_array_free (stack->last_root_children_stacked, TRUE); + if (stack->last_all_root_children_stacked) + free_last_all_root_children_stacked_cache (stack); g_free (stack); } @@ -119,7 +128,7 @@ meta_stack_add (MetaStack *stack, "Window %s has stack_position initialized to %d\n", window->desc, window->stack_position); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -155,7 +164,7 @@ meta_stack_remove (MetaStack *stack, stack->removed = g_list_prepend (stack->removed, GUINT_TO_POINTER (window->frame->xwindow)); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -165,7 +174,7 @@ meta_stack_update_layer (MetaStack *stack, { stack->need_relayer = TRUE; - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -175,7 +184,7 @@ meta_stack_update_transient (MetaStack *stack, { stack->need_constrain = TRUE; - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -204,7 +213,7 @@ meta_stack_raise (MetaStack *stack, meta_window_set_stack_position_no_sync (window, max_stack_position); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -232,7 +241,7 @@ meta_stack_lower (MetaStack *stack, meta_window_set_stack_position_no_sync (window, min_stack_position); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, window->screen->active_workspace); } @@ -248,7 +257,7 @@ meta_stack_thaw (MetaStack *stack) g_return_if_fail (stack->freeze_count > 0); stack->freeze_count -= 1; - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -827,7 +836,7 @@ stack_do_window_deletions (MetaStack *stack) /* We go from the end figuring removals are more * likely to be recent. */ - i = stack->windows->len; + i = stack->xwindows->len; while (i > 0) { --i; @@ -838,9 +847,9 @@ stack_do_window_deletions (MetaStack *stack) * both the window->xwindow and window->frame->xwindow * in the removal list. */ - if (xwindow == g_array_index (stack->windows, Window, i)) + if (xwindow == g_array_index (stack->xwindows, Window, i)) { - g_array_remove_index (stack->windows, i); + g_array_remove_index (stack->xwindows, i); goto next; } } @@ -869,10 +878,10 @@ stack_do_window_additions (MetaStack *stack) "Adding %d windows to sorted list\n", n_added); - old_size = stack->windows->len; - g_array_set_size (stack->windows, old_size + n_added); + old_size = stack->xwindows->len; + g_array_set_size (stack->xwindows, old_size + n_added); - end = &g_array_index (stack->windows, Window, old_size); + end = &g_array_index (stack->xwindows, Window, old_size); /* stack->added has the most recent additions at the * front of the list, so we need to reverse it @@ -1027,6 +1036,102 @@ stack_ensure_sorted (MetaStack *stack) stack_do_resort (stack); } +static MetaStackWindow * +find_top_most_managed_window (MetaScreen *screen, + const MetaStackWindow *ignore) +{ + MetaStackTracker *stack_tracker = screen->stack_tracker; + MetaStackWindow *windows; + int n_windows; + int i; + + meta_stack_tracker_get_stack (stack_tracker, + &windows, &n_windows); + + /* Children are in order from bottom to top. We want to + * find the topmost managed child, then configure + * our window to be above it. + */ + for (i = n_windows -1; i >= 0; i--) + { + MetaStackWindow *other_window = &windows[i]; + + if (other_window->any.type == ignore->any.type && + ((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 && + other_window->x11.xwindow == ignore->x11.xwindow) || + other_window->wayland.meta_window == ignore->wayland.meta_window)) + { + /* Do nothing. This means we're already the topmost managed + * window, but it DOES NOT mean we are already just above + * the topmost managed window. This is important because if + * an override redirect window is up, and we map a new + * managed window, the new window is probably above the old + * popup by default, and we want to push it below that + * popup. So keep looking for a sibling managed window + * to be moved below. + */ + } + else + { + if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + MetaWindow *other = meta_display_lookup_x_window (screen->display, + other_window->x11.xwindow); + + if (other != NULL && !other->override_redirect) + return other_window; + } + else + { + /* All wayland windows are currently considered "managed" + * TODO: consider wayland pop-up windows like override + * redirect windows here. */ + return other_window; + } + } + } + + return NULL; +} + +/* When moving an X window we sometimes need an X based sibling. + * + * If the given sibling is X based this function returns it back + * otherwise it searches downwards looking for the nearest X window. + * + * If no X based sibling could be found return NULL. */ +static MetaStackWindow * +find_x11_sibling_downwards (MetaScreen *screen, + MetaStackWindow *sibling) +{ + MetaStackTracker *stack_tracker = screen->stack_tracker; + MetaStackWindow *windows; + int n_windows; + int i; + + if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11) + return sibling; + + meta_stack_tracker_get_stack (stack_tracker, + &windows, &n_windows); + + /* NB: Children are in order from bottom to top and we + * want to search downwards for the nearest X window. + */ + + for (i = n_windows - 1; i >= 0; i--) + if (meta_stack_window_equal (&windows[i], sibling)) + break; + + for (; i >= 0; i--) + { + if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11) + return &windows[i]; + } + + return NULL; +} + /** * raise_window_relative_to_managed_windows: * @@ -1051,84 +1156,74 @@ stack_ensure_sorted (MetaStack *stack) */ static void raise_window_relative_to_managed_windows (MetaScreen *screen, - Window xwindow) + const MetaStackWindow *window) { + gulong serial = 0; + MetaStackWindow *sibling; - Window *children; - int n_children; - int i; - - meta_stack_tracker_get_stack (screen->stack_tracker, - &children, &n_children); - - /* Children are in order from bottom to top. We want to - * find the topmost managed child, then configure - * our window to be above it. - */ - i = n_children - 1; - while (i >= 0) + sibling = find_top_most_managed_window (screen, window); + if (!sibling) { - if (children[i] == xwindow) + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) { - /* Do nothing. This means we're already the topmost managed - * window, but it DOES NOT mean we are already just above - * the topmost managed window. This is important because if - * an override redirect window is up, and we map a new - * managed window, the new window is probably above the old - * popup by default, and we want to push it below that - * popup. So keep looking for a sibling managed window - * to be moved below. - */ + serial = XNextRequest (screen->display->xdisplay); + meta_error_trap_push (screen->display); + XLowerWindow (screen->display->xdisplay, + window->x11.xwindow); + meta_error_trap_pop (screen->display); } - else - { - MetaWindow *other = meta_display_lookup_x_window (screen->display, - children[i]); - if (other != NULL && !other->override_redirect) - { - XWindowChanges changes; - /* children[i] is the topmost managed child */ + /* No sibling to use, just lower ourselves to the bottom + * to be sure we're below any override redirect windows. + */ + meta_stack_tracker_record_lower (screen->stack_tracker, + window, + serial); + return; + } + + /* window is the topmost managed child */ meta_topic (META_DEBUG_STACK, "Moving 0x%lx above topmost managed child window 0x%lx\n", - xwindow, children[i]); + window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0, + sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0); - changes.sibling = children[i]; + if (window->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + XWindowChanges changes; + MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling); + serial = XNextRequest (screen->display->xdisplay); + + if (x11_sibling) + { + changes.sibling = x11_sibling->x11.xwindow; changes.stack_mode = Above; meta_error_trap_push (screen->display); - meta_stack_tracker_record_raise_above (screen->stack_tracker, - xwindow, - children[i], - XNextRequest (screen->display->xdisplay)); XConfigureWindow (screen->display->xdisplay, - xwindow, + window->x11.xwindow, CWSibling | CWStackMode, &changes); meta_error_trap_pop (screen->display); - - break; - } } - - --i; - } - - if (i < 0) + else { /* No sibling to use, just lower ourselves to the bottom * to be sure we're below any override redirect windows. */ meta_error_trap_push (screen->display); - meta_stack_tracker_record_lower (screen->stack_tracker, - xwindow, - XNextRequest (screen->display->xdisplay)); XLowerWindow (screen->display->xdisplay, - xwindow); + window->x11.xwindow); meta_error_trap_pop (screen->display); } } + meta_stack_tracker_record_raise_above (screen->stack_tracker, + window, + sibling, + serial); +} + /** * stack_sync_to_server: * @@ -1143,13 +1238,16 @@ raise_window_relative_to_managed_windows (MetaScreen *screen, * job of computing the minimal set of stacking requests needed. */ static void -stack_sync_to_server (MetaStack *stack) +stack_sync_to_xserver (MetaStack *stack) { - GArray *stacked; - GArray *root_children_stacked; + GArray *x11_stacked; + GArray *x11_root_children_stacked; + GArray *all_root_children_stacked; /* wayland OR x11 */ GList *tmp; - GArray *all_hidden; + GArray *x11_hidden; + GArray *x11_hidden_stack_windows; int n_override_redirect = 0; + MetaStackWindow guard_stack_window; /* Bail out if frozen */ if (stack->freeze_count > 0) @@ -1164,13 +1262,17 @@ stack_sync_to_server (MetaStack *stack) * _NET hints, and "root_children_stacked" is in top-to-bottom * order for XRestackWindows() */ - stacked = g_array_new (FALSE, FALSE, sizeof (Window)); - root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); - all_hidden = g_array_new (FALSE, FALSE, sizeof (Window)); + x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); + + all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow)); + x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); + + x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow)); + x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window)); /* The screen guard window sits above all hidden windows and acts as * a barrier to input reaching these windows. */ - g_array_append_val (all_hidden, stack->screen->guard_window); + g_array_append_val (x11_hidden, stack->screen->guard_window); meta_topic (META_DEBUG_STACK, "Top to bottom: "); meta_push_no_msg_prefix (); @@ -1179,6 +1281,9 @@ stack_sync_to_server (MetaStack *stack) { MetaWindow *w = tmp->data; Window top_level_window; + MetaStackWindow stack_window; + + stack_window.any.type = w->client_type; meta_topic (META_DEBUG_STACK, "%u:%d - %s ", w->layer, w->stack_position, w->desc); @@ -1187,60 +1292,82 @@ stack_sync_to_server (MetaStack *stack) if (w->override_redirect) n_override_redirect++; else - g_array_prepend_val (stacked, w->xwindow); + g_array_prepend_val (x11_stacked, w->xwindow); if (w->frame) top_level_window = w->frame->xwindow; else top_level_window = w->xwindow; + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + stack_window.x11.xwindow = top_level_window; + else + stack_window.wayland.meta_window = w; + /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below * the screens fullscreen guard_window. */ if (w->hidden) { - g_array_append_val (all_hidden, top_level_window); + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + { + MetaStackWindow stack_window; + + stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + stack_window.x11.xwindow = top_level_window; + + g_array_append_val (x11_hidden_stack_windows, stack_window); + g_array_append_val (x11_hidden, top_level_window); + } continue; } + g_array_append_val (all_root_children_stacked, stack_window); + /* build XRestackWindows() array from top to bottom */ - g_array_append_val (root_children_stacked, top_level_window); + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + g_array_append_val (x11_root_children_stacked, top_level_window); } meta_topic (META_DEBUG_STACK, "\n"); meta_pop_no_msg_prefix (); - /* All windows should be in some stacking order */ - if (stacked->len != stack->windows->len - n_override_redirect) + /* All X windows should be in some stacking order */ + if (x11_stacked->len != stack->xwindows->len - n_override_redirect) meta_bug ("%u windows stacked, %u windows exist in stack\n", - stacked->len, stack->windows->len); + x11_stacked->len, stack->xwindows->len); /* Sync to server */ meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", - root_children_stacked->len); + all_root_children_stacked->len); meta_error_trap_push (stack->screen->display); - if (stack->last_root_children_stacked == NULL) + if (stack->last_all_root_children_stacked == NULL) { /* Just impose our stack, we don't know the previous state. * This involves a ton of circulate requests and may flicker. */ meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n"); - if (root_children_stacked->len > 0) + if (all_root_children_stacked->len > 1) { - meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, - (Window *) root_children_stacked->data, - root_children_stacked->len, - XNextRequest (stack->screen->display->xdisplay)); + gulong serial = 0; + if (x11_root_children_stacked->len > 1) + { + serial = XNextRequest (stack->screen->display->xdisplay); XRestackWindows (stack->screen->display->xdisplay, - (Window *) root_children_stacked->data, - root_children_stacked->len); + (Window *) x11_root_children_stacked->data, + x11_root_children_stacked->len); + } + meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, + (MetaStackWindow *) all_root_children_stacked->data, + all_root_children_stacked->len, + serial); } } - else if (root_children_stacked->len > 0) + else if (all_root_children_stacked->len > 0) { /* Try to do minimal window moves to get the stack in order */ /* A point of note: these arrays include frames not client windows, @@ -1248,28 +1375,34 @@ stack_sync_to_server (MetaStack *stack) * was saved, then we may have inefficiency, but I don't think things * break... */ - const Window *old_stack = (Window *) stack->last_root_children_stacked->data; - const Window *new_stack = (Window *) root_children_stacked->data; - const int old_len = stack->last_root_children_stacked->len; - const int new_len = root_children_stacked->len; - const Window *oldp = old_stack; - const Window *newp = new_stack; - const Window *old_end = old_stack + old_len; - const Window *new_end = new_stack + new_len; - Window last_window = None; - + const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data; + const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data; + const int old_len = stack->last_all_root_children_stacked->len; + const int new_len = all_root_children_stacked->len; + const MetaStackWindow *oldp = old_stack; + const MetaStackWindow *newp = new_stack; + const MetaStackWindow *old_end = old_stack + old_len; + const MetaStackWindow *new_end = new_stack + new_len; + Window last_xwindow = None; + const MetaStackWindow *last_window = NULL; + while (oldp != old_end && newp != new_end) { - if (*oldp == *newp) + if (meta_stack_window_equal (oldp, newp)) { /* Stacks are the same here, move on */ ++oldp; - last_window = *newp; + if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11) + last_xwindow = newp->x11.xwindow; + last_window = newp; ++newp; } - else if (meta_display_lookup_x_window (stack->screen->display, - *oldp) == NULL) + else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 && + meta_display_lookup_x_window (stack->screen->display, + oldp->x11.xwindow) == NULL) || + (oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND && + oldp->wayland.meta_window == NULL)) { /* *oldp is no longer known to us (probably destroyed), * so we can just skip it @@ -1278,75 +1411,161 @@ stack_sync_to_server (MetaStack *stack) } else { - /* Move *newp below last_window */ - if (last_window == None) + /* Move *newp below the last_window */ + if (!last_window) { - meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp); + meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", + newp->x11.xwindow); - raise_window_relative_to_managed_windows (stack->screen, - *newp); + raise_window_relative_to_managed_windows (stack->screen, newp); + } + else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 && + last_xwindow == None) + { + /* In this case we have an X window that we need to + * put below a wayland window and this is the + * topmost X window. */ + + /* In X terms (because this is the topmost X window) + * we want to + * raise_window_relative_to_managed_windows() to + * ensure the X window is below override-redirect + * pop-up windows. + * + * In Wayland terms we just want to ensure + * newp is lowered below last_window (which + * notably doesn't require an X request because we + * know last_window isn't an X window). + */ + + raise_window_relative_to_managed_windows (stack->screen, newp); + + meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, + newp, last_window, + 0); /* no x request serial */ } else { - /* This means that if last_window is dead, but not + gulong serial = 0; + + /* This means that if last_xwindow is dead, but not * *newp, then we fail to restack *newp; but on - * unmanaging last_window, we'll fix it up. + * unmanaging last_xwindow, we'll fix it up. */ - XWindowChanges changes; + meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n", + newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0, + last_xwindow); - changes.sibling = last_window; + if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + XWindowChanges changes; + serial = XNextRequest (stack->screen->display->xdisplay); + + changes.sibling = last_xwindow; changes.stack_mode = Below; - meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n", - *newp, last_window); - - meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, - *newp, last_window, - XNextRequest (stack->screen->display->xdisplay)); XConfigureWindow (stack->screen->display->xdisplay, - *newp, + newp->x11.xwindow, CWSibling | CWStackMode, &changes); } - last_window = *newp; + meta_stack_tracker_record_lower_below (stack->screen->stack_tracker, + newp, last_window, + serial); + } + + if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11) + last_xwindow = newp->x11.xwindow; + last_window = newp; ++newp; } } if (newp != new_end) { + const MetaStackWindow *x_ref; + unsigned long serial = 0; + /* Restack remaining windows */ meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n", (int) (new_end - newp)); + + /* rewind until we find the last stacked X window that we can use + * as a reference point for re-stacking remaining X windows */ + if (newp != new_stack) + for (x_ref = newp - 1; + x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack; + x_ref--) + ; + else + x_ref = new_stack; + + /* If we didn't find an X window looking backwards then walk forwards + * through the remaining windows to find the first remaining X window + * instead. */ + if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11) + { + for (x_ref = newp; + x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack; + x_ref++) + ; + } + + /* If there are any X windows remaining unstacked then restack them */ + if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11) + { + int i; + + for (i = x11_root_children_stacked->len - 1; i; i--) + { + Window *reference = &g_array_index (x11_root_children_stacked, Window, i); + + if (*reference == x_ref->x11.xwindow) + { + int n = x11_root_children_stacked->len - i; + + /* There's no point restacking if there's only one X window */ + if (n == 1) + break; + + serial = XNextRequest (stack->screen->display->xdisplay); + XRestackWindows (stack->screen->display->xdisplay, + reference, n); + break; + } + } + } + /* We need to include an already-stacked window * in the restack call, so we get in the proper position * with respect to it. */ if (newp != new_stack) - --newp; + newp = MIN (newp - 1, x_ref); meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, - (Window *) newp, new_end - newp, - XNextRequest (stack->screen->display->xdisplay)); - XRestackWindows (stack->screen->display->xdisplay, - (Window *) newp, new_end - newp); + newp, new_end - newp, + serial); } } - /* Push hidden windows to the bottom of the stack under the guard window */ + /* Push hidden X windows to the bottom of the stack under the guard window */ + guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11; + guard_stack_window.x11.xwindow = stack->screen->guard_window; meta_stack_tracker_record_lower (stack->screen->stack_tracker, - stack->screen->guard_window, + &guard_stack_window, XNextRequest (stack->screen->display->xdisplay)); XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window); meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker, - (Window *)all_hidden->data, - all_hidden->len, + (MetaStackWindow *)x11_hidden_stack_windows->data, + x11_hidden_stack_windows->len, XNextRequest (stack->screen->display->xdisplay)); XRestackWindows (stack->screen->display->xdisplay, - (Window *)all_hidden->data, - all_hidden->len); - g_array_free (all_hidden, TRUE); + (Window *)x11_hidden->data, + x11_hidden->len); + g_array_free (x11_hidden, TRUE); + g_array_free (x11_hidden_stack_windows, TRUE); meta_error_trap_pop (stack->screen->display); /* on error, a window was destroyed; it should eventually @@ -1361,21 +1580,23 @@ stack_sync_to_server (MetaStack *stack) stack->screen->display->atom__NET_CLIENT_LIST, XA_WINDOW, 32, PropModeReplace, - (unsigned char *)stack->windows->data, - stack->windows->len); + (unsigned char *)stack->xwindows->data, + stack->xwindows->len); XChangeProperty (stack->screen->display->xdisplay, stack->screen->xroot, stack->screen->display->atom__NET_CLIENT_LIST_STACKING, XA_WINDOW, 32, PropModeReplace, - (unsigned char *)stacked->data, - stacked->len); + (unsigned char *)x11_stacked->data, + x11_stacked->len); - g_array_free (stacked, TRUE); + g_array_free (x11_stacked, TRUE); - if (stack->last_root_children_stacked) - g_array_free (stack->last_root_children_stacked, TRUE); - stack->last_root_children_stacked = root_children_stacked; + if (stack->last_all_root_children_stacked) + free_last_all_root_children_stacked_cache (stack); + stack->last_all_root_children_stacked = all_root_children_stacked; + + g_array_free (x11_root_children_stacked, TRUE); /* That was scary... */ } @@ -1486,8 +1707,8 @@ get_default_focus_window (MetaStack *stack, MetaWindow *topmost_in_group; MetaWindow *topmost_overall; MetaGroup *not_this_one_group; - GList *link; - + GList *l; + transient_parent = NULL; topmost_in_group = NULL; topmost_overall = NULL; @@ -1499,49 +1720,49 @@ get_default_focus_window (MetaStack *stack, stack_ensure_sorted (stack); /* top of this layer is at the front of the list */ - link = stack->sorted; - - while (link) + for (l = stack->sorted; l != NULL; l = l->next) { - MetaWindow *window = link->data; + MetaWindow *window = l->data; - if (window && - window != not_this_one && - (window->unmaps_pending == 0) && - !window->minimized && - (window->input || window->take_focus) && - (workspace == NULL || - meta_window_located_on_workspace (window, workspace))) + if (!window) + continue; + + if (window == not_this_one) + continue; + + if (window->unmaps_pending > 0) + continue; + + if (window->minimized) + continue; + + if (!(window->input || window->take_focus)) + continue; + + if (workspace != NULL && !meta_window_located_on_workspace (window, workspace)) + continue; + + if (must_be_at_point && !window_contains_point (window, root_x, root_y)) + continue; + + if (not_this_one != NULL) { - if (not_this_one != NULL) - { - if (transient_parent == NULL && - not_this_one->xtransient_for != None && - not_this_one->xtransient_for == window->xwindow && - (!must_be_at_point || - window_contains_point (window, root_x, root_y))) - transient_parent = window; + if (transient_parent == NULL && + meta_window_get_transient_for (not_this_one) == window) + transient_parent = window; - if (topmost_in_group == NULL && - not_this_one_group != NULL && - not_this_one_group == meta_window_get_group (window) && - (!must_be_at_point || - window_contains_point (window, root_x, root_y))) - topmost_in_group = window; - } - - if (topmost_overall == NULL && - window->type != META_WINDOW_DOCK && - (!must_be_at_point || - window_contains_point (window, root_x, root_y))) - topmost_overall = window; - - /* We could try to bail out early here for efficiency in - * some cases, but it's just not worth the code. - */ + if (topmost_in_group == NULL && + not_this_one_group != NULL && + not_this_one_group == meta_window_get_group (window)) + topmost_in_group = window; } - link = link->next; + if (topmost_overall == NULL && window->type != META_WINDOW_DOCK) + topmost_overall = window; + + /* We could try to bail out early here for efficiency in + * some cases, but it's just not worth the code. + */ } if (transient_parent) @@ -1726,7 +1947,7 @@ meta_stack_set_positions (MetaStack *stack, meta_topic (META_DEBUG_STACK, "Reset the stack positions of (nearly) all windows\n"); - stack_sync_to_server (stack); + stack_sync_to_xserver (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -1789,7 +2010,7 @@ meta_window_set_stack_position (MetaWindow *window, int position) { meta_window_set_stack_position_no_sync (window, position); - stack_sync_to_server (window->screen->stack); + stack_sync_to_xserver (window->screen->stack); meta_stack_update_window_tile_matches (window->screen->stack, window->screen->active_workspace); } diff --git a/src/core/stack.h b/src/core/stack.h index b0cd1bab5..f9555a981 100644 --- a/src/core/stack.h +++ b/src/core/stack.h @@ -58,7 +58,7 @@ struct _MetaStack * A sequence of all the Windows (X handles, not MetaWindows) of the windows * we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST. */ - GArray *windows; + GArray *xwindows; /** The MetaWindows of the windows we manage, sorted in order. */ GList *sorted; @@ -97,7 +97,7 @@ struct _MetaStack * The last-known stack of all windows, bottom to top. We cache it here * so that subsequent times we'll be able to do incremental moves. */ - GArray *last_root_children_stacked; + GArray *last_all_root_children_stacked; /** * Number of stack positions; same as the length of added, but diff --git a/src/core/util-private.h b/src/core/util-private.h index 8e51b42f4..6f25806cf 100644 --- a/src/core/util-private.h +++ b/src/core/util-private.h @@ -32,5 +32,6 @@ void meta_set_verbose (gboolean setting); void meta_set_debugging (gboolean setting); void meta_set_syncing (gboolean setting); void meta_set_replace_current_wm (gboolean setting); +void meta_set_is_wayland_compositor (gboolean setting); #endif diff --git a/src/core/util.c b/src/core/util.c index cde58ee53..3ac907fd4 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -53,6 +53,7 @@ static gint verbose_topics = 0; static gboolean is_debugging = FALSE; static gboolean replace_current = FALSE; static int no_prefix = 0; +static gboolean is_wayland_compositor = FALSE; #ifdef WITH_VERBOSE_MODE static FILE* logfile = NULL; @@ -79,7 +80,7 @@ ensure_logfile (void) if (err != NULL) { - meta_warning (_("Failed to open debug log: %s\n"), + meta_warning ("Failed to open debug log: %s\n", err->message); g_error_free (err); return; @@ -89,13 +90,13 @@ ensure_logfile (void) if (logfile == NULL) { - meta_warning (_("Failed to fdopen() log file %s: %s\n"), + meta_warning ("Failed to fdopen() log file %s: %s\n", filename, strerror (errno)); close (fd); } else { - g_printerr (_("Opened log file %s\n"), filename); + g_printerr ("Opened log file %s\n", filename); } g_free (filename); @@ -192,6 +193,18 @@ meta_set_replace_current_wm (gboolean setting) replace_current = setting; } +gboolean +meta_is_wayland_compositor (void) +{ + return is_wayland_compositor; +} + +void +meta_set_is_wayland_compositor (gboolean value) +{ + is_wayland_compositor = value; +} + char * meta_g_utf8_strndup (const gchar *src, gsize n) @@ -259,7 +272,7 @@ meta_debug_spew_real (const char *format, ...) out = logfile ? logfile : stderr; if (no_prefix == 0) - utf8_fputs (_("Window manager: "), out); + utf8_fputs ("Window manager: ", out); utf8_fputs (str, out); fflush (out); @@ -409,7 +422,7 @@ meta_bug (const char *format, ...) #endif if (no_prefix == 0) - utf8_fputs (_("Bug in window manager: "), out); + utf8_fputs ("Bug in window manager: ", out); utf8_fputs (str, out); fflush (out); @@ -440,7 +453,7 @@ meta_warning (const char *format, ...) #endif if (no_prefix == 0) - utf8_fputs (_("Window manager warning: "), out); + utf8_fputs ("Window manager warning: ", out); utf8_fputs (str, out); fflush (out); @@ -468,7 +481,7 @@ meta_fatal (const char *format, ...) #endif if (no_prefix == 0) - utf8_fputs (_("Window manager error: "), out); + utf8_fputs ("Window manager error: ", out); utf8_fputs (str, out); fflush (out); diff --git a/src/core/window-private.h b/src/core/window-private.h index fbeacabad..374bca7d7 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -38,10 +38,15 @@ #include "screen-private.h" #include #include "stack.h" -#include "iconcache.h" #include #include #include +#include + +#include "x11/iconcache.h" +#include "x11/group-private.h" + +#include "wayland/meta-wayland-types.h" typedef struct _MetaWindowQueue MetaWindowQueue; @@ -60,13 +65,29 @@ typedef enum { #define NUMBER_OF_QUEUES 3 - typedef enum { _NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0, _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1, _NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2, } MetaBypassCompositorHintValue; +typedef enum +{ + META_IS_CONFIGURE_REQUEST = 1 << 0, + META_DO_GRAVITY_ADJUST = 1 << 1, + META_IS_USER_ACTION = 1 << 2, + META_IS_MOVE_ACTION = 1 << 3, + META_IS_RESIZE_ACTION = 1 << 4, + META_IS_WAYLAND_RESIZE = 1 << 5 +} MetaMoveResizeFlags; + +typedef enum +{ + META_MOVE_RESIZE_RESULT_MOVED = 1 << 0, + META_MOVE_RESIZE_RESULT_RESIZED = 1 << 1, + META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2, +} MetaMoveResizeResultFlags; + struct _MetaWindow { GObject parent_instance; @@ -75,25 +96,24 @@ struct _MetaWindow MetaScreen *screen; const MetaMonitorInfo *monitor; MetaWorkspace *workspace; + MetaWindowClientType client_type; + MetaWaylandSurface *surface; Window xwindow; /* may be NULL! not all windows get decorated */ MetaFrame *frame; int depth; Visual *xvisual; - Colormap colormap; char *desc; /* used in debug spew */ char *title; - char *icon_name; GdkPixbuf *icon; GdkPixbuf *mini_icon; MetaIconCache icon_cache; Pixmap wm_hints_pixmap; Pixmap wm_hints_mask; - + MetaWindowType type; - Atom type_atom; - + /* NOTE these five are not in UTF-8, we just treat them as random * binary data */ @@ -119,6 +139,7 @@ struct _MetaWindow Window xtransient_for; Window xgroup_leader; Window xclient_leader; + MetaWindow *transient_for; /* Initial workspace property */ int initial_workspace; @@ -153,8 +174,8 @@ struct _MetaWindow /* Whether we're fullscreen */ guint fullscreen : 1; - /* Whether the urgent flag of WM_HINTS is set */ - guint wm_hints_urgent : 1; + /* Whether the window is marked as urgent */ + guint urgent : 1; /* Whether we have to fullscreen after placement */ guint fullscreen_after_placement : 1; @@ -199,10 +220,18 @@ struct _MetaWindow */ guint hidden : 1; - /* Whether the compositor thinks the window is visible + /* Whether the compositor thinks the window is visible. + * This should match up with calls to meta_compositor_show_window / + * meta_compositor_hide_window. */ guint visible_to_compositor : 1; + /* Whether the compositor knows about the window. + * This should match up with calls to meta_compositor_add_window / + * meta_compositor_remove_window. + */ + guint known_to_compositor : 1; + /* When we next show or hide the window, what effect we should * tell the compositor to perform. */ @@ -232,7 +261,7 @@ struct _MetaWindow /* These are the flags from WM_PROTOCOLS */ guint take_focus : 1; guint delete_window : 1; - guint net_wm_ping : 1; + guint can_ping : 1; /* Globally active / No input */ guint input : 1; @@ -256,13 +285,6 @@ struct _MetaWindow guint has_move_func : 1; guint has_resize_func : 1; guint has_fullscreen_func : 1; - - /* Weird "_NET_WM_STATE_MODAL" flag */ - guint wm_state_modal : 1; - - /* TRUE if the client forced these on */ - guint wm_state_skip_taskbar : 1; - guint wm_state_skip_pager : 1; /* Computed whether to skip taskbar or not */ guint skip_taskbar : 1; @@ -316,15 +338,6 @@ struct _MetaWindow /* Transient parent is a root window */ guint transient_parent_is_root_window : 1; - - /* Info on which props we got our attributes from */ - guint using_net_wm_name : 1; /* vs. plain wm_name */ - guint using_net_wm_visible_name : 1; /* tracked so we can clear it */ - guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */ - guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */ - - /* icon props have changed */ - guint need_reread_icon : 1; /* if TRUE, window was maximized at start of current grab op */ guint shaken_loose : 1; @@ -341,6 +354,10 @@ struct _MetaWindow /* whether or not the window is from a program running on another machine */ guint is_remote : 1; + /* Used for Wayland -- surfaces can behave as if they were unmapped if + * they have a NULL buffer attached... */ + guint surface_mapped; + /* if non-NULL, the bounds of the window frame */ cairo_region_t *frame_bounds; @@ -398,6 +415,12 @@ struct _MetaWindow */ MetaRectangle rect; + /* The size and position we want the window to be (i.e. what we last asked + * the client to configure). + * This is only used for wayland clients. + */ + MetaRectangle expected_rect; + gboolean has_custom_frame_extents; GtkBorder custom_frame_extents; @@ -415,8 +438,6 @@ struct _MetaWindow * gives the position and size of the client window (i.e. ignoring * the frame). * - * Position valid if user_has_moved, size valid if user_has_resized - * * Position always in root coords, unlike window->rect. */ MetaRectangle user_rect; @@ -455,10 +476,24 @@ struct _MetaWindowClass { GObjectClass parent_class; - void (*workspace_changed) (MetaWindow *window, int old_workspace); - void (*focus) (MetaWindow *window); - void (*raised) (MetaWindow *window); - void (*unmanaged) (MetaWindow *window); + void (*manage) (MetaWindow *window); + void (*unmanage) (MetaWindow *window); + void (*ping) (MetaWindow *window, + guint32 serial); + void (*delete) (MetaWindow *window, + guint32 timestamp); + void (*kill) (MetaWindow *window); + void (*focus) (MetaWindow *window, + guint32 timestamp); + void (*move_resize_internal) (MetaWindow *window, + int gravity, + MetaRectangle requested_rect, + MetaRectangle constrained_rect, + MetaMoveResizeFlags flags, + MetaMoveResizeResultFlags *result); + void (*get_default_skip_hints) (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out); }; /* These differ from window->has_foo_func in that they consider @@ -486,10 +521,22 @@ struct _MetaWindowClass #define META_WINDOW_ALLOWS_HORIZONTAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_width < (w)->size_hints.max_width) #define META_WINDOW_ALLOWS_VERTICAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_height < (w)->size_hints.max_height) -MetaWindow* meta_window_new (MetaDisplay *display, - Window xwindow, - gboolean must_be_viewable, - MetaCompEffect effect); +MetaWindow * _meta_window_shared_new (MetaDisplay *display, + MetaScreen *screen, + MetaWindowClientType client_type, + MetaWaylandSurface *surface, + Window xwindow, + gulong existing_wm_state, + MetaCompEffect effect, + XWindowAttributes *attrs); + +MetaWindow * meta_window_x11_new (MetaDisplay *display, + Window xwindow, + gboolean must_be_viewable, + MetaCompEffect effect); +MetaWindow * meta_window_wayland_new (MetaDisplay *display, + MetaWaylandSurface *surface); + void meta_window_unmanage (MetaWindow *window, guint32 timestamp); void meta_window_calc_showing (MetaWindow *window); @@ -539,9 +586,6 @@ void meta_window_change_workspace (MetaWindow *window, /* Return whether the window should be currently mapped */ gboolean meta_window_should_be_showing (MetaWindow *window); -/* See warning in window.c about this function */ -gboolean __window_is_terminal (MetaWindow *window); - void meta_window_update_struts (MetaWindow *window); /* this gets root coords */ @@ -575,12 +619,6 @@ void meta_window_get_geometry (MetaWindow *window, void meta_window_update_unfocused_button_grabs (MetaWindow *window); -/* Sends a client message */ -void meta_window_send_icccm_message (MetaWindow *window, - Atom atom, - guint32 timestamp); - - void meta_window_move_resize_request(MetaWindow *window, guint value_mask, int gravity, @@ -588,12 +626,11 @@ void meta_window_move_resize_request(MetaWindow *window, int y, int width, int height); -gboolean meta_window_configure_request (MetaWindow *window, - XEvent *event); -gboolean meta_window_property_notify (MetaWindow *window, - XEvent *event); -gboolean meta_window_client_message (MetaWindow *window, - XEvent *event); +void meta_window_move_resize_wayland (MetaWindow *window, + int width, + int height, + int dx, + int dy); void meta_window_set_focused_internal (MetaWindow *window, gboolean focused); @@ -607,16 +644,15 @@ void meta_window_show_menu (MetaWindow *window, int button, guint32 timestamp); -void meta_window_set_gravity (MetaWindow *window, - int gravity); - #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, gint64 new_counter_value); #endif /* HAVE_XSYNC */ -void meta_window_handle_mouse_grab_op_event (MetaWindow *window, - XIDeviceEvent *xev); +void meta_window_handle_mouse_grab_op_event (MetaWindow *window, + const ClutterEvent *event); +void meta_window_handle_mouse_grab_op_xevent (MetaWindow *window, + XIDeviceEvent *xevent); GList* meta_window_get_workspaces (MetaWindow *window); @@ -652,7 +688,8 @@ void meta_window_update_layer (MetaWindow *window); void meta_window_recalc_features (MetaWindow *window); -void meta_window_recalc_window_type (MetaWindow *window); +void meta_window_set_type (MetaWindow *window, + MetaWindowType type); void meta_window_frame_size_changed (MetaWindow *window); @@ -664,8 +701,6 @@ void meta_window_set_user_time (MetaWindow *window, void meta_window_update_icon_now (MetaWindow *window); -void meta_window_update_role (MetaWindow *window); -void meta_window_update_net_wm_type (MetaWindow *window); void meta_window_update_for_monitors_changed (MetaWindow *window); void meta_window_update_on_all_workspaces (MetaWindow *window); @@ -679,18 +714,56 @@ void meta_window_compute_tile_match (MetaWindow *window); gboolean meta_window_updates_are_frozen (MetaWindow *window); -void meta_window_update_opaque_region_x11 (MetaWindow *window); -void meta_window_update_input_region_x11 (MetaWindow *window); -void meta_window_update_shape_region_x11 (MetaWindow *window); +void meta_window_set_title (MetaWindow *window, + const char *title); +void meta_window_set_wm_class (MetaWindow *window, + const char *wm_class, + const char *wm_instance); +void meta_window_set_gtk_dbus_properties (MetaWindow *window, + const char *application_id, + const char *unique_bus_name, + const char *appmenu_path, + const char *menubar_path, + const char *application_object_path, + const char *window_object_path); + +void meta_window_set_transient_for (MetaWindow *window, + MetaWindow *parent); void meta_window_set_opacity (MetaWindow *window, guint opacity); +void meta_window_set_custom_frame_extents (MetaWindow *window, + GtkBorder *extents); + +void meta_window_handle_enter (MetaWindow *window, + guint32 timestamp, + guint root_x, + guint root_y); + +void meta_window_set_surface_mapped (MetaWindow *window, + gboolean surface_mapped); + Window meta_window_get_toplevel_xwindow (MetaWindow *window); void meta_window_get_client_area_rect (const MetaWindow *window, cairo_rectangle_int_t *rect); +void meta_window_activate_full (MetaWindow *window, + guint32 timestamp, + MetaClientType source_indication, + MetaWorkspace *workspace); + gboolean meta_window_is_client_decorated (MetaWindow *window); +void meta_window_update_monitor (MetaWindow *window); + +void meta_window_set_urgent (MetaWindow *window, + gboolean urgent); + +void meta_window_update_resize (MetaWindow *window, + gboolean snap, + int x, int y, + gboolean force); + #endif diff --git a/src/core/window.c b/src/core/window.c index 8fca023db..5729d5778 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -38,18 +38,14 @@ #include "keybindings-private.h" #include "ui.h" #include "place.h" -#include "session.h" #include -#include "resizepopup.h" -#include "xprops.h" #include -#include "window-props.h" +#include "resizepopup.h" #include "constraints.h" #include "mutter-enum-types.h" #include "core.h" #include -#include /* For display->resource_mask */ #include #include #include @@ -58,7 +54,15 @@ #include #endif -#include +#include "meta/compositor-mutter.h" + +#include "x11/window-x11.h" +#include "x11/window-props.h" +#include "x11/xprops.h" +#include "x11/session.h" + +#include "wayland/window-wayland.h" +#include "wayland/meta-wayland-private.h" /* Windows that unmaximize to a size bigger than that fraction of the workarea * will be scaled down to that size (while maintaining aspect ratio). @@ -69,31 +73,17 @@ static int destroying_windows_disallowed = 0; -static void update_sm_hints (MetaWindow *window); -static void update_net_frame_extents (MetaWindow *window); -static void recalc_window_type (MetaWindow *window); -static void recalc_window_features (MetaWindow *window); static void invalidate_work_areas (MetaWindow *window); -static void set_wm_state_on_xwindow (MetaDisplay *display, - Window xwindow, - int state); static void set_wm_state (MetaWindow *window); static void set_net_wm_state (MetaWindow *window); static void meta_window_set_above (MetaWindow *window, gboolean new_value); -static void send_configure_notify (MetaWindow *window); -static gboolean process_property_notify (MetaWindow *window, - XPropertyEvent *event); - static void meta_window_force_placement (MetaWindow *window); static void meta_window_show (MetaWindow *window); static void meta_window_hide (MetaWindow *window); -static gboolean meta_window_same_client (MetaWindow *window, - MetaWindow *other_window); - static void meta_window_save_rect (MetaWindow *window); static void save_user_window_placement (MetaWindow *window); static void force_save_user_window_placement (MetaWindow *window); @@ -141,8 +131,6 @@ static void meta_window_move_between_rects (MetaWindow *window, static void unmaximize_window_before_freeing (MetaWindow *window); static void unminimize_window_and_all_transient_parents (MetaWindow *window); -static void meta_window_update_monitor (MetaWindow *window); - /* Idle handlers for the three queues (run with meta_later_add()). The * "data" parameter in each case will be a GINT_TO_POINTER of the * index into the queue arrays to use. @@ -154,7 +142,7 @@ static gboolean idle_calc_showing (gpointer data); static gboolean idle_move_resize (gpointer data); static gboolean idle_update_icon (gpointer data); -G_DEFINE_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); enum { PROP_0, @@ -214,11 +202,20 @@ prefs_changed_callback (MetaPreference pref, window->type == META_WINDOW_MODAL_DIALOG) { window->attached = meta_window_should_attach_to_parent (window); - recalc_window_features (window); + meta_window_recalc_features (window); meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } } +static void +meta_window_real_get_default_skip_hints (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out) +{ + *skip_taskbar_out = FALSE; + *skip_pager_out = FALSE; +} + static void meta_window_finalize (GObject *object) { @@ -239,6 +236,9 @@ meta_window_finalize (GObject *object) if (window->opaque_region) cairo_region_destroy (window->opaque_region); + if (window->transient_for) + g_object_unref (window->transient_for); + meta_icon_cache_free (&window->icon_cache); g_free (window->sm_client_id); @@ -248,7 +248,6 @@ meta_window_finalize (GObject *object) g_free (window->res_class); g_free (window->res_name); g_free (window->title); - g_free (window->icon_name); g_free (window->desc); g_free (window->gtk_theme_variant); g_free (window->gtk_application_id); @@ -305,7 +304,7 @@ meta_window_get_property(GObject *object, g_value_set_boolean (value, win->wm_state_demands_attention); break; case PROP_URGENT: - g_value_set_boolean (value, win->wm_hints_urgent); + g_value_set_boolean (value, win->urgent); break; case PROP_SKIP_TASKBAR: g_value_set_boolean (value, win->skip_taskbar); @@ -373,6 +372,8 @@ meta_window_class_init (MetaWindowClass *klass) object_class->get_property = meta_window_get_property; object_class->set_property = meta_window_set_property; + klass->get_default_skip_hints = meta_window_real_get_default_skip_hints; + g_object_class_install_property (object_class, PROP_TITLE, g_param_spec_string ("title", @@ -569,7 +570,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("workspace-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, workspace_changed), + 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); @@ -578,7 +579,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("focus", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, focus), + 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -586,7 +587,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("raised", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, raised), + 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -594,7 +595,7 @@ meta_window_class_init (MetaWindowClass *klass) g_signal_new ("unmanaged", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MetaWindowClass, unmanaged), + 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -639,24 +640,6 @@ meta_window_init (MetaWindow *self) meta_prefs_add_listener (prefs_changed_callback, self); } -#ifdef WITH_VERBOSE_MODE -static const char* -wm_state_to_string (int state) -{ - switch (state) - { - case NormalState: - return "NormalState"; - case IconicState: - return "IconicState"; - case WithdrawnState: - return "WithdrawnState"; - } - - return "Unknown"; -} -#endif - static gboolean is_desktop_or_dock_foreach (MetaWindow *window, void *data) @@ -703,90 +686,6 @@ maybe_leave_show_desktop_mode (MetaWindow *window) } } -/* The MUTTER_WM_CLASS_FILTER environment variable is designed for - * performance and regression testing environments where we want to do - * tests with only a limited set of windows and ignore all other windows - * - * When it is set to a comma separated list of WM_CLASS class names, all - * windows not matching the list will be ignored. - * - * Returns TRUE if window has been filtered out and should be ignored. - */ -static gboolean -maybe_filter_window (MetaDisplay *display, - Window xwindow, - gboolean must_be_viewable, - XWindowAttributes *attrs) -{ - static char **filter_wm_classes = NULL; - static gboolean initialized = FALSE; - XClassHint class_hint; - gboolean filtered; - Status success; - int i; - - if (!initialized) - { - const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER"); - if (filter_string) - filter_wm_classes = g_strsplit (filter_string, ",", -1); - initialized = TRUE; - } - - if (!filter_wm_classes || !filter_wm_classes[0]) - return FALSE; - - filtered = TRUE; - - meta_error_trap_push (display); - success = XGetClassHint (display->xdisplay, xwindow, &class_hint); - - if (success) - { - for (i = 0; filter_wm_classes[i]; i++) - { - if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0) - { - filtered = FALSE; - break; - } - } - - XFree (class_hint.res_name); - XFree (class_hint.res_class); - } - - if (filtered) - { - /* We want to try and get the window managed by the next WM that come along, - * so we need to make sure that windows that are requested to be mapped while - * Mutter is running (!must_be_viewable), or windows already viewable at startup - * get a non-withdrawn WM_STATE property. Previously unmapped windows are left - * with whatever WM_STATE property they had. - */ - if (!must_be_viewable || attrs->map_state == IsViewable) - { - gulong old_state; - - if (!meta_prop_get_cardinal_with_atom_type (display, xwindow, - display->atom_WM_STATE, - display->atom_WM_STATE, - &old_state)) - old_state = WithdrawnState; - - if (old_state == WithdrawnState) - set_wm_state_on_xwindow (display, xwindow, NormalState); - } - - /* Make sure filtered windows are hidden from view */ - XUnmapWindow (display->xdisplay, xwindow); - } - - meta_error_trap_pop (display); - - return filtered; -} - gboolean meta_window_should_attach_to_parent (MetaWindow *window) { @@ -841,192 +740,56 @@ sync_client_window_mapped (MetaWindow *window) meta_error_trap_pop (window->display); } -MetaWindow* -meta_window_new (MetaDisplay *display, - Window xwindow, - gboolean must_be_viewable, - MetaCompEffect effect) +static void +meta_window_update_desc (MetaWindow *window) +{ + g_clear_pointer (&window->desc, g_free); + + if (window->title) + window->desc = g_strdup_printf ("0x%lx (%.10s)", window->xwindow, window->title); + else + window->desc = g_strdup_printf ("0x%lx", window->xwindow); +} + +MetaWindow * +_meta_window_shared_new (MetaDisplay *display, + MetaScreen *screen, + MetaWindowClientType client_type, + MetaWaylandSurface *surface, + Window xwindow, + gulong existing_wm_state, + MetaCompEffect effect, + XWindowAttributes *attrs) { - XWindowAttributes attrs; MetaWindow *window; - GSList *tmp; MetaWorkspace *space; - gulong existing_wm_state; - gulong event_mask; MetaMoveResizeFlags flags; - MetaScreen *screen; - meta_verbose ("Attempting to manage 0x%lx\n", xwindow); + g_assert (attrs != NULL); - if (meta_display_xwindow_is_a_no_focus_window (display, xwindow)) - { - meta_verbose ("Not managing no_focus_window 0x%lx\n", - xwindow); - return NULL; - } - - meta_error_trap_push (display); /* Push a trap over all of window - * creation, to reduce XSync() calls - */ - /* - * This function executes without any server grabs held. This means that - * the window could have already gone away, or could go away at any point, - * so we must be careful with X error handling. - */ - - if (!XGetWindowAttributes (display->xdisplay, xwindow, &attrs)) - { - meta_verbose ("Failed to get attributes for window 0x%lx\n", - xwindow); - goto error; - } - - screen = NULL; - for (tmp = display->screens; tmp != NULL; tmp = tmp->next) - { - MetaScreen *scr = tmp->data; - - if (scr->xroot == attrs.root) - { - screen = tmp->data; - break; - } - } - - g_assert (screen); - - /* A black list of override redirect windows that we don't need to manage: */ - if (attrs.override_redirect && - (xwindow == screen->no_focus_window || - xwindow == screen->flash_window || - xwindow == screen->wm_sn_selection_window || - attrs.class == InputOnly || - /* any windows created via meta_create_offscreen_window: */ - (attrs.x == -100 && attrs.y == -100 - && attrs.width == 1 && attrs.height == 1) || - xwindow == screen->wm_cm_selection_window || - xwindow == screen->guard_window || - (display->compositor && - xwindow == XCompositeGetOverlayWindow (display->xdisplay, - screen->xroot) - ) - ) - ) { - meta_verbose ("Not managing our own windows\n"); - goto error; - } - - if (maybe_filter_window (display, xwindow, must_be_viewable, &attrs)) - { - meta_verbose ("Not managing filtered window\n"); - goto error; - } - - meta_verbose ("must_be_viewable = %d attrs.map_state = %d (%s)\n", - must_be_viewable, - attrs.map_state, - (attrs.map_state == IsUnmapped) ? + meta_verbose ("attrs->map_state = %d (%s)\n", + attrs->map_state, + (attrs->map_state == IsUnmapped) ? "IsUnmapped" : - (attrs.map_state == IsViewable) ? + (attrs->map_state == IsViewable) ? "IsViewable" : - (attrs.map_state == IsUnviewable) ? + (attrs->map_state == IsUnviewable) ? "IsUnviewable" : "(unknown)"); - existing_wm_state = WithdrawnState; - if (must_be_viewable && attrs.map_state != IsViewable) - { - /* Only manage if WM_STATE is IconicState or NormalState */ - gulong state; - - /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */ - if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow, - display->atom_WM_STATE, - display->atom_WM_STATE, - &state) && - (state == IconicState || state == NormalState))) - { - meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow); - goto error; - } - - existing_wm_state = state; - meta_verbose ("WM_STATE of %lx = %s\n", xwindow, - wm_state_to_string (existing_wm_state)); - } - - /* - * XAddToSaveSet can only be called on windows created by a different client. - * with Mutter we want to be able to create manageable windows from within - * the process (such as a dummy desktop window). As we do not want this - * call failing to prevent the window from being managed, we call this - * before creating the return-checked error trap. - */ - XAddToSaveSet (display->xdisplay, xwindow); - - meta_error_trap_push_with_return (display); - - event_mask = PropertyChangeMask | ColormapChangeMask; - if (attrs.override_redirect) - event_mask |= StructureNotifyMask; - - /* If the window is from this client (a menu, say) we need to augment - * the event mask, not replace it. For windows from other clients, - * attrs.your_event_mask will be empty at this point. - */ - XSelectInput (display->xdisplay, xwindow, attrs.your_event_mask | event_mask); - - { - unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; - XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; - - meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask); - - XISetMask (mask.mask, XI_Enter); - XISetMask (mask.mask, XI_Leave); - XISetMask (mask.mask, XI_FocusIn); - XISetMask (mask.mask, XI_FocusOut); - - XISelectEvents (display->xdisplay, xwindow, &mask, 1); - } - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display)) - XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); -#endif - - /* Get rid of any borders */ - if (attrs.border_width != 0) - XSetWindowBorderWidth (display->xdisplay, xwindow, 0); - - /* Get rid of weird gravities */ - if (attrs.win_gravity != NorthWestGravity) - { - XSetWindowAttributes set_attrs; - - set_attrs.win_gravity = NorthWestGravity; - - XChangeWindowAttributes (display->xdisplay, - xwindow, - CWWinGravity, - &set_attrs); - } - - if (meta_error_trap_pop_with_return (display) != Success) - { - meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", - xwindow); - goto error; - } - - - window = g_object_new (META_TYPE_WINDOW, NULL); + if (client_type == META_WINDOW_CLIENT_TYPE_X11) + window = g_object_new (META_TYPE_WINDOW_X11, NULL); + else + window = g_object_new (META_TYPE_WINDOW_WAYLAND, NULL); window->constructing = TRUE; window->dialog_pid = -1; + window->client_type = client_type; + window->surface = surface; window->xwindow = xwindow; + window->surface_mapped = FALSE; /* this is in window->screen->display, but that's too annoying to * type @@ -1043,24 +806,24 @@ meta_window_new (MetaDisplay *display, window->screen = screen; - window->desc = g_strdup_printf ("0x%lx", window->xwindow); + meta_window_update_desc (window); - window->override_redirect = attrs.override_redirect; + window->override_redirect = attrs->override_redirect; /* avoid tons of stack updates */ meta_stack_freeze (window->screen->stack); - window->rect.x = attrs.x; - window->rect.y = attrs.y; - window->rect.width = attrs.width; - window->rect.height = attrs.height; + window->rect.x = attrs->x; + window->rect.y = attrs->y; + window->rect.width = attrs->width; + window->rect.height = attrs->height; /* And border width, size_hints are the "request" */ - window->border_width = attrs.border_width; - window->size_hints.x = attrs.x; - window->size_hints.y = attrs.y; - window->size_hints.width = attrs.width; - window->size_hints.height = attrs.height; + window->border_width = attrs->border_width; + window->size_hints.x = attrs->x; + window->size_hints.y = attrs->y; + window->size_hints.width = attrs->width; + window->size_hints.height = attrs->height; /* initialize the remaining size_hints as if size_hints.flags were zero */ meta_set_normal_hints (window, NULL); @@ -1068,18 +831,15 @@ meta_window_new (MetaDisplay *display, window->saved_rect = window->rect; window->user_rect = window->rect; - window->depth = attrs.depth; - window->xvisual = attrs.visual; - window->colormap = attrs.colormap; + window->depth = attrs->depth; + window->xvisual = attrs->visual; window->title = NULL; - window->icon_name = NULL; window->icon = NULL; window->mini_icon = NULL; meta_icon_cache_init (&window->icon_cache); window->wm_hints_pixmap = None; window->wm_hints_mask = None; - window->wm_hints_urgent = FALSE; window->frame = NULL; window->has_focus = FALSE; @@ -1105,8 +865,9 @@ meta_window_new (MetaDisplay *display, window->minimized = FALSE; window->tab_unminimized = FALSE; window->iconic = FALSE; - window->mapped = attrs.map_state != IsUnmapped; + window->mapped = attrs->map_state != IsUnmapped; window->hidden = FALSE; + window->known_to_compositor = FALSE; window->visible_to_compositor = FALSE; window->pending_compositor_effect = effect; /* if already mapped, no need to worry about focus-on-first-time-showing */ @@ -1132,7 +893,7 @@ meta_window_new (MetaDisplay *display, window->user_time_window = None; window->take_focus = FALSE; window->delete_window = FALSE; - window->net_wm_ping = FALSE; + window->can_ping = FALSE; window->input = TRUE; window->calc_placement = FALSE; window->shaken_loose = FALSE; @@ -1149,7 +910,11 @@ meta_window_new (MetaDisplay *display, window->mwm_has_move_func = TRUE; window->mwm_has_resize_func = TRUE; - window->decorated = TRUE; + if (client_type == META_WINDOW_CLIENT_TYPE_X11) + window->decorated = TRUE; + else + window->decorated = FALSE; + window->has_close_func = TRUE; window->has_minimize_func = TRUE; window->has_maximize_func = TRUE; @@ -1162,11 +927,8 @@ meta_window_new (MetaDisplay *display, window->always_sticky = FALSE; - window->wm_state_modal = FALSE; window->skip_taskbar = FALSE; window->skip_pager = FALSE; - window->wm_state_skip_taskbar = FALSE; - window->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; window->wm_state_demands_attention = FALSE; @@ -1186,17 +948,9 @@ meta_window_new (MetaDisplay *display, window->transient_parent_is_root_window = FALSE; window->type = META_WINDOW_NORMAL; - window->type_atom = None; window->struts = NULL; - window->using_net_wm_name = FALSE; - window->using_net_wm_visible_name = FALSE; - window->using_net_wm_icon_name = FALSE; - window->using_net_wm_visible_icon_name = FALSE; - - window->need_reread_icon = TRUE; - window->layer = META_LAYER_LAST; /* invalid value */ window->stack_position = -1; window->initial_workspace = 0; /* not used */ @@ -1208,6 +962,15 @@ meta_window_new (MetaDisplay *display, window->tile_match = NULL; + /* Assign this #MetaWindow a sequence number which can be used + * for sorting. + */ + window->stable_sequence = ++display->window_sequence_counter; + + window->opacity = 0xFF; + + META_WINDOW_GET_CLASS (window)->manage (window); + if (window->override_redirect) { window->decorated = FALSE; @@ -1218,35 +981,6 @@ meta_window_new (MetaDisplay *display, window->has_resize_func = FALSE; } - meta_display_register_x_window (display, &window->xwindow, window); - - meta_window_update_shape_region_x11 (window); - meta_window_update_input_region_x11 (window); - - /* Assign this #MetaWindow a sequence number which can be used - * for sorting. - */ - window->stable_sequence = ++display->window_sequence_counter; - - window->opacity = 0xFF; - - /* assign the window to its group, or create a new group if needed - */ - window->group = NULL; - window->xgroup_leader = None; - meta_window_compute_group (window); - - meta_window_load_initial_properties (window); - - if (!window->override_redirect) - { - update_sm_hints (window); /* must come after transient_for */ - - meta_window_update_role (window); - } - - meta_window_update_net_wm_type (window); - if (!window->override_redirect) meta_window_update_icon_now (window); @@ -1282,11 +1016,6 @@ meta_window_new (MetaDisplay *display, * can use this time as a fallback. */ if (!window->override_redirect && !window->net_wm_user_time_set) { - MetaWindow *parent = NULL; - if (window->xtransient_for) - parent = meta_display_lookup_x_window (window->display, - window->xtransient_for); - /* First, maybe the app was launched with startup notification using an * obsolete version of the spec; use that timestamp if it exists. */ @@ -1295,8 +1024,8 @@ meta_window_new (MetaDisplay *display, * being recorded as a fallback for potential transients */ window->net_wm_user_time = window->initial_timestamp; - else if (parent != NULL) - meta_window_set_user_time(window, parent->net_wm_user_time); + else if (window->transient_for != NULL) + meta_window_set_user_time (window, window->transient_for->net_wm_user_time); else /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just * being recorded as a fallback for potential transients @@ -1307,7 +1036,7 @@ meta_window_new (MetaDisplay *display, window->attached = meta_window_should_attach_to_parent (window); if (window->attached) - recalc_window_features (window); + meta_window_recalc_features (window); if (window->decorated) meta_window_ensure_frame (window); @@ -1376,21 +1105,16 @@ meta_window_new (MetaDisplay *display, if (!window->override_redirect) { if (window->workspace == NULL && - window->xtransient_for != None) + window->transient_for != NULL) { /* Try putting dialog on parent's workspace */ - MetaWindow *parent; - - parent = meta_display_lookup_x_window (window->display, - window->xtransient_for); - - if (parent && parent->workspace) + if (window->transient_for->workspace) { meta_topic (META_DEBUG_PLACEMENT, "Putting window %s on same workspace as parent %s\n", - window->desc, parent->desc); + window->desc, window->transient_for->desc); - if (parent->on_all_workspaces_requested) + if (window->transient_for->on_all_workspaces_requested) { window->on_all_workspaces_requested = TRUE; window->on_all_workspaces = TRUE; @@ -1398,7 +1122,7 @@ meta_window_new (MetaDisplay *display, /* this will implicitly add to the appropriate MRU lists */ - meta_workspace_add_window (parent->workspace, window); + meta_workspace_add_window (window->transient_for->workspace, window); } } @@ -1471,8 +1195,8 @@ meta_window_new (MetaDisplay *display, set_net_wm_state (window); } - if (screen->display->compositor) - meta_compositor_add_window (screen->display->compositor, window); + meta_compositor_add_window (screen->display->compositor, window); + window->known_to_compositor = TRUE; /* Sync stack changes */ meta_stack_thaw (window->screen->stack); @@ -1511,8 +1235,6 @@ meta_window_new (MetaDisplay *display, !window->initially_iconic) unminimize_window_and_all_transient_parents (window); - meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ - window->constructing = FALSE; meta_display_notify_window_created (display, window); @@ -1520,14 +1242,63 @@ meta_window_new (MetaDisplay *display, if (window->wm_state_demands_attention) g_signal_emit_by_name (window->display, "window-demands-attention", window); - if (window->wm_hints_urgent) - g_signal_emit_by_name (window->display, "window-marked-urgent", window); + return window; +} + +MetaWindow * +meta_window_wayland_new (MetaDisplay *display, + MetaWaylandSurface *surface) +{ + XWindowAttributes attrs; + MetaScreen *scr = display->screen; + MetaWindow *window; + + attrs.x = 0; + attrs.y = 0; + attrs.width = 1; + attrs.height = 1; + attrs.border_width = 0; + attrs.depth = 24; + attrs.visual = NULL; + attrs.root = scr->xroot; + attrs.class = InputOutput; + attrs.bit_gravity = NorthWestGravity; + attrs.win_gravity = NorthWestGravity; + attrs.backing_store = 0; + attrs.backing_planes = ~0; + attrs.backing_pixel = 0; + attrs.save_under = 0; + attrs.colormap = 0; + attrs.map_installed = 1; + attrs.map_state = IsUnmapped; + attrs.all_event_masks = ~0; + attrs.your_event_mask = 0; + attrs.do_not_propagate_mask = 0; + attrs.override_redirect = 0; + attrs.screen = scr->xscreen; + + /* XXX: Note: In the Wayland case we currently still trap X errors while + * creating a MetaWindow because we will still be making various redundant + * X requests (passing a window xid of None) until we thoroughly audit all + * the code to make sure it knows about non X based clients... + */ + meta_error_trap_push (display); /* Push a trap over all of window + * creation, to reduce XSync() calls + */ + + window = _meta_window_shared_new (display, + scr, + META_WINDOW_CLIENT_TYPE_WAYLAND, + surface, + None, + WithdrawnState, + META_COMP_EFFECT_CREATE, + &attrs); + window->can_ping = TRUE; + + meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ return window; - -error: - meta_error_trap_pop (display); - return NULL; } /* This function should only be called from the end of meta_window_new_with_attrs () */ @@ -1694,15 +1465,21 @@ meta_window_unmanage (MetaWindow *window, meta_verbose ("Unmanaging 0x%lx\n", window->xwindow); - if (window->display->compositor) - { - if (window->visible_to_compositor) - meta_compositor_hide_window (window->display->compositor, window, - META_COMP_EFFECT_DESTROY); + /* This needs to happen for both Wayland and XWayland clients, + * so it can't be in MetaWindowWayland. */ + if (window->surface) + meta_wayland_surface_set_window (window->surface, NULL); - meta_compositor_remove_window (window->display->compositor, window); + if (window->visible_to_compositor) + { + window->visible_to_compositor = FALSE; + meta_compositor_hide_window (window->display->compositor, window, + META_COMP_EFFECT_DESTROY); } + meta_compositor_remove_window (window->display->compositor, window); + window->known_to_compositor = FALSE; + if (window->display->window_with_menu == window) { meta_ui_window_menu_free (window->display->window_menu); @@ -1802,12 +1579,6 @@ meta_window_unmanage (MetaWindow *window, if (window->maximized_horizontally || window->maximized_vertically) unmaximize_window_before_freeing (window); - /* The XReparentWindow call in meta_window_destroy_frame() moves the - * window so we need to send a configure notify; see bug 399552. (We - * also do this just in case a window got unmaximized.) - */ - send_configure_notify (window); - meta_window_unqueue (window, META_QUEUE_CALC_SHOWING | META_QUEUE_MOVE_RESIZE | META_QUEUE_UPDATE_ICON); @@ -1843,110 +1614,24 @@ meta_window_unmanage (MetaWindow *window, meta_window_destroy_sync_request_alarm (window); - if (window->frame) - meta_window_destroy_frame (window); - /* If an undecorated window is being withdrawn, that will change the * stack as presented to the compositing manager, without actually * changing the stacking order of X windows. */ meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker); - if (window->withdrawn) - { - /* We need to clean off the window's state so it - * won't be restored if the app maps it again. - */ - meta_error_trap_push (window->display); - meta_verbose ("Cleaning state from window %s\n", window->desc); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_DESKTOP); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_STATE); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_FULLSCREEN_MONITORS); - set_wm_state (window); - meta_error_trap_pop (window->display); - } - else - { - /* We need to put WM_STATE so that others will understand it on - * restart. - */ - if (!window->minimized) - { - meta_error_trap_push (window->display); - set_wm_state (window); - meta_error_trap_pop (window->display); - } - - /* If we're unmanaging a window that is not withdrawn, then - * either (a) mutter is exiting, in which case we need to map - * the window so the next WM will know that it's not Withdrawn, - * or (b) we want to create a new MetaWindow to replace the - * current one, which will happen automatically if we re-map - * the X Window. - */ - meta_error_trap_push (window->display); - XMapWindow (window->display->xdisplay, - window->xwindow); - meta_error_trap_pop (window->display); - } - meta_window_ungrab_keys (window); meta_display_ungrab_window_buttons (window->display, window->xwindow); meta_display_ungrab_focus_window_button (window->display, window); if (window->display->autoraise_window == window) meta_display_remove_autoraise_callback (window->display); - meta_display_unregister_x_window (window->display, window->xwindow); + META_WINDOW_GET_CLASS (window)->unmanage (window); - - meta_error_trap_push (window->display); - - /* Put back anything we messed up */ - if (window->border_width != 0) - XSetWindowBorderWidth (window->display->xdisplay, - window->xwindow, - window->border_width); - - /* No save set */ - XRemoveFromSaveSet (window->display->xdisplay, - window->xwindow); - - /* Even though the window is now unmanaged, we can't unselect events. This - * window might be a window from this process, like a GdkMenu, in - * which case it will have pointer events and so forth selected - * for it by GDK. There's no way to disentangle those events from the events - * we've selected. Even for a window from a different X client, - * GDK could also have selected events for it for IPC purposes, so we - * can't unselect in that case either. - * - * Similarly, we can't unselected for events on window->user_time_window. - * It might be our own GDK focus window, or it might be a window that a - * different client is using for multiple different things: - * _NET_WM_USER_TIME_WINDOW and IPC, perhaps. - */ - - if (window->user_time_window != None) - { - meta_display_unregister_x_window (window->display, - window->user_time_window); - window->user_time_window = None; - } - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (window->display)) - XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask); -#endif - - meta_error_trap_pop (window->display); + if (window->frame) + meta_window_destroy_frame (window); meta_prefs_remove_listener (prefs_changed_callback, window); - meta_screen_queue_check_fullscreen (window->screen); g_signal_emit (window, window_signals[UNMANAGED], 0); @@ -2007,156 +1692,18 @@ meta_window_update_on_all_workspaces (MetaWindow *window) } } -static void -set_wm_state_on_xwindow (MetaDisplay *display, - Window xwindow, - int state) -{ - unsigned long data[2]; - - /* Mutter doesn't use icon windows, so data[1] should be None - * according to the ICCCM 2.0 Section 4.1.3.1. - */ - data[0] = state; - data[1] = None; - - meta_error_trap_push (display); - XChangeProperty (display->xdisplay, xwindow, - display->atom_WM_STATE, - display->atom_WM_STATE, - 32, PropModeReplace, (guchar*) data, 2); - meta_error_trap_pop (display); -} - static void set_wm_state (MetaWindow *window) { - int state; - - if (window->withdrawn) - state = WithdrawnState; - else if (window->iconic) - state = IconicState; - else - state = NormalState; - - set_wm_state_on_xwindow (window->display, window->xwindow, state); + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_x11_set_wm_state (window); } static void set_net_wm_state (MetaWindow *window) { - int i; - unsigned long data[13]; - - i = 0; - if (window->shaded) - { - data[i] = window->display->atom__NET_WM_STATE_SHADED; - ++i; - } - if (window->wm_state_modal) - { - data[i] = window->display->atom__NET_WM_STATE_MODAL; - ++i; - } - if (window->skip_pager) - { - data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER; - ++i; - } - if (window->skip_taskbar) - { - data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR; - ++i; - } - if (window->maximized_horizontally) - { - data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ; - ++i; - } - if (window->maximized_vertically) - { - data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT; - ++i; - } - if (window->fullscreen) - { - data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN; - ++i; - } - if (!meta_window_showing_on_its_workspace (window) || window->shaded) - { - data[i] = window->display->atom__NET_WM_STATE_HIDDEN; - ++i; - } - if (window->wm_state_above) - { - data[i] = window->display->atom__NET_WM_STATE_ABOVE; - ++i; - } - if (window->wm_state_below) - { - data[i] = window->display->atom__NET_WM_STATE_BELOW; - ++i; - } - if (window->wm_state_demands_attention) - { - data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION; - ++i; - } - if (window->on_all_workspaces_requested) - { - data[i] = window->display->atom__NET_WM_STATE_STICKY; - ++i; - } - if (meta_window_appears_focused (window)) - { - data[i] = window->display->atom__NET_WM_STATE_FOCUSED; - ++i; - } - - meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); - - meta_error_trap_push (window->display); - XChangeProperty (window->display->xdisplay, window->xwindow, - window->display->atom__NET_WM_STATE, - XA_ATOM, - 32, PropModeReplace, (guchar*) data, i); - meta_error_trap_pop (window->display); - - if (window->fullscreen) - { - if (window->fullscreen_monitors[0] >= 0) - { - data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[0]); - data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[1]); - data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[2]); - data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen, - window->fullscreen_monitors[3]); - - meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); - meta_error_trap_push (window->display); - XChangeProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_FULLSCREEN_MONITORS, - XA_CARDINAL, 32, PropModeReplace, - (guchar*) data, 4); - meta_error_trap_pop (window->display); - } - else - { - meta_verbose ("Clearing _NET_WM_FULLSCREEN_MONITORS\n"); - meta_error_trap_push (window->display); - XDeleteProperty (window->display->xdisplay, - window->xwindow, - window->display->atom__NET_WM_FULLSCREEN_MONITORS); - meta_error_trap_pop (window->display); - } - } + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_x11_set_net_wm_state (window); } /** @@ -2262,6 +1809,9 @@ meta_window_should_be_showing (MetaWindow *window) { gboolean on_workspace; + if (!window->surface_mapped) + return FALSE; + meta_verbose ("Should be showing for window %s\n", window->desc); /* See if we're on the workspace */ @@ -2711,8 +2261,8 @@ intervening_user_event_occurred (MetaWindow *window) * behavior is worthwhile. The basic idea is to get more feedback about how * usage scenarios of "strict" focus users and what they expect. See #326159. */ -gboolean -__window_is_terminal (MetaWindow *window) +static gboolean +window_is_terminal (MetaWindow *window) { if (window == NULL || window->res_class == NULL) return FALSE; @@ -2788,7 +2338,7 @@ window_state_on_map (MetaWindow *window, if (*takes_focus && meta_prefs_get_focus_new_windows () == G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && !window->display->allow_terminal_deactivation && - __window_is_terminal (window->display->focus_window) && + window_is_terminal (window->display->focus_window) && !meta_window_is_ancestor_of_transient (window->display->focus_window, window)) { @@ -3067,27 +2617,24 @@ meta_window_show (MetaWindow *window) if (!window->visible_to_compositor) { + MetaCompEffect effect = META_COMP_EFFECT_NONE; + window->visible_to_compositor = TRUE; - if (window->display->compositor) + switch (window->pending_compositor_effect) { - MetaCompEffect effect = META_COMP_EFFECT_NONE; - - switch (window->pending_compositor_effect) - { - case META_COMP_EFFECT_CREATE: - case META_COMP_EFFECT_UNMINIMIZE: - effect = window->pending_compositor_effect; - break; - case META_COMP_EFFECT_NONE: - case META_COMP_EFFECT_DESTROY: - case META_COMP_EFFECT_MINIMIZE: - break; - } - - meta_compositor_show_window (window->display->compositor, - window, effect); + case META_COMP_EFFECT_CREATE: + case META_COMP_EFFECT_UNMINIMIZE: + effect = window->pending_compositor_effect; + break; + case META_COMP_EFFECT_NONE: + case META_COMP_EFFECT_DESTROY: + case META_COMP_EFFECT_MINIMIZE: + break; } + + meta_compositor_show_window (window->display->compositor, + window, effect); } /* We don't want to worry about all cases from inside @@ -3130,6 +2677,9 @@ meta_window_show (MetaWindow *window) if (did_show) meta_screen_queue_check_fullscreen (window->screen); + if (did_show && window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + meta_wayland_compositor_repick (meta_wayland_compositor_get_default ()); + /* * Now that we have shown the window, we no longer want to consider the * initial timestamp in any subsequent deliberations whether to focus this @@ -3157,26 +2707,23 @@ meta_window_hide (MetaWindow *window) if (window->visible_to_compositor) { + MetaCompEffect effect = META_COMP_EFFECT_NONE; + window->visible_to_compositor = FALSE; - if (window->display->compositor) + switch (window->pending_compositor_effect) { - MetaCompEffect effect = META_COMP_EFFECT_NONE; - - switch (window->pending_compositor_effect) - { - case META_COMP_EFFECT_CREATE: - case META_COMP_EFFECT_UNMINIMIZE: - case META_COMP_EFFECT_NONE: - break; - case META_COMP_EFFECT_DESTROY: - case META_COMP_EFFECT_MINIMIZE: - effect = window->pending_compositor_effect; - break; - } - - meta_compositor_hide_window (window->display->compositor, window, effect); + case META_COMP_EFFECT_CREATE: + case META_COMP_EFFECT_UNMINIMIZE: + case META_COMP_EFFECT_NONE: + break; + case META_COMP_EFFECT_DESTROY: + case META_COMP_EFFECT_MINIMIZE: + effect = window->pending_compositor_effect; + break; } + + meta_compositor_hide_window (window->display->compositor, window, effect); } did_hide = FALSE; @@ -3424,9 +2971,12 @@ meta_window_maximize_internal (MetaWindow *window, if (maximize_horizontally || maximize_vertically) window->force_save_user_rect = FALSE; - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); + if (window->surface && window->maximized_horizontally && window->maximized_vertically) + meta_wayland_surface_send_maximized (window->surface); + g_object_freeze_notify (G_OBJECT (window)); g_object_notify (G_OBJECT (window), "maximized-horizontally"); g_object_notify (G_OBJECT (window), "maximized-vertically"); @@ -3439,6 +2989,8 @@ meta_window_maximize (MetaWindow *window, { MetaRectangle *saved_rect = NULL; gboolean maximize_horizontally, maximize_vertically; + MetaRectangle old_rect; + MetaRectangle new_rect; g_return_if_fail (!window->override_redirect); @@ -3488,27 +3040,15 @@ meta_window_maximize (MetaWindow *window, directions, saved_rect); - if (window->display->compositor) - { - MetaRectangle old_rect; - MetaRectangle new_rect; + meta_window_get_frame_rect (window, &old_rect); - meta_window_get_frame_rect (window, &old_rect); + meta_window_move_resize_now (window); - meta_window_move_resize_now (window); - - meta_window_get_frame_rect (window, &new_rect); - meta_compositor_maximize_window (window->display->compositor, - window, - &old_rect, - &new_rect); - } - else - { - /* move_resize with new maximization constraints - */ - meta_window_queue(window, META_QUEUE_MOVE_RESIZE); - } + meta_window_get_frame_rect (window, &new_rect); + meta_compositor_maximize_window (window->display->compositor, + window, + &old_rect, + &new_rect); } } @@ -3668,6 +3208,8 @@ void meta_window_tile (MetaWindow *window) { MetaMaximizeFlags directions; + MetaRectangle old_rect; + MetaRectangle new_rect; /* Don't do anything if no tiling is requested */ if (window->tile_mode == META_TILE_NONE) @@ -3681,31 +3223,19 @@ meta_window_tile (MetaWindow *window) meta_window_maximize_internal (window, directions, NULL); meta_screen_update_tile_preview (window->screen, FALSE); - if (window->display->compositor) - { - MetaRectangle old_rect; - MetaRectangle new_rect; + meta_window_get_frame_rect (window, &old_rect); - meta_window_get_frame_rect (window, &old_rect); + meta_window_move_resize_now (window); - meta_window_move_resize_now (window); + meta_window_get_frame_rect (window, &new_rect); + meta_compositor_maximize_window (window->display->compositor, + window, + &old_rect, + &new_rect); - meta_window_get_frame_rect (window, &new_rect); - meta_compositor_maximize_window (window->display->compositor, - window, - &old_rect, - &new_rect); - - if (window->frame) - meta_ui_queue_frame_draw (window->screen->ui, - window->frame->xwindow); - } - else - { - /* move_resize with new tiling constraints - */ - meta_window_queue (window, META_QUEUE_MOVE_RESIZE); - } + if (window->frame) + meta_ui_queue_frame_draw (window->screen->ui, + window->frame->xwindow); } static gboolean @@ -3778,6 +3308,7 @@ meta_window_unmaximize_internal (MetaWindow *window, int gravity) { gboolean unmaximize_horizontally, unmaximize_vertically; + MetaRectangle new_rect; g_return_if_fail (!window->override_redirect); @@ -3814,7 +3345,7 @@ meta_window_unmaximize_internal (MetaWindow *window, window->maximized_vertically = window->maximized_vertically && !unmaximize_vertically; - /* recalc_window_features() will eventually clear the cached frame + /* recalc_features() will eventually clear the cached frame * extents, but we need the correct frame extents in the code below, * so invalidate the old frame extents manually up front. */ @@ -3862,34 +3393,19 @@ meta_window_unmaximize_internal (MetaWindow *window, */ ensure_size_hints_satisfied (&target_rect, &window->size_hints); - if (window->display->compositor) - { - MetaRectangle new_rect; + meta_window_move_resize_internal (window, + META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, + gravity, + target_rect.x, + target_rect.y, + target_rect.width, + target_rect.height); - meta_window_move_resize_internal (window, - META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, - gravity, - target_rect.x, - target_rect.y, - target_rect.width, - target_rect.height); - - meta_window_get_frame_rect (window, &new_rect); - meta_compositor_unmaximize_window (window->display->compositor, - window, - &old_rect, - &new_rect); - } - else - { - meta_window_move_resize_internal (window, - META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION, - gravity, - target_rect.x, - target_rect.y, - target_rect.width, - target_rect.height); - } + meta_window_get_frame_rect (window, &new_rect); + meta_compositor_unmaximize_window (window->display->compositor, + window, + &old_rect, + &new_rect); /* Make sure user_rect is current. */ @@ -3908,14 +3424,17 @@ meta_window_unmaximize_internal (MetaWindow *window, window->display->grab_anchor_window_pos = window->user_rect; } - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); } - g_object_freeze_notify (G_OBJECT (window)); - g_object_notify (G_OBJECT (window), "maximized-horizontally"); - g_object_notify (G_OBJECT (window), "maximized-vertically"); - g_object_thaw_notify (G_OBJECT (window)); + if (window->surface && !window->maximized_horizontally && !window->maximized_vertically) + meta_wayland_surface_send_unmaximized (window->surface); + + g_object_freeze_notify (G_OBJECT (window)); + g_object_notify (G_OBJECT (window), "maximized-horizontally"); + g_object_notify (G_OBJECT (window), "maximized-vertically"); + g_object_thaw_notify (G_OBJECT (window)); } void @@ -4012,12 +3531,15 @@ meta_window_make_fullscreen_internal (MetaWindow *window) meta_window_raise (window); meta_stack_thaw (window->screen->stack); - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); /* For the auto-minimize feature, if we fail to get focus */ meta_screen_queue_check_fullscreen (window->screen); + if (window->surface) + meta_wayland_surface_send_fullscreened (window->surface); + g_object_notify (G_OBJECT (window), "fullscreen"); } } @@ -4058,7 +3580,7 @@ meta_window_unmake_fullscreen (MetaWindow *window) /* Need to update window->has_resize_func before we move_resize() */ - recalc_window_features (window); + meta_window_recalc_features (window); set_net_wm_state (window); meta_window_move_resize (window, @@ -4074,6 +3596,9 @@ meta_window_unmake_fullscreen (MetaWindow *window) meta_window_update_layer (window); + if (window->surface) + meta_wayland_surface_send_unfullscreened (window->surface); + g_object_notify (G_OBJECT (window), "fullscreen"); } } @@ -4172,11 +3697,11 @@ unminimize_window_and_all_transient_parents (MetaWindow *window) meta_window_foreach_ancestor (window, unminimize_func, NULL); } -static void -window_activate (MetaWindow *window, - guint32 timestamp, - MetaClientType source_indication, - MetaWorkspace *workspace) +void +meta_window_activate_full (MetaWindow *window, + guint32 timestamp, + MetaClientType source_indication, + MetaWorkspace *workspace) { gboolean can_ignore_outdated_timestamps; meta_topic (META_DEBUG_FOCUS, @@ -4224,14 +3749,14 @@ window_activate (MetaWindow *window, /* For non-transient windows, we just set up a pulsing indicator, rather than move windows or workspaces. See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */ - if (window->xtransient_for == None && + if (window->transient_for == NULL && !meta_window_located_on_workspace (window, workspace)) { meta_window_set_demands_attention (window); /* We've marked it as demanding, don't need to do anything else. */ return; } - else if (window->xtransient_for != None) + else if (window->transient_for != NULL) { /* Move transients to current workspace - preference dialogs should appear over the source window. */ @@ -4269,7 +3794,7 @@ meta_window_activate (MetaWindow *window, * we were such. If we change the pager behavior later, we could revisit * this and just add extra flags to window_activate. */ - window_activate (window, timestamp, META_CLIENT_TYPE_PAGER, NULL); + meta_window_activate_full (window, timestamp, META_CLIENT_TYPE_PAGER, NULL); } void @@ -4279,11 +3804,7 @@ meta_window_activate_with_workspace (MetaWindow *window, { g_return_if_fail (!window->override_redirect); - /* We're not really a pager, but the behavior we want is the same as if - * we were such. If we change the pager behavior later, we could revisit - * this and just add extra flags to window_activate. - */ - window_activate (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace); + meta_window_activate_full (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace); } /* Manually fix all the weirdness explained in the big comment at the @@ -4421,12 +3942,6 @@ adjust_for_gravity (MetaWindow *window, } } -static gboolean -static_gravity_works (MetaDisplay *display) -{ - return display->static_gravity_works; -} - void meta_window_create_sync_request_alarm (MetaWindow *window) { @@ -4438,7 +3953,7 @@ meta_window_create_sync_request_alarm (MetaWindow *window) window->sync_request_alarm != None) return; - meta_error_trap_push_with_return (window->display); + meta_error_trap_push (window->display); /* In the new (extended style), the counter value is initialized by * the client before mapping the window. In the old style, we're @@ -4514,90 +4029,6 @@ meta_window_destroy_sync_request_alarm (MetaWindow *window) #endif /* HAVE_XSYNC */ } -#ifdef HAVE_XSYNC -static gboolean -sync_request_timeout (gpointer data) -{ - MetaWindow *window = data; - - window->sync_request_timeout_id = 0; - - /* We have now waited for more than a second for the - * application to respond to the sync request - */ - window->disable_sync = TRUE; - - /* Reset the wait serial, so we don't continue freezing - * window updates - */ - window->sync_request_wait_serial = 0; - meta_compositor_set_updates_frozen (window->display->compositor, window, - meta_window_updates_are_frozen (window)); - - if (window == window->display->grab_window && - meta_grab_op_is_resizing (window->display->grab_op)) - { - update_resize (window, - window->display->grab_last_user_action_was_snap, - window->display->grab_latest_motion_x, - window->display->grab_latest_motion_y, - TRUE); - } - - return FALSE; -} - -static void -send_sync_request (MetaWindow *window) -{ - XClientMessageEvent ev; - gint64 wait_serial; - - /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to - * increase the value, but for the new "extended" style we need to - * pick an even (unfrozen) value sufficiently ahead of the last serial - * that we received from the client; the same code still works - * for the old style. The increment of 240 is specified by the EWMH - * and is (1 second) * (60fps) * (an increment of 4 per frame). - */ - wait_serial = window->sync_request_serial + 240; - - window->sync_request_wait_serial = wait_serial; - - ev.type = ClientMessage; - ev.window = window->xwindow; - ev.message_type = window->display->atom_WM_PROTOCOLS; - ev.format = 32; - ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST; - /* FIXME: meta_display_get_current_time() is bad, but since calls - * come from meta_window_move_resize_internal (which in turn come - * from all over), I'm not sure what we can do to fix it. Do we - * want to use _roundtrip, though? - */ - ev.data.l[1] = meta_display_get_current_time (window->display); - ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff); - ev.data.l[3] = wait_serial >> 32; - ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0; - - /* We don't need to trap errors here as we are already - * inside an error_trap_push()/pop() pair. - */ - XSendEvent (window->display->xdisplay, - window->xwindow, False, 0, (XEvent*) &ev); - - /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST; - * if this time expires, we consider the window unresponsive - * and resize it unsynchonized. - */ - window->sync_request_timeout_id = g_timeout_add (1000, - sync_request_timeout, - window); - - meta_compositor_set_updates_frozen (window->display->compositor, window, - meta_window_updates_are_frozen (window)); -} -#endif - /** * meta_window_updates_are_frozen: * @window: a #MetaWindow @@ -4700,7 +4131,7 @@ meta_window_update_for_monitors_changed (MetaWindow *window) &new->rect); } -static void +void meta_window_update_monitor (MetaWindow *window) { const MetaMonitorInfo *old; @@ -4736,7 +4167,7 @@ meta_window_update_monitor (MetaWindow *window) /* If we're changing monitors, we need to update the has_maximize_func flag, * as the working area has changed. */ - recalc_window_features (window); + meta_window_recalc_features (window); } } @@ -4769,6 +4200,7 @@ meta_window_move_resize_internal (MetaWindow *window, * 2 | A not-resize-only ConfigureRequest/net_moveresize_window request * 3 | meta_window_move * 3 | meta_window_move_resize + * 4 | meta_window_move_resize_wayland * * For each of the cases, root_x_nw and root_y_nw must be treated as follows: * @@ -4779,42 +4211,38 @@ meta_window_move_resize_internal (MetaWindow *window, * coordinates are relative to some corner or side of the outer * window (except for the case of StaticGravity) and we want to * know the location of the upper left corner of the inner window. - * (3) These values are already the desired positon of the NW corner + * (3) These values are already the desired position of the NW corner * of the inner window + * (4) These values are already the desired position of the NW corner + * of the inner window (which is also the outer window, because + * we don't decorate wayland clients), and the client has acknowledged + * the window size change. */ - XWindowChanges values; - unsigned int mask; - gboolean need_configure_notify; - MetaFrameBorders borders; - gboolean need_move_client = FALSE; - gboolean need_move_frame = FALSE; - gboolean need_resize_client = FALSE; - gboolean need_resize_frame = FALSE; - int size_dx; - int size_dy; - gboolean frame_shape_changed = FALSE; gboolean is_configure_request; gboolean do_gravity_adjust; gboolean is_user_action; + gboolean is_wayland_resize; gboolean did_placement; - gboolean configure_frame_first; - gboolean use_static_gravity; /* used for the configure request, but may not be final * destination due to StaticGravity etc. */ - int client_move_x; - int client_move_y; MetaRectangle new_rect; MetaRectangle old_rect; + MetaRectangle requested_rect; + MetaMoveResizeResultFlags result; + MetaFrameBorders borders; g_return_if_fail (!window->override_redirect); is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0; do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0; is_user_action = (flags & META_IS_USER_ACTION) != 0; + is_wayland_resize = (flags & META_IS_WAYLAND_RESIZE) != 0; - /* The action has to be a move or a resize or both... */ - g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)); + /* The action has to be a move, a resize or the wayland client + * acking our choice of size. + */ + g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION | META_IS_WAYLAND_RESIZE)); /* We don't need it in the idle queue anymore. */ meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE); @@ -4828,13 +4256,14 @@ meta_window_move_resize_internal (MetaWindow *window, is_user_action ? " (user move/resize)" : "", old_rect.x, old_rect.y, old_rect.width, old_rect.height); - meta_frame_calc_borders (window->frame, - &borders); + meta_frame_calc_borders (window->frame, &borders); - new_rect.x = root_x_nw; - new_rect.y = root_y_nw; - new_rect.width = w; - new_rect.height = h; + requested_rect.x = root_x_nw; + requested_rect.y = root_y_nw; + requested_rect.width = w; + requested_rect.height = h; + + new_rect = requested_rect; /* If this is a resize only, the position should be ignored and * instead obtained by resizing the old rectangle according to the @@ -4872,328 +4301,31 @@ meta_window_move_resize_internal (MetaWindow *window, did_placement = !window->placed && window->calc_placement; - meta_window_constrain (window, - flags, - gravity, - &old_rect, - &new_rect); - - /* meta_window_constrain() might have maximized the window after placement, - * changing the borders. - */ - meta_frame_calc_borders (window->frame, &borders); - - w = new_rect.width; - h = new_rect.height; - root_x_nw = new_rect.x; - root_y_nw = new_rect.y; - - if (w != window->rect.width || - h != window->rect.height) - need_resize_client = TRUE; - - window->rect.width = w; - window->rect.height = h; - - if (window->frame) + if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) { - int frame_size_dx, frame_size_dy; - int new_w, new_h; - - new_w = window->rect.width + borders.total.left + borders.total.right; - - if (window->shaded) - new_h = borders.total.top; - else - new_h = window->rect.height + borders.total.top + borders.total.bottom; - - frame_size_dx = new_w - window->frame->rect.width; - frame_size_dy = new_h - window->frame->rect.height; - - need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0); - - window->frame->rect.width = new_w; - window->frame->rect.height = new_h; - - meta_topic (META_DEBUG_GEOMETRY, - "Calculated frame size %dx%d\n", - window->frame->rect.width, - window->frame->rect.height); + meta_window_constrain (window, + flags, + gravity, + &old_rect, + &new_rect); } - /* For nice effect, when growing the window we want to move/resize - * the frame first, when shrinking the window we want to move/resize - * the client first. If we grow one way and shrink the other, - * see which way we're moving "more" - * - * Mail from Owen subject "Suggestion: Gravity and resizing from the left" - * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html - * - * An annoying fact you need to know in this code is that StaticGravity - * does nothing if you _only_ resize or _only_ move the frame; - * it must move _and_ resize, otherwise you get NorthWestGravity - * behavior. The move and resize must actually occur, it is not - * enough to set CWX | CWWidth but pass in the current size/pos. - */ - - if (window->frame) - { - int new_x, new_y; - int frame_pos_dx, frame_pos_dy; - - /* Compute new frame coords */ - new_x = root_x_nw - borders.total.left; - new_y = root_y_nw - borders.total.top; - - frame_pos_dx = new_x - window->frame->rect.x; - frame_pos_dy = new_y - window->frame->rect.y; - - need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0); - - window->frame->rect.x = new_x; - window->frame->rect.y = new_y; - - /* If frame will both move and resize, then StaticGravity - * on the child window will kick in and implicitly move - * the child with respect to the frame. The implicit - * move will keep the child in the same place with - * respect to the root window. If frame only moves - * or only resizes, then the child will just move along - * with the frame. - */ - - /* window->rect.x, window->rect.y are relative to frame, - * remember they are the server coords - */ - - new_x = borders.total.left; - new_y = borders.total.top; - - if (need_resize_frame && need_move_frame && - static_gravity_works (window->display)) - { - /* static gravity kicks in because frame - * is both moved and resized - */ - /* when we move the frame by frame_pos_dx, frame_pos_dy the - * client will implicitly move relative to frame by the - * inverse delta. - * - * When moving client then frame, we move the client by the - * frame delta, to be canceled out by the implicit move by - * the inverse frame delta, resulting in a client at new_x, - * new_y. - * - * When moving frame then client, we move the client - * by the same delta as the frame, because the client - * was "left behind" by the frame - resulting in a client - * at new_x, new_y. - * - * In both cases we need to move the client window - * in all cases where we had to move the frame window. - */ - - client_move_x = new_x + frame_pos_dx; - client_move_y = new_y + frame_pos_dy; - - if (need_move_frame) - need_move_client = TRUE; - - use_static_gravity = TRUE; - } - else - { - client_move_x = new_x; - client_move_y = new_y; - - if (client_move_x != window->rect.x || - client_move_y != window->rect.y) - need_move_client = TRUE; - - use_static_gravity = FALSE; - } - - /* This is the final target position, but not necessarily what - * we pass to XConfigureWindow, due to StaticGravity implicit - * movement. - */ - window->rect.x = new_x; - window->rect.y = new_y; - } - else - { - if (root_x_nw != window->rect.x || - root_y_nw != window->rect.y) - need_move_client = TRUE; - - window->rect.x = root_x_nw; - window->rect.y = root_y_nw; - - client_move_x = window->rect.x; - client_move_y = window->rect.y; - - use_static_gravity = FALSE; - } - - /* If frame extents have changed, fill in other frame fields and - change frame's extents property. */ - if (window->frame && - (window->frame->child_x != borders.total.left || - window->frame->child_y != borders.total.top || - window->frame->right_width != borders.total.right || - window->frame->bottom_height != borders.total.bottom)) - { - window->frame->child_x = borders.total.left; - window->frame->child_y = borders.total.top; - window->frame->right_width = borders.total.right; - window->frame->bottom_height = borders.total.bottom; - - update_net_frame_extents (window); - } - - /* See ICCCM 4.1.5 for when to send ConfigureNotify */ - - need_configure_notify = FALSE; - - /* If this is a configure request and we change nothing, then we - * must send configure notify. - */ - if (is_configure_request && - !(need_move_client || need_move_frame || - need_resize_client || need_resize_frame || - window->border_width != 0)) - need_configure_notify = TRUE; - - /* We must send configure notify if we move but don't resize, since - * the client window may not get a real event - */ - if ((need_move_client || need_move_frame) && - !(need_resize_client || need_resize_frame)) - need_configure_notify = TRUE; - - /* MapRequest events with a PPosition or UPosition hint with a frame - * are moved by mutter without resizing; send a configure notify - * in such cases. See #322840. (Note that window->constructing is - * only true iff this call is due to a MapRequest, and when - * PPosition/UPosition hints aren't set, mutter seems to send a - * ConfigureNotify anyway due to the above code.) - */ - if (window->constructing && window->frame && - ((window->size_hints.flags & PPosition) || - (window->size_hints.flags & USPosition))) - need_configure_notify = TRUE; - - /* The rest of this function syncs our new size/pos with X as - * efficiently as possible - */ - - /* Normally, we configure the frame first depending on whether - * we grow the frame more than we shrink. The idea is to avoid - * messing up the window contents by having a temporary situation - * where the frame is smaller than the window. However, if we're - * cooperating with the client to create an atomic frame upate, - * and the window is redirected, then we should always update - * the frame first, since updating the frame will force a new - * backing pixmap to be allocated, and the old backing pixmap - * will be left undisturbed for us to paint to the screen until - * the client finishes redrawing. - */ - if (window->extended_sync_request_counter) - { - configure_frame_first = TRUE; - } - else - { - size_dx = w - window->rect.width; - size_dy = h - window->rect.height; - - configure_frame_first = size_dx + size_dy >= 0; - } - - if (use_static_gravity) - meta_window_set_gravity (window, StaticGravity); - - if (configure_frame_first && window->frame) - frame_shape_changed = meta_frame_sync_to_window (window->frame, - gravity, - need_move_frame, need_resize_frame); - - values.border_width = 0; - values.x = client_move_x; - values.y = client_move_y; - values.width = window->rect.width; - values.height = window->rect.height; - - mask = 0; - if (is_configure_request && window->border_width != 0) - mask |= CWBorderWidth; /* must force to 0 */ - if (need_move_client) - mask |= (CWX | CWY); - if (need_resize_client) - mask |= (CWWidth | CWHeight); - - if (mask != 0) - { - { - int newx, newy; - meta_window_get_position (window, &newx, &newy); - meta_topic (META_DEBUG_GEOMETRY, - "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n", - newx, newy, - window->rect.width, window->rect.height, - mask & CWBorderWidth ? "true" : "false", - need_move_client ? "true" : "false", - need_resize_client ? "true" : "false"); - } - - meta_error_trap_push (window->display); - -#ifdef HAVE_XSYNC - if (window == window->display->grab_window && - meta_grab_op_is_resizing (window->display->grab_op) && - !window->disable_sync && - window->sync_request_counter != None && - window->sync_request_alarm != None && - window->sync_request_timeout_id == 0) - { - send_sync_request (window); - } -#endif - - XConfigureWindow (window->display->xdisplay, - window->xwindow, - mask, - &values); - - meta_error_trap_pop (window->display); - } - - if (!configure_frame_first && window->frame) - frame_shape_changed = meta_frame_sync_to_window (window->frame, - gravity, - need_move_frame, need_resize_frame); - - /* Put gravity back to be nice to lesser window managers */ - if (use_static_gravity) - meta_window_set_gravity (window, NorthWestGravity); - - if (need_configure_notify) - send_configure_notify (window); + /* Do the protocol-specific move/resize logic */ + META_WINDOW_GET_CLASS (window)->move_resize_internal (window, gravity, requested_rect, new_rect, flags, &result); if (!window->placed && window->force_save_user_rect && !window->fullscreen) force_save_user_window_placement (window); else if (is_user_action) save_user_window_placement (window); - if (need_move_client || need_move_frame) + if (result & META_MOVE_RESIZE_RESULT_MOVED) g_signal_emit (window, window_signals[POSITION_CHANGED], 0); - if (need_resize_client || need_resize_frame) + if (result & META_MOVE_RESIZE_RESULT_RESIZED) g_signal_emit (window, window_signals[SIZE_CHANGED], 0); - if (need_move_frame || need_resize_frame || - need_move_client || need_resize_client || - did_placement) + if ((result & (META_MOVE_RESIZE_RESULT_MOVED | META_MOVE_RESIZE_RESULT_RESIZED)) != 0 || + did_placement || is_wayland_resize) { int newx, newy; meta_window_get_position (window, &newx, &newy); @@ -5202,7 +4334,7 @@ meta_window_move_resize_internal (MetaWindow *window, newx, newy, window->rect.width, window->rect.height, window->user_rect.x, window->user_rect.y, window->user_rect.width, window->user_rect.height); - if (window->display->compositor) + if (window->known_to_compositor) meta_compositor_sync_window_geometry (window->display->compositor, window, did_placement); @@ -5222,7 +4354,7 @@ meta_window_move_resize_internal (MetaWindow *window, * b) all constraints are obeyed by window->rect and frame->rect */ - if (frame_shape_changed && window->frame_bounds) + if ((result & META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED) && window->frame_bounds) { cairo_region_destroy (window->frame_bounds); window->frame_bounds = NULL; @@ -5263,6 +4395,38 @@ meta_window_resize (MetaWindow *window, x, y, w, h); } +/* + * meta_window_move_resize_wayland: + * + * Complete a resize operation from a wayland client. + * + */ +void +meta_window_move_resize_wayland (MetaWindow *window, + int width, + int height, + int dx, + int dy) +{ + int x, y; + MetaMoveResizeFlags flags; + + flags = META_IS_WAYLAND_RESIZE; + + meta_window_get_position (window, &x, &y); + x += dx; y += dy; + + if (x != window->expected_rect.x || y != window->expected_rect.y) + flags |= META_IS_MOVE_ACTION; + if (width != window->expected_rect.width || + height != window->expected_rect.height) + flags |= META_IS_RESIZE_ACTION; + + meta_window_move_resize_internal (window, flags, NorthWestGravity, + x, y, width, height); + save_user_window_placement (window); +} + /** * meta_window_move: * @window: a #MetaWindow @@ -5493,40 +4657,6 @@ idle_move_resize (gpointer data) return FALSE; } -/** - * meta_window_configure_notify: (skip) - * @window: a #MetaWindow - * @event: a #XConfigureEvent - * - * This is used to notify us of an unrequested configuration - * (only applicable to override redirect windows) - */ -void -meta_window_configure_notify (MetaWindow *window, - XConfigureEvent *event) -{ - g_assert (window->override_redirect); - g_assert (window->frame == NULL); - - window->rect.x = event->x; - window->rect.y = event->y; - window->rect.width = event->width; - window->rect.height = event->height; - meta_window_update_monitor (window); - - /* Whether an override-redirect window is considered fullscreen depends - * on its geometry. - */ - if (window->override_redirect) - meta_screen_queue_check_fullscreen (window->screen); - - if (!event->override_redirect && !event->send_event) - meta_warning ("Unhandled change of windows override redirect status\n"); - - if (window->display->compositor) - meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE); -} - void meta_window_get_position (MetaWindow *window, int *x, @@ -5896,8 +5026,8 @@ get_modal_transient (MetaWindow *window) { MetaWindow *transient = tmp->data; - if (transient->xtransient_for == modal_transient->xwindow && - transient->wm_state_modal) + if (transient->transient_for == modal_transient && + transient->type == META_WINDOW_MODAL_DIALOG) { modal_transient = transient; tmp = windows; @@ -5962,69 +5092,7 @@ meta_window_focus (MetaWindow *window, return; } - /* For output-only or shaded windows, focus the frame. - * This seems to result in the client window getting key events - * though, so I don't know if it's icccm-compliant. - * - * Still, we have to do this or keynav breaks for these windows. - */ - if (window->frame && - (window->shaded || - !(window->input || window->take_focus))) - { - if (window->frame) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing frame of %s\n", window->desc); - meta_display_set_input_focus_window (window->display, - window, - TRUE, - timestamp); - } - } - else - { - if (window->input) - { - meta_topic (META_DEBUG_FOCUS, - "Setting input focus on %s since input = true\n", - window->desc); - meta_display_set_input_focus_window (window->display, - window, - FALSE, - timestamp); - } - - if (window->take_focus) - { - meta_topic (META_DEBUG_FOCUS, - "Sending WM_TAKE_FOCUS to %s since take_focus = true\n", - window->desc); - - if (!window->input) - { - /* The "Globally Active Input" window case, where the window - * doesn't want us to call XSetInputFocus on it, but does - * want us to send a WM_TAKE_FOCUS. - * - * Normally, we want to just leave the focus undisturbed until - * the window respnds to WM_TAKE_FOCUS, but if we're unmanaging - * the current focus window we *need* to move the focus away, so - * we focus the no_focus_window now (and set - * display->focus_window to that) before sending WM_TAKE_FOCUS. - */ - if (window->display->focus_window != NULL && - window->display->focus_window->unmanaging) - meta_display_focus_the_no_focus_window (window->display, - window->screen, - timestamp); - } - - meta_display_request_take_focus (window->display, - window, - timestamp); - } - } + META_WINDOW_GET_CLASS (window)->focus (window, timestamp); if (window->wm_state_demands_attention) meta_window_unset_demands_attention(window); @@ -6180,35 +5248,6 @@ meta_window_get_net_wm_desktop (MetaWindow *window) return meta_workspace_index (window->workspace); } -static void -update_net_frame_extents (MetaWindow *window) -{ - unsigned long data[4]; - MetaFrameBorders borders; - - meta_frame_calc_borders (window->frame, &borders); - /* Left */ - data[0] = borders.visible.left; - /* Right */ - data[1] = borders.visible.right; - /* Top */ - data[2] = borders.visible.top; - /* Bottom */ - data[3] = borders.visible.bottom; - - meta_topic (META_DEBUG_GEOMETRY, - "Setting _NET_FRAME_EXTENTS on managed window 0x%lx " - "to left = %lu, right = %lu, top = %lu, bottom = %lu\n", - window->xwindow, data[0], data[1], data[2], data[3]); - - meta_error_trap_push (window->display); - XChangeProperty (window->display->xdisplay, window->xwindow, - window->display->atom__NET_FRAME_EXTENTS, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 4); - meta_error_trap_pop (window->display); -} - void meta_window_set_current_workspace_hint (MetaWindow *window) { @@ -6325,42 +5364,6 @@ meta_window_lower (MetaWindow *window) meta_stack_lower (window->screen->stack, window); } -void -meta_window_send_icccm_message (MetaWindow *window, - Atom atom, - guint32 timestamp) -{ - /* This comment and code are from twm, copyright - * Open Group, Evans & Sutherland, etc. - */ - - /* - * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all - * client messages will have the following form: - * - * event type ClientMessage - * message type _XA_WM_PROTOCOLS - * window tmp->w - * format 32 - * data[0] message atom - * data[1] time stamp - */ - - XClientMessageEvent ev; - - ev.type = ClientMessage; - ev.window = window->xwindow; - ev.message_type = window->display->atom_WM_PROTOCOLS; - ev.format = 32; - ev.data.l[0] = atom; - ev.data.l[1] = timestamp; - - meta_error_trap_push (window->display); - XSendEvent (window->display->xdisplay, - window->xwindow, False, 0, (XEvent*) &ev); - meta_error_trap_pop (window->display); -} - void meta_window_move_resize_request (MetaWindow *window, guint value_mask, @@ -6526,97 +5529,6 @@ meta_window_move_resize_request (MetaWindow *window, save_user_window_placement (window); } -gboolean -meta_window_configure_request (MetaWindow *window, - XEvent *event) -{ - /* Note that x, y is the corner of the window border, - * and width, height is the size of the window inside - * its border, but that we always deny border requests - * and give windows a border of 0. But we save the - * requested border here. - */ - if (event->xconfigurerequest.value_mask & CWBorderWidth) - window->border_width = event->xconfigurerequest.border_width; - - meta_window_move_resize_request(window, - event->xconfigurerequest.value_mask, - window->size_hints.win_gravity, - event->xconfigurerequest.x, - event->xconfigurerequest.y, - event->xconfigurerequest.width, - event->xconfigurerequest.height); - - /* Handle stacking. We only handle raises/lowers, mostly because - * stack.c really can't deal with anything else. I guess we'll fix - * that if a client turns up that really requires it. Only a very - * few clients even require the raise/lower (and in fact all client - * attempts to deal with stacking order are essentially broken, - * since they have no idea what other clients are involved or how - * the stack looks). - * - * I'm pretty sure no interesting client uses TopIf, BottomIf, or - * Opposite anyway, so the only possible missing thing is - * Above/Below with a sibling set. For now we just pretend there's - * never a sibling set and always do the full raise/lower instead of - * the raise-just-above/below-sibling. - */ - if (event->xconfigurerequest.value_mask & CWStackMode) - { - MetaWindow *active_window; - active_window = window->display->focus_window; - if (meta_prefs_get_disable_workarounds ()) - { - meta_topic (META_DEBUG_STACK, - "%s sent an xconfigure stacking request; this is " - "broken behavior and the request is being ignored.\n", - window->desc); - } - else if (active_window && - !meta_window_same_application (window, active_window) && - !meta_window_same_client (window, active_window) && - XSERVER_TIME_IS_BEFORE (window->net_wm_user_time, - active_window->net_wm_user_time)) - { - meta_topic (META_DEBUG_STACK, - "Ignoring xconfigure stacking request from %s (with " - "user_time %u); currently active application is %s (with " - "user_time %u).\n", - window->desc, - window->net_wm_user_time, - active_window->desc, - active_window->net_wm_user_time); - if (event->xconfigurerequest.detail == Above) - meta_window_set_demands_attention(window); - } - else - { - switch (event->xconfigurerequest.detail) - { - case Above: - meta_window_raise (window); - break; - case Below: - meta_window_lower (window); - break; - case TopIf: - case BottomIf: - case Opposite: - break; - } - } - } - - return TRUE; -} - -gboolean -meta_window_property_notify (MetaWindow *window, - XEvent *event) -{ - return process_property_notify (window, &event->xproperty); -} - /* * Move window to the requested workspace; append controls whether new WS * should be created if one does not exist. @@ -6654,531 +5566,6 @@ meta_window_change_workspace_by_index (MetaWindow *window, } } -#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 -#define _NET_WM_MOVERESIZE_SIZE_TOP 1 -#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 -#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 -#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 -#define _NET_WM_MOVERESIZE_MOVE 8 -#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 -#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 -#define _NET_WM_MOVERESIZE_CANCEL 11 - -static int -query_pressed_buttons (MetaWindow *window) -{ - double x, y, query_root_x, query_root_y; - Window root, child; - XIButtonState buttons; - XIModifierState mods; - XIGroupState group; - int button = 0; - - meta_error_trap_push (window->display); - XIQueryPointer (window->display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - window->xwindow, - &root, &child, - &query_root_x, &query_root_y, - &x, &y, - &buttons, &mods, &group); - - if (meta_error_trap_pop_with_return (window->display) != Success) - goto out; - - if (XIMaskIsSet (buttons.mask, Button1)) - button |= 1 << 1; - if (XIMaskIsSet (buttons.mask, Button2)) - button |= 1 << 2; - if (XIMaskIsSet (buttons.mask, Button3)) - button |= 1 << 3; - - free (buttons.mask); - - out: - return button; -} - -gboolean -meta_window_client_message (MetaWindow *window, - XEvent *event) -{ - MetaDisplay *display; - - display = window->display; - - if (window->override_redirect) - { - /* Don't warn here: we could warn on any of the messages below, - * but we might also receive other client messages that are - * part of protocols we don't know anything about. So, silently - * ignoring is simplest. - */ - return FALSE; - } - - if (event->xclient.message_type == - display->atom__NET_CLOSE_WINDOW) - { - guint32 timestamp; - - if (event->xclient.data.l[0] != 0) - timestamp = event->xclient.data.l[0]; - else - { - meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without " - "a timestamp! This means some buggy (outdated) " - "application is on the loose!\n", - window->desc); - timestamp = meta_display_get_current_time (window->display); - } - - meta_window_delete (window, timestamp); - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_DESKTOP) - { - int space; - MetaWorkspace *workspace; - - space = event->xclient.data.l[0]; - - meta_verbose ("Request to move %s to workspace %d\n", - window->desc, space); - - workspace = - meta_screen_get_workspace_by_index (window->screen, - space); - - if (workspace) - { - if (window->on_all_workspaces_requested) - meta_window_unstick (window); - meta_window_change_workspace (window, workspace); - } - else if (space == (int) 0xFFFFFFFF) - { - meta_window_stick (window); - } - else - { - meta_verbose ("No such workspace %d for screen\n", space); - } - - meta_verbose ("Window %s now on_all_workspaces = %d\n", - window->desc, window->on_all_workspaces); - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_STATE) - { - gulong action; - Atom first; - Atom second; - - action = event->xclient.data.l[0]; - first = event->xclient.data.l[1]; - second = event->xclient.data.l[2]; - - if (meta_is_verbose ()) - { - char *str1; - char *str2; - - meta_error_trap_push_with_return (display); - str1 = XGetAtomName (display->xdisplay, first); - if (meta_error_trap_pop_with_return (display) != Success) - str1 = NULL; - - meta_error_trap_push_with_return (display); - str2 = XGetAtomName (display->xdisplay, second); - if (meta_error_trap_pop_with_return (display) != Success) - str2 = NULL; - - meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n", - action, - str1 ? str1 : "(unknown)", - str2 ? str2 : "(unknown)"); - - meta_XFree (str1); - meta_XFree (str2); - } - - if (first == display->atom__NET_WM_STATE_SHADED || - second == display->atom__NET_WM_STATE_SHADED) - { - gboolean shade; - guint32 timestamp; - - /* Stupid protocol has no timestamp; of course, shading - * sucks anyway so who really cares that we're forced to do - * a roundtrip here? - */ - timestamp = meta_display_get_current_time_roundtrip (window->display); - - shade = (action == _NET_WM_STATE_ADD || - (action == _NET_WM_STATE_TOGGLE && !window->shaded)); - if (shade && window->has_shade_func) - meta_window_shade (window, timestamp); - else - meta_window_unshade (window, timestamp); - } - - if (first == display->atom__NET_WM_STATE_FULLSCREEN || - second == display->atom__NET_WM_STATE_FULLSCREEN) - { - gboolean make_fullscreen; - - make_fullscreen = (action == _NET_WM_STATE_ADD || - (action == _NET_WM_STATE_TOGGLE && !window->fullscreen)); - if (make_fullscreen && window->has_fullscreen_func) - meta_window_make_fullscreen (window); - else - meta_window_unmake_fullscreen (window); - } - - if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || - second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || - first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || - second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) - { - gboolean max; - MetaMaximizeFlags directions = 0; - - max = (action == _NET_WM_STATE_ADD || - (action == _NET_WM_STATE_TOGGLE && - !window->maximized_horizontally)); - - if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || - second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ) - directions |= META_MAXIMIZE_HORIZONTAL; - - if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || - second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) - directions |= META_MAXIMIZE_VERTICAL; - - if (max && window->has_maximize_func) - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_maximize (window, directions); - } - else - { - if (meta_prefs_get_raise_on_click ()) - meta_window_raise (window); - meta_window_unmaximize (window, directions); - } - } - - if (first == display->atom__NET_WM_STATE_MODAL || - second == display->atom__NET_WM_STATE_MODAL) - { - window->wm_state_modal = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal); - - recalc_window_type (window); - meta_window_queue(window, META_QUEUE_MOVE_RESIZE); - } - - if (first == display->atom__NET_WM_STATE_SKIP_PAGER || - second == display->atom__NET_WM_STATE_SKIP_PAGER) - { - window->wm_state_skip_pager = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->skip_pager); - - recalc_window_features (window); - set_net_wm_state (window); - } - - if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR || - second == display->atom__NET_WM_STATE_SKIP_TASKBAR) - { - window->wm_state_skip_taskbar = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar); - - recalc_window_features (window); - set_net_wm_state (window); - } - - if (first == display->atom__NET_WM_STATE_ABOVE || - second == display->atom__NET_WM_STATE_ABOVE) - { - meta_window_set_above(window, - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_above)); - } - - if (first == display->atom__NET_WM_STATE_BELOW || - second == display->atom__NET_WM_STATE_BELOW) - { - window->wm_state_below = - (action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below); - - meta_window_update_layer (window); - set_net_wm_state (window); - } - - if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION || - second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION) - { - if ((action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) - meta_window_set_demands_attention (window); - else - meta_window_unset_demands_attention (window); - } - - if (first == display->atom__NET_WM_STATE_STICKY || - second == display->atom__NET_WM_STATE_STICKY) - { - if ((action == _NET_WM_STATE_ADD) || - (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested)) - meta_window_stick (window); - else - meta_window_unstick (window); - } - - return TRUE; - } - else if (event->xclient.message_type == - display->atom_WM_CHANGE_STATE) - { - meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n", - event->xclient.data.l[0]); - if (event->xclient.data.l[0] == IconicState && - window->has_minimize_func) - meta_window_minimize (window); - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_MOVERESIZE) - { - int x_root; - int y_root; - int action; - MetaGrabOp op; - int button; - guint32 timestamp; - - /* _NET_WM_MOVERESIZE messages are almost certainly going to come from - * clients when users click on the fake "frame" that the client has, - * thus we should also treat such messages as though it were a - * "frame action". - */ - gboolean const frame_action = TRUE; - - x_root = event->xclient.data.l[0]; - y_root = event->xclient.data.l[1]; - action = event->xclient.data.l[2]; - button = event->xclient.data.l[3]; - - /* FIXME: What a braindead protocol; no timestamp?!? */ - timestamp = meta_display_get_current_time_roundtrip (display); - meta_topic (META_DEBUG_WINDOW_OPS, - "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n", - window->desc, - x_root, y_root, action, button); - - op = META_GRAB_OP_NONE; - switch (action) - { - case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: - op = META_GRAB_OP_RESIZING_NW; - break; - case _NET_WM_MOVERESIZE_SIZE_TOP: - op = META_GRAB_OP_RESIZING_N; - break; - case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: - op = META_GRAB_OP_RESIZING_NE; - break; - case _NET_WM_MOVERESIZE_SIZE_RIGHT: - op = META_GRAB_OP_RESIZING_E; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: - op = META_GRAB_OP_RESIZING_SE; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOM: - op = META_GRAB_OP_RESIZING_S; - break; - case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: - op = META_GRAB_OP_RESIZING_SW; - break; - case _NET_WM_MOVERESIZE_SIZE_LEFT: - op = META_GRAB_OP_RESIZING_W; - break; - case _NET_WM_MOVERESIZE_MOVE: - op = META_GRAB_OP_MOVING; - break; - case _NET_WM_MOVERESIZE_SIZE_KEYBOARD: - op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN; - break; - case _NET_WM_MOVERESIZE_MOVE_KEYBOARD: - op = META_GRAB_OP_KEYBOARD_MOVING; - break; - case _NET_WM_MOVERESIZE_CANCEL: - /* handled below */ - break; - default: - break; - } - - if (action == _NET_WM_MOVERESIZE_CANCEL) - { - meta_display_end_grab_op (window->display, timestamp); - } - else if (op != META_GRAB_OP_NONE && - ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) || - (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN))) - { - meta_window_begin_grab_op (window, op, frame_action, timestamp); - } - else if (op != META_GRAB_OP_NONE && - ((window->has_move_func && op == META_GRAB_OP_MOVING) || - (window->has_resize_func && - (op != META_GRAB_OP_MOVING && - op != META_GRAB_OP_KEYBOARD_MOVING)))) - { - int button_mask; - - meta_topic (META_DEBUG_WINDOW_OPS, - "Beginning move/resize with button = %d\n", button); - meta_display_begin_grab_op (window->display, - window->screen, - window, - op, - FALSE, - frame_action, - button, 0, - timestamp, - x_root, - y_root); - - button_mask = query_pressed_buttons (window); - - if (button == 0) - { - /* - * the button SHOULD already be included in the message - */ - if ((button_mask & (1 << 1)) != 0) - button = 1; - else if ((button_mask & (1 << 2)) != 0) - button = 2; - else if ((button_mask & (1 << 3)) != 0) - button = 3; - - if (button != 0) - window->display->grab_button = button; - else - meta_display_end_grab_op (window->display, - timestamp); - } - else - { - /* There is a potential race here. If the user presses and - * releases their mouse button very fast, it's possible for - * both the ButtonPress and ButtonRelease to be sent to the - * client before it can get a chance to send _NET_WM_MOVERESIZE - * to us. When that happens, we'll become stuck in a grab - * state, as we haven't received a ButtonRelease to cancel the - * grab. - * - * We can solve this by querying after we take the explicit - * pointer grab -- if the button isn't pressed, we cancel the - * drag immediately. - */ - - if ((button_mask & (1 << button)) == 0) - meta_display_end_grab_op (window->display, timestamp); - } - } - - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_MOVERESIZE_WINDOW) - { - int gravity; - guint value_mask; - - gravity = (event->xclient.data.l[0] & 0xff); - value_mask = (event->xclient.data.l[0] & 0xf00) >> 8; - /* source = (event->xclient.data.l[0] & 0xf000) >> 12; */ - - if (gravity == 0) - gravity = window->size_hints.win_gravity; - - meta_window_move_resize_request(window, - value_mask, - gravity, - event->xclient.data.l[1], /* x */ - event->xclient.data.l[2], /* y */ - event->xclient.data.l[3], /* width */ - event->xclient.data.l[4]); /* height */ - } - else if (event->xclient.message_type == - display->atom__NET_ACTIVE_WINDOW) - { - MetaClientType source_indication; - guint32 timestamp; - - meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating\n", - window->desc); - - source_indication = event->xclient.data.l[0]; - timestamp = event->xclient.data.l[1]; - - if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED) - source_indication = META_CLIENT_TYPE_UNKNOWN; - - if (timestamp == 0) - { - /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */ - meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a " - "timestamp of 0 for %s\n", - window->desc); - timestamp = meta_display_get_current_time (display); - } - - window_activate (window, timestamp, source_indication, NULL); - return TRUE; - } - else if (event->xclient.message_type == - display->atom__NET_WM_FULLSCREEN_MONITORS) - { - gulong top, bottom, left, right; - - meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", - window->desc); - - top = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[0]); - bottom = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[1]); - left = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[2]); - right = meta_screen_xinerama_index_to_monitor_index (window->screen, - event->xclient.data.l[3]); - /* source_indication = event->xclient.data.l[4]; */ - - meta_window_update_fullscreen_monitors (window, top, bottom, left, right); - } - - return FALSE; -} - static void meta_window_appears_focused_changed (MetaWindow *window) { @@ -7189,6 +5576,14 @@ meta_window_appears_focused_changed (MetaWindow *window) if (window->frame) meta_frame_queue_draw (window->frame); + + if (window->surface) + { + if (meta_window_appears_focused (window)) + meta_wayland_surface_activated (window->surface); + else + meta_wayland_surface_deactivated (window->surface); + } } /** @@ -7283,11 +5678,6 @@ meta_window_set_focused_internal (MetaWindow *window, if (window->frame) meta_frame_queue_draw (window->frame); - meta_error_trap_push (window->display); - XInstallColormap (window->display->xdisplay, - window->colormap); - meta_error_trap_pop (window->display); - /* move into FOCUSED_WINDOW layer */ meta_window_update_layer (window); @@ -7326,11 +5716,6 @@ meta_window_set_focused_internal (MetaWindow *window, if (!window->attached_focus_window) meta_window_appears_focused_changed (window); - meta_error_trap_push (window->display); - XUninstallColormap (window->display->xdisplay, - window->colormap); - meta_error_trap_pop (window->display); - /* move out of FOCUSED_WINDOW layer */ meta_window_update_layer (window); @@ -7341,86 +5726,6 @@ meta_window_set_focused_internal (MetaWindow *window, } } -static gboolean -process_property_notify (MetaWindow *window, - XPropertyEvent *event) -{ - Window xid = window->xwindow; - - if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */ - { - char *property_name = XGetAtomName (window->display->xdisplay, - event->atom); - - meta_verbose ("Property notify on %s for %s\n", - window->desc, property_name); - XFree (property_name); - } - - if (event->atom == window->display->atom__NET_WM_USER_TIME && - window->user_time_window) - { - xid = window->user_time_window; - } - - meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE); - - return TRUE; -} - -static void -send_configure_notify (MetaWindow *window) -{ - XEvent event; - - /* from twm */ - - event.type = ConfigureNotify; - event.xconfigure.display = window->display->xdisplay; - event.xconfigure.event = window->xwindow; - event.xconfigure.window = window->xwindow; - event.xconfigure.x = window->rect.x - window->border_width; - event.xconfigure.y = window->rect.y - window->border_width; - if (window->frame) - { - if (window->withdrawn) - { - MetaFrameBorders borders; - /* We reparent the client window and put it to the position - * where the visible top-left of the frame window currently is. - */ - - meta_frame_calc_borders (window->frame, &borders); - - event.xconfigure.x = window->frame->rect.x + borders.invisible.left; - event.xconfigure.y = window->frame->rect.y + borders.invisible.top; - } - else - { - /* Need to be in root window coordinates */ - event.xconfigure.x += window->frame->rect.x; - event.xconfigure.y += window->frame->rect.y; - } - } - event.xconfigure.width = window->rect.width; - event.xconfigure.height = window->rect.height; - event.xconfigure.border_width = window->border_width; /* requested not actual */ - event.xconfigure.above = None; /* FIXME */ - event.xconfigure.override_redirect = False; - - meta_topic (META_DEBUG_GEOMETRY, - "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n", - window->desc, - event.xconfigure.x, event.xconfigure.y, - event.xconfigure.width, event.xconfigure.height); - - meta_error_trap_push (window->display); - XSendEvent (window->display->xdisplay, - window->xwindow, - False, StructureNotifyMask, &event); - meta_error_trap_pop (window->display); -} - /** * meta_window_get_icon_geometry: * @window: a #MetaWindow @@ -7473,448 +5778,6 @@ meta_window_set_icon_geometry (MetaWindow *window, } } -static Window -read_client_leader (MetaDisplay *display, - Window xwindow) -{ - Window retval = None; - - meta_prop_get_window (display, xwindow, - display->atom_WM_CLIENT_LEADER, - &retval); - - return retval; -} - -typedef struct -{ - Window leader; -} ClientLeaderData; - -static gboolean -find_client_leader_func (MetaWindow *ancestor, - void *data) -{ - ClientLeaderData *d; - - d = data; - - d->leader = read_client_leader (ancestor->display, - ancestor->xwindow); - - /* keep going if no client leader found */ - return d->leader == None; -} - -static void -update_sm_hints (MetaWindow *window) -{ - Window leader; - - window->xclient_leader = None; - window->sm_client_id = NULL; - - /* If not on the current window, we can get the client - * leader from transient parents. If we find a client - * leader, we read the SM_CLIENT_ID from it. - */ - leader = read_client_leader (window->display, window->xwindow); - if (leader == None) - { - ClientLeaderData d; - d.leader = None; - meta_window_foreach_ancestor (window, find_client_leader_func, - &d); - leader = d.leader; - } - - if (leader != None) - { - char *str; - - window->xclient_leader = leader; - - if (meta_prop_get_latin1_string (window->display, leader, - window->display->atom_SM_CLIENT_ID, - &str)) - { - window->sm_client_id = g_strdup (str); - meta_XFree (str); - } - } - else - { - meta_verbose ("Didn't find a client leader for %s\n", window->desc); - - if (!meta_prefs_get_disable_workarounds ()) - { - /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app - * instead of the client leader - */ - char *str; - - str = NULL; - if (meta_prop_get_latin1_string (window->display, window->xwindow, - window->display->atom_SM_CLIENT_ID, - &str)) - { - if (window->sm_client_id == NULL) /* first time through */ - meta_warning (_("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n"), - window->desc); - - window->sm_client_id = g_strdup (str); - meta_XFree (str); - } - } - } - - meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n", - window->desc, window->xclient_leader, - window->sm_client_id ? window->sm_client_id : "none"); -} - -void -meta_window_update_role (MetaWindow *window) -{ - char *str; - - g_return_if_fail (!window->override_redirect); - - if (window->role) - g_free (window->role); - window->role = NULL; - - if (meta_prop_get_latin1_string (window->display, window->xwindow, - window->display->atom_WM_WINDOW_ROLE, - &str)) - { - window->role = g_strdup (str); - meta_XFree (str); - } - - meta_verbose ("Updated role of %s to '%s'\n", - window->desc, window->role ? window->role : "null"); -} - -void -meta_window_update_net_wm_type (MetaWindow *window) -{ - int n_atoms; - Atom *atoms; - int i; - - window->type_atom = None; - n_atoms = 0; - atoms = NULL; - - meta_prop_get_atom_list (window->display, window->xwindow, - window->display->atom__NET_WM_WINDOW_TYPE, - &atoms, &n_atoms); - - i = 0; - while (i < n_atoms) - { - /* We break as soon as we find one we recognize, - * supposed to prefer those near the front of the list - */ - if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG || - atoms[i] == - window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP || - atoms[i] == - window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_COMBO || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DND || - atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) - { - window->type_atom = atoms[i]; - break; - } - - ++i; - } - - meta_XFree (atoms); - - if (meta_is_verbose ()) - { - char *str; - - str = NULL; - if (window->type_atom != None) - { - meta_error_trap_push (window->display); - str = XGetAtomName (window->display->xdisplay, window->type_atom); - meta_error_trap_pop (window->display); - } - - meta_verbose ("Window %s type atom %s\n", window->desc, - str ? str : "(none)"); - - if (str) - meta_XFree (str); - } - - meta_window_recalc_window_type (window); -} - -static void -meta_window_set_opaque_region (MetaWindow *window, - cairo_region_t *region) -{ - g_clear_pointer (&window->opaque_region, cairo_region_destroy); - - if (region != NULL) - window->opaque_region = cairo_region_reference (region); - - if (window->display->compositor) - meta_compositor_window_shape_changed (window->display->compositor, window); -} - -void -meta_window_update_opaque_region_x11 (MetaWindow *window) -{ - cairo_region_t *opaque_region = NULL; - gulong *region = NULL; - int nitems; - - if (meta_prop_get_cardinal_list (window->display, - window->xwindow, - window->display->atom__NET_WM_OPAQUE_REGION, - ®ion, &nitems)) - { - cairo_rectangle_int_t *rects; - int i, rect_index, nrects; - - if (nitems % 4 != 0) - { - meta_verbose ("_NET_WM_OPAQUE_REGION does not have a list of 4-tuples."); - goto out; - } - - /* empty region */ - if (nitems == 0) - goto out; - - nrects = nitems / 4; - - rects = g_new (cairo_rectangle_int_t, nrects); - - rect_index = 0; - i = 0; - while (i < nitems) - { - cairo_rectangle_int_t *rect = &rects[rect_index]; - - rect->x = region[i++]; - rect->y = region[i++]; - rect->width = region[i++]; - rect->height = region[i++]; - - rect_index++; - } - - opaque_region = cairo_region_create_rectangles (rects, nrects); - - g_free (rects); - } - - out: - meta_XFree (region); - - meta_window_set_opaque_region (window, opaque_region); - cairo_region_destroy (opaque_region); -} - -static cairo_region_t * -region_create_from_x_rectangles (const XRectangle *rects, - int n_rects) -{ - int i; - cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects); - - for (i = 0; i < n_rects; i ++) - { - cairo_rects[i].x = rects[i].x; - cairo_rects[i].y = rects[i].y; - cairo_rects[i].width = rects[i].width; - cairo_rects[i].height = rects[i].height; - } - - return cairo_region_create_rectangles (cairo_rects, n_rects); -} - -static void -meta_window_set_input_region (MetaWindow *window, - cairo_region_t *region) -{ - g_clear_pointer (&window->input_region, cairo_region_destroy); - - if (region != NULL) - window->input_region = cairo_region_reference (region); - - if (window->display->compositor) - meta_compositor_window_shape_changed (window->display->compositor, window); -} - -void -meta_window_update_input_region_x11 (MetaWindow *window) -{ - cairo_region_t *region = NULL; - - /* Decorated windows don't have an input region, because - we don't shape the frame to match the client windows - (so the events are blocked by the frame anyway) - */ - if (window->decorated) - { - if (window->input_region) - meta_window_set_input_region (window, NULL); - return; - } - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (window->display)) - { - /* Translate the set of XShape rectangles that we - * get from the X server to a cairo_region. */ - XRectangle *rects = NULL; - int n_rects, ordering; - - meta_error_trap_push (window->display); - rects = XShapeGetRectangles (window->display->xdisplay, - window->xwindow, - ShapeInput, - &n_rects, - &ordering); - meta_error_trap_pop (window->display); - - /* XXX: The x shape extension doesn't provide a way to only test if an - * input shape has been specified, so we have to query and throw away the - * rectangles. */ - if (rects) - { - if (n_rects > 1 || - (n_rects == 1 && - (rects[0].x != 0 || - rects[0].y != 0 || - rects[0].width != window->rect.width || - rects[0].height != window->rect.height))) - region = region_create_from_x_rectangles (rects, n_rects); - - XFree (rects); - } - } -#endif /* HAVE_SHAPE */ - - if (region != NULL) - { - cairo_rectangle_int_t client_area; - - client_area.x = 0; - client_area.y = 0; - client_area.width = window->rect.width; - client_area.height = window->rect.height; - - /* The shape we get back from the client may have coordinates - * outside of the frame. The X SHAPE Extension requires that - * the overall shape the client provides never exceeds the - * "bounding rectangle" of the window -- the shape that the - * window would have gotten if it was unshaped. In our case, - * this is simply the client area. - */ - cairo_region_intersect_rectangle (region, &client_area); - } - - meta_window_set_input_region (window, region); - cairo_region_destroy (region); -} - -static void -meta_window_set_shape_region (MetaWindow *window, - cairo_region_t *region) -{ - g_clear_pointer (&window->shape_region, cairo_region_destroy); - - if (region != NULL) - window->shape_region = cairo_region_reference (region); - - if (window->display->compositor) - meta_compositor_window_shape_changed (window->display->compositor, window); -} - -void -meta_window_update_shape_region_x11 (MetaWindow *window) -{ - cairo_region_t *region = NULL; - -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (window->display)) - { - /* Translate the set of XShape rectangles that we - * get from the X server to a cairo_region. */ - XRectangle *rects = NULL; - int n_rects, ordering; - - int x_bounding, y_bounding, x_clip, y_clip; - unsigned w_bounding, h_bounding, w_clip, h_clip; - int bounding_shaped, clip_shaped; - - meta_error_trap_push (window->display); - XShapeQueryExtents (window->display->xdisplay, window->xwindow, - &bounding_shaped, &x_bounding, &y_bounding, - &w_bounding, &h_bounding, - &clip_shaped, &x_clip, &y_clip, - &w_clip, &h_clip); - - if (bounding_shaped) - { - rects = XShapeGetRectangles (window->display->xdisplay, - window->xwindow, - ShapeBounding, - &n_rects, - &ordering); - } - meta_error_trap_pop (window->display); - - if (rects) - { - region = region_create_from_x_rectangles (rects, n_rects); - XFree (rects); - } - } -#endif - - if (region != NULL) - { - cairo_rectangle_int_t client_area; - - client_area.x = 0; - client_area.y = 0; - client_area.width = window->rect.width; - client_area.height = window->rect.height; - - /* The shape we get back from the client may have coordinates - * outside of the frame. The X SHAPE Extension requires that - * the overall shape the client provides never exceeds the - * "bounding rectangle" of the window -- the shape that the - * window would have gotten if it was unshaped. In our case, - * this is simply the client area. - */ - cairo_region_intersect_rectangle (region, &client_area); - } - - meta_window_set_shape_region (window, region); - cairo_region_destroy (region); -} - static void redraw_icon (MetaWindow *window) { @@ -8207,154 +6070,48 @@ meta_window_update_struts (MetaWindow *window) } } -void -meta_window_recalc_window_type (MetaWindow *window) +static void +meta_window_type_changed (MetaWindow *window) { - recalc_window_type (window); + gboolean old_decorated = window->decorated; + GObject *object = G_OBJECT (window); + + window->attached = meta_window_should_attach_to_parent (window); + meta_window_recalc_features (window); + + if (!window->override_redirect) + set_net_wm_state (window); + + /* Update frame */ + if (window->decorated) + meta_window_ensure_frame (window); + else + meta_window_destroy_frame (window); + + /* update stacking constraints */ + meta_window_update_layer (window); + + meta_window_grab_keys (window); + + g_object_freeze_notify (object); + + if (old_decorated != window->decorated) + g_object_notify (object, "decorated"); + + g_object_notify (object, "window-type"); + + g_object_thaw_notify (object); } -static void -recalc_window_type (MetaWindow *window) +void +meta_window_set_type (MetaWindow *window, + MetaWindowType type) { - MetaWindowType old_type; + if (window->type == type) + return; - old_type = window->type; - - if (window->type_atom != None) - { - if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP) - window->type = META_WINDOW_DESKTOP; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK) - window->type = META_WINDOW_DOCK; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR) - window->type = META_WINDOW_TOOLBAR; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU) - window->type = META_WINDOW_MENU; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY) - window->type = META_WINDOW_UTILITY; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH) - window->type = META_WINDOW_SPLASHSCREEN; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG) - window->type = META_WINDOW_DIALOG; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) - window->type = META_WINDOW_NORMAL; - /* The below are *typically* override-redirect windows, but the spec does - * not disallow using them for managed windows. - */ - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) - window->type = META_WINDOW_DROPDOWN_MENU; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU) - window->type = META_WINDOW_POPUP_MENU; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP) - window->type = META_WINDOW_TOOLTIP; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION) - window->type = META_WINDOW_NOTIFICATION; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO) - window->type = META_WINDOW_COMBO; - else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND) - window->type = META_WINDOW_DND; - else - { - char *atom_name; - - /* - * Fallback on a normal type, and print warning. Don't abort. - */ - window->type = META_WINDOW_NORMAL; - - meta_error_trap_push (window->display); - atom_name = XGetAtomName (window->display->xdisplay, - window->type_atom); - meta_error_trap_pop (window->display); - - meta_warning ("Unrecognized type atom [%s] set for %s \n", - atom_name ? atom_name : "unknown", - window->desc); - - if (atom_name) - XFree (atom_name); - } - } - else if (window->xtransient_for != None) - { - window->type = META_WINDOW_DIALOG; - } - else - { - window->type = META_WINDOW_NORMAL; - } - - if (window->type == META_WINDOW_DIALOG && - window->wm_state_modal) - window->type = META_WINDOW_MODAL_DIALOG; - - /* We don't want to allow override-redirect windows to have decorated-window - * types since that's just confusing. - */ - if (window->override_redirect) - { - switch (window->type) - { - /* Decorated types */ - case META_WINDOW_NORMAL: - case META_WINDOW_DIALOG: - case META_WINDOW_MODAL_DIALOG: - case META_WINDOW_MENU: - case META_WINDOW_UTILITY: - window->type = META_WINDOW_OVERRIDE_OTHER; - break; - /* Undecorated types, normally not override-redirect */ - case META_WINDOW_DESKTOP: - case META_WINDOW_DOCK: - case META_WINDOW_TOOLBAR: - case META_WINDOW_SPLASHSCREEN: - /* Undecorated types, normally override-redirect types */ - case META_WINDOW_DROPDOWN_MENU: - case META_WINDOW_POPUP_MENU: - case META_WINDOW_TOOLTIP: - case META_WINDOW_NOTIFICATION: - case META_WINDOW_COMBO: - case META_WINDOW_DND: - /* To complete enum */ - case META_WINDOW_OVERRIDE_OTHER: - break; - } - } - - meta_verbose ("Calculated type %u for %s, old type %u\n", - window->type, window->desc, old_type); - - if (old_type != window->type) - { - gboolean old_decorated = window->decorated; - GObject *object = G_OBJECT (window); - - window->attached = meta_window_should_attach_to_parent (window); - recalc_window_features (window); - - if (!window->override_redirect) - set_net_wm_state (window); - - /* Update frame */ - if (window->decorated) - meta_window_ensure_frame (window); - else - meta_window_destroy_frame (window); - - /* update stacking constraints */ - meta_window_update_layer (window); - - meta_window_grab_keys (window); - - g_object_freeze_notify (object); - - if (old_decorated != window->decorated) - g_object_notify (object, "decorated"); - - g_object_notify (object, "window-type"); - - g_object_thaw_notify (object); - } + window->type = type; + meta_window_type_changed (window); } void @@ -8435,14 +6192,60 @@ set_allowed_actions_hint (MetaWindow *window) #undef MAX_N_ACTIONS } -void -meta_window_recalc_features (MetaWindow *window) +static void +meta_window_get_default_skip_hints (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out) { - recalc_window_features (window); + META_WINDOW_GET_CLASS (window)->get_default_skip_hints (window, skip_taskbar_out, skip_pager_out); } static void -recalc_window_features (MetaWindow *window) +meta_window_recalc_skip_features (MetaWindow *window) +{ + switch (window->type) + { + /* Force skip taskbar/pager on these window types */ + case META_WINDOW_DESKTOP: + case META_WINDOW_DOCK: + case META_WINDOW_TOOLBAR: + case META_WINDOW_MENU: + case META_WINDOW_UTILITY: + case META_WINDOW_SPLASHSCREEN: + case META_WINDOW_DROPDOWN_MENU: + case META_WINDOW_POPUP_MENU: + case META_WINDOW_TOOLTIP: + case META_WINDOW_NOTIFICATION: + case META_WINDOW_COMBO: + case META_WINDOW_DND: + case META_WINDOW_OVERRIDE_OTHER: + window->skip_taskbar = TRUE; + window->skip_pager = TRUE; + break; + + case META_WINDOW_DIALOG: + case META_WINDOW_MODAL_DIALOG: + /* only skip taskbar if we have a real transient parent + (and ignore the application hints) */ + if (window->transient_for != NULL) + window->skip_taskbar = TRUE; + else + window->skip_taskbar = FALSE; + break; + + case META_WINDOW_NORMAL: + { + gboolean skip_taskbar_hint, skip_pager_hint; + meta_window_get_default_skip_hints (window, &skip_taskbar_hint, &skip_pager_hint); + window->skip_taskbar = skip_taskbar_hint; + window->skip_pager = skip_pager_hint; + } + break; + } +} + +void +meta_window_recalc_features (MetaWindow *window) { gboolean old_has_close_func; gboolean old_has_minimize_func; @@ -8461,7 +6264,10 @@ recalc_window_features (MetaWindow *window) old_skip_taskbar = window->skip_taskbar; /* Use MWM hints initially */ - window->decorated = window->mwm_decorated; + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + window->decorated = window->mwm_decorated; + else + window->decorated = FALSE; window->border_only = window->mwm_border_only; window->has_close_func = window->mwm_has_close_func; window->has_minimize_func = window->mwm_has_minimize_func; @@ -8484,7 +6290,7 @@ recalc_window_features (MetaWindow *window) * about these apps but make them work. */ - meta_warning (_("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n"), + meta_warning ("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n", window->desc, window->size_hints.min_width, window->size_hints.min_height, @@ -8589,49 +6395,7 @@ recalc_window_features (MetaWindow *window) if (!window->decorated || window->border_only) window->has_shade_func = FALSE; - window->skip_taskbar = FALSE; - window->skip_pager = FALSE; - - if (window->wm_state_skip_taskbar) - window->skip_taskbar = TRUE; - - if (window->wm_state_skip_pager) - window->skip_pager = TRUE; - - switch (window->type) - { - /* Force skip taskbar/pager on these window types */ - case META_WINDOW_DESKTOP: - case META_WINDOW_DOCK: - case META_WINDOW_TOOLBAR: - case META_WINDOW_MENU: - case META_WINDOW_UTILITY: - case META_WINDOW_SPLASHSCREEN: - case META_WINDOW_DROPDOWN_MENU: - case META_WINDOW_POPUP_MENU: - case META_WINDOW_TOOLTIP: - case META_WINDOW_NOTIFICATION: - case META_WINDOW_COMBO: - case META_WINDOW_DND: - case META_WINDOW_OVERRIDE_OTHER: - window->skip_taskbar = TRUE; - window->skip_pager = TRUE; - break; - - case META_WINDOW_DIALOG: - case META_WINDOW_MODAL_DIALOG: - /* only skip taskbar if we have a real transient parent - (and ignore the application hints) */ - if (window->xtransient_for != None && - window->xtransient_for != window->screen->xroot) - window->skip_taskbar = TRUE; - else - window->skip_taskbar = FALSE; - break; - - case META_WINDOW_NORMAL: - break; - } + meta_window_recalc_skip_features (window); meta_topic (META_DEBUG_WINDOW_OPS, "Window %s decorated = %d border_only = %d has_close = %d has_minimize = %d has_maximize = %d has_move = %d has_shade = %d skip_taskbar = %d skip_pager = %d\n", @@ -8650,10 +6414,9 @@ recalc_window_features (MetaWindow *window) g_object_notify (G_OBJECT (window), "skip-taskbar"); /* FIXME: - * Lame workaround for recalc_window_features - * being used overzealously. The fix is to - * only recalc_window_features when something - * has actually changed. + * Lame workaround for recalc_features being used overzealously. + * The fix is to only recalc_features when something has + * actually changed. */ if (window->constructing || old_has_close_func != window->has_close_func || @@ -9672,98 +7435,6 @@ update_resize (MetaWindow *window, g_get_current_time (&window->display->grab_last_moveresize_time); } -typedef struct -{ - Window window; - int count; - guint32 last_time; -} EventScannerData; - -static Bool -find_last_time_predicate (Display *display, - XEvent *ev, - XPointer arg) -{ - EventScannerData *esd = (void*) arg; - XIEvent *xev; - - if (ev->type != GenericEvent) - return False; - - /* We are peeking into events not yet handled by GDK, - * Allocate cookie events here so we can handle XI2. - * - * GDK will handle later these events, and eventually - * free the cookie data itself. - */ - XGetEventData (display, &ev->xcookie); - xev = (XIEvent *) ev->xcookie.data; - - if (xev->evtype != XI_Motion) - return False; - - if (esd->window != ((XIDeviceEvent *) xev)->event) - return False; - - esd->count += 1; - esd->last_time = xev->time; - - return False; -} - -static gboolean -check_use_this_motion_notify (MetaWindow *window, - XIDeviceEvent *xev) -{ - EventScannerData esd; - XEvent useless; - - /* This code is copied from Owen's GDK code. */ - - if (window->display->grab_motion_notify_time != 0) - { - /* == is really the right test, but I'm all for paranoia */ - if (window->display->grab_motion_notify_time <= - xev->time) - { - meta_topic (META_DEBUG_RESIZING, - "Arrived at event with time %u (waiting for %u), using it\n", - (unsigned int)xev->time, - window->display->grab_motion_notify_time); - window->display->grab_motion_notify_time = 0; - return TRUE; - } - else - return FALSE; /* haven't reached the saved timestamp yet */ - } - - esd.window = xev->event; - esd.count = 0; - esd.last_time = 0; - - /* "useless" isn't filled in because the predicate never returns True */ - XCheckIfEvent (window->display->xdisplay, - &useless, - find_last_time_predicate, - (XPointer) &esd); - - if (esd.count > 0) - meta_topic (META_DEBUG_RESIZING, - "Will skip %d motion events and use the event with time %u\n", - esd.count, (unsigned int) esd.last_time); - - if (esd.last_time == 0) - return TRUE; - else - { - /* Save this timestamp, and ignore all motion notify - * until we get to the one with this stamp. - */ - window->display->grab_motion_notify_time = esd.last_time; - return FALSE; - } -} - static void update_tile_mode (MetaWindow *window) { @@ -9781,6 +7452,15 @@ update_tile_mode (MetaWindow *window) } } +void +meta_window_update_resize (MetaWindow *window, + gboolean snap, + int x, int y, + gboolean force) +{ + update_resize (window, snap, x, y, force); +} + #ifdef HAVE_XSYNC void meta_window_update_sync_request_counter (MetaWindow *window, @@ -9835,18 +7515,24 @@ meta_window_update_sync_request_counter (MetaWindow *window, #endif /* HAVE_XSYNC */ void -meta_window_handle_mouse_grab_op_event (MetaWindow *window, - XIDeviceEvent *xev) +meta_window_handle_mouse_grab_op_event (MetaWindow *window, + const ClutterEvent *event) { - switch (xev->evtype) + gboolean is_window_root = (event->any.stage != NULL && + window && + window->screen && + CLUTTER_ACTOR (event->any.stage) == + meta_get_stage_for_screen (window->screen)); + + switch (event->type) { - case XI_ButtonRelease: - if (xev->detail == 1 || - xev->detail == meta_prefs_get_mouse_button_resize ()) + case CLUTTER_BUTTON_RELEASE: + if (event->button.button == 1 || + event->button.button == (unsigned int) meta_prefs_get_mouse_button_resize ()) { meta_display_check_threshold_reached (window->display, - xev->root_x, - xev->root_y); + event->button.x, + event->button.y); /* If the user was snap moving then ignore the button * release because they may have let go of shift before * releasing the mouse button and they almost certainly do @@ -9859,19 +7545,19 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, { if (window->tile_mode != META_TILE_NONE) meta_window_tile (window); - else if (xev->root == window->screen->xroot) + else if (is_window_root) update_move (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y); + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->button.x, + event->button.y); } else if (meta_grab_op_is_resizing (window->display->grab_op)) { - if (xev->root == window->screen->xroot) + if (is_window_root) update_resize (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y, + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->button.x, + event->button.y, TRUE); /* If a tiled window has been dragged free with a @@ -9884,37 +7570,33 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, update_tile_mode (window); } } - meta_display_end_grab_op (window->display, xev->time); + meta_display_end_grab_op (window->display, event->any.time); } break; - case XI_Motion: + case CLUTTER_MOTION: meta_display_check_threshold_reached (window->display, - xev->root_x, - xev->root_y); + event->motion.x, + event->motion.y); if (meta_grab_op_is_moving (window->display->grab_op)) { - if (xev->root == window->screen->xroot) + if (is_window_root) { - if (check_use_this_motion_notify (window, - xev)) - update_move (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y); + update_move (window, + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->motion.x, + event->motion.y); } } else if (meta_grab_op_is_resizing (window->display->grab_op)) { - if (xev->root == window->screen->xroot) + if (is_window_root) { - if (check_use_this_motion_notify (window, - xev)) - update_resize (window, - xev->mods.effective & ShiftMask, - xev->root_x, - xev->root_y, - FALSE); + update_resize (window, + event->button.modifier_state & CLUTTER_SHIFT_MASK, + event->motion.x, + event->motion.y, + FALSE); } } break; @@ -9924,26 +7606,6 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window, } } -void -meta_window_set_gravity (MetaWindow *window, - int gravity) -{ - XSetWindowAttributes attrs; - - meta_verbose ("Setting gravity of %s to %d\n", window->desc, gravity); - - attrs.win_gravity = gravity; - - meta_error_trap_push (window->display); - - XChangeWindowAttributes (window->display->xdisplay, - window->xwindow, - CWWinGravity, - &attrs); - - meta_error_trap_pop (window->display); -} - static void get_work_area_monitor (MetaWindow *window, MetaRectangle *area, @@ -10096,23 +7758,6 @@ meta_window_same_application (MetaWindow *window, group==other_group; } -/* Generally meta_window_same_application() is a better idea - * of "sameness", since it handles the case where multiple apps - * want to look like the same app or the same app wants to look - * like multiple apps, but in the case of workarounds for legacy - * applications (which likely aren't setting the group properly - * anyways), it may be desirable to check this as well. - */ -static gboolean -meta_window_same_client (MetaWindow *window, - MetaWindow *other_window) -{ - int resource_mask = window->display->xdisplay->resource_mask; - - return ((window->xwindow & ~resource_mask) == - (other_window->xwindow & ~resource_mask)); -} - /** * meta_window_is_client_decorated: * @@ -10122,13 +7767,23 @@ meta_window_same_client (MetaWindow *window, gboolean meta_window_is_client_decorated (MetaWindow *window) { - /* Currently the implementation here is hackish - - * has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set - * to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for - * client-side-decorated window, even if the value is 0 because - * the window is maxized and has no invisible borders or shadows. - */ - return window->has_custom_frame_extents; + if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + { + /* Assume all Wayland clients draw decorations - not strictly + * true but good enough for current purposes. + */ + return TRUE; + } + else + { + /* Currently the implementation here is hackish - + * has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set + * to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for + * client-side-decorated window, even if the value is 0 because + * the window is maxized and has no invisible borders or shadows. + */ + return window->has_custom_frame_extents; + } } void @@ -10251,11 +7906,10 @@ meta_window_foreach_ancestor (MetaWindow *window, w = window; do { - if (w->xtransient_for == None || - w->transient_parent_is_root_window) + if (w->transient_for == NULL) break; - w = meta_display_lookup_x_window (w->display, w->xtransient_for); + w = w->transient_for; } while (w && (* func) (w, user_data)); } @@ -10384,7 +8038,7 @@ warp_grab_pointer (MetaWindow *window, *x = CLAMP (*x, 0, window->screen->rect.width-1); *y = CLAMP (*y, 0, window->screen->rect.height-1); - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); meta_topic (META_DEBUG_WINDOW_OPS, "Warping pointer to %d,%d with window at %d,%d\n", @@ -10606,9 +8260,8 @@ meta_window_set_user_time (MetaWindow *window, /* If this is a terminal, user interaction with it means the user likely * doesn't want to have focus transferred for now due to new windows. */ - if (meta_prefs_get_focus_new_windows () == - G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && - __window_is_terminal (window)) + if (meta_prefs_get_focus_new_windows () == G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT && + window_is_terminal (window)) window->display->allow_terminal_deactivation = FALSE; } @@ -10847,23 +8500,6 @@ meta_window_get_window_type (MetaWindow *window) return window->type; } -/** - * meta_window_get_window_type_atom: (skip) - * @window: a #MetaWindow - * - * Gets the X atom from the _NET_WM_WINDOW_TYPE property used by the - * application to set the window type. (Note that this is constrained - * to be some value that Mutter recognizes - a completely unrecognized - * type atom will be returned as None.) - * - * Return value: the raw X atom for the window type, or None - */ -Atom -meta_window_get_window_type_atom (MetaWindow *window) -{ - return window->type_atom; -} - /** * meta_window_get_workspace: * @window: a #MetaWindow @@ -11078,32 +8714,15 @@ meta_window_get_transient_for (MetaWindow *window) { g_return_val_if_fail (META_IS_WINDOW (window), NULL); - if (window->xtransient_for) + if (window->transient_for) + return window->transient_for; + else if (window->xtransient_for) return meta_display_lookup_x_window (window->display, window->xtransient_for); else return NULL; } -/** - * meta_window_get_transient_for_as_xid: - * @window: a #MetaWindow - * - * Returns the XID of the window that is pointed to by the - * WM_TRANSIENT_FOR hint on this window (see XGetTransientForHint() - * or XSetTransientForHint()). Metacity keeps transient windows above their - * parents. A typical usage of this hint is for a dialog that wants to stay - * above its associated window. - * - * Return value: (transfer none): the window this window is transient for, or - * None if the WM_TRANSIENT_FOR hint is unset. - */ -Window -meta_window_get_transient_for_as_xid (MetaWindow *window) -{ - return window->xtransient_for; -} - /** * meta_window_get_pid: * @window: a #MetaWindow @@ -11153,23 +8772,6 @@ meta_window_is_remote (MetaWindow *window) return window->is_remote; } -/** - * meta_window_is_modal: - * @window: a #MetaWindow - * - * Queries whether the window is in a modal state as described by the - * _NET_WM_STATE protocol. - * - * Return value: (transfer none): TRUE if the window is in modal state. - */ -gboolean -meta_window_is_modal (MetaWindow *window) -{ - g_return_val_if_fail (META_IS_WINDOW (window), FALSE); - - return window->wm_state_modal; -} - /** * meta_window_get_mutter_hints: * @window: a #MetaWindow @@ -11403,10 +9005,126 @@ meta_window_compute_tile_match (MetaWindow *window) } } -Window -meta_window_get_toplevel_xwindow (MetaWindow *window) +void +meta_window_set_title (MetaWindow *window, + const char *title) { - return window->frame ? window->frame->xwindow : window->xwindow; + g_free (window->title); + window->title = g_strdup (title); + + if (window->frame) + meta_ui_set_frame_title (window->screen->ui, + window->frame->xwindow, + window->title); + + meta_window_update_desc (window); + + g_object_notify (G_OBJECT (window), "title"); +} + +void +meta_window_set_wm_class (MetaWindow *window, + const char *wm_class, + const char *wm_instance) +{ + g_free (window->res_class); + g_free (window->res_name); + + window->res_name = g_strdup (wm_instance); + window->res_class = g_strdup (wm_class); + + g_object_notify (G_OBJECT (window), "wm-class"); +} + +void +meta_window_set_gtk_dbus_properties (MetaWindow *window, + const char *application_id, + const char *unique_bus_name, + const char *appmenu_path, + const char *menubar_path, + const char *application_object_path, + const char *window_object_path) +{ + g_object_freeze_notify (G_OBJECT (window)); + + g_free (window->gtk_application_id); + window->gtk_application_id = g_strdup (application_id); + g_object_notify (G_OBJECT (window), "gtk-application-id"); + + g_free (window->gtk_unique_bus_name); + window->gtk_unique_bus_name = g_strdup (unique_bus_name); + g_object_notify (G_OBJECT (window), "gtk-unique-bus-name"); + + g_free (window->gtk_app_menu_object_path); + window->gtk_app_menu_object_path = g_strdup (appmenu_path); + g_object_notify (G_OBJECT (window), "gtk-app-menu-object-path"); + + g_free (window->gtk_menubar_object_path); + window->gtk_menubar_object_path = g_strdup (menubar_path); + g_object_notify (G_OBJECT (window), "gtk-menubar-object-path"); + + g_free (window->gtk_application_object_path); + window->gtk_application_object_path = g_strdup (application_object_path); + g_object_notify (G_OBJECT (window), "gtk-application-object-path"); + + g_free (window->gtk_window_object_path); + window->gtk_window_object_path = g_strdup (window_object_path); + g_object_notify (G_OBJECT (window), "gtk-window-object-path"); + + g_object_thaw_notify (G_OBJECT (window)); +} + +void +meta_window_set_transient_for (MetaWindow *window, + MetaWindow *parent) +{ + if (meta_window_appears_focused (window) && window->transient_for != None) + meta_window_propagate_focus_appearance (window, FALSE); + + /* may now be a dialog */ + if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) + meta_window_x11_recalc_window_type (window); + + if (!window->constructing) + { + /* If the window attaches, detaches, or changes attached + * parents, we need to destroy the MetaWindow and let a new one + * be created (which happens as a side effect of + * meta_window_unmanage()). The condition below is correct + * because we know window->transient_for has changed. + */ + if (window->attached || meta_window_should_attach_to_parent (window)) + { + guint32 timestamp; + + timestamp = meta_display_get_current_time_roundtrip (window->display); + meta_window_unmanage (window, timestamp); + return; + } + } + + /* update stacking constraints */ + if (!window->override_redirect) + meta_stack_update_transient (window->screen->stack, window); + + /* We know this won't create a reference cycle because we check for loops */ + g_clear_object (&window->transient_for); + window->transient_for = parent ? g_object_ref (parent) : NULL; + + /* possibly change its group. We treat being a window's transient as + * equivalent to making it your group leader, to work around shortcomings + * in programs such as xmms-- see #328211. + */ + if (window->xtransient_for != None && + window->xgroup_leader != None && + window->xtransient_for != window->xgroup_leader) + meta_window_group_leader_changed (window); + + if (!window->constructing && !window->override_redirect) + meta_window_queue (window, META_QUEUE_MOVE_RESIZE); + + if (meta_window_appears_focused (window) && window->transient_for != None) + meta_window_propagate_focus_appearance (window, TRUE); } void @@ -11415,8 +9133,211 @@ meta_window_set_opacity (MetaWindow *window, { window->opacity = opacity; - if (window->display->compositor) - meta_compositor_window_opacity_changed (window->display->compositor, window); + meta_compositor_window_opacity_changed (window->display->compositor, window); +} + +static void +reset_ignored_crossing_serials (MetaDisplay *display) +{ + int i; + + i = 0; + while (i < N_IGNORED_CROSSING_SERIALS) + { + display->ignored_crossing_serials[i] = 0; + ++i; + } + + display->ungrab_should_not_cause_focus_window = None; +} + +typedef struct +{ + MetaWindow *window; + int pointer_x; + int pointer_y; +} MetaFocusData; + +static void +mouse_mode_focus (MetaWindow *window, + guint32 timestamp) +{ + MetaDisplay *display = window->display; + + if (window->type != META_WINDOW_DESKTOP) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing %s at time %u.\n", window->desc, timestamp); + + meta_window_focus (window, timestamp); + + if (meta_prefs_get_auto_raise ()) + meta_display_queue_autoraise_callback (display, window); + else + meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled\n"); + } + else + { + /* In mouse focus mode, we defocus when the mouse *enters* + * the DESKTOP window, instead of defocusing on LeaveNotify. + * This is because having the mouse enter override-redirect + * child windows unfortunately causes LeaveNotify events that + * we can't distinguish from the mouse actually leaving the + * toplevel window as we expect. But, since we filter out + * EnterNotify events on override-redirect windows, this + * alternative mechanism works great. + */ + if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE && + display->focus_window != NULL) + { + meta_topic (META_DEBUG_FOCUS, + "Unsetting focus from %s due to mouse entering " + "the DESKTOP window\n", + display->focus_window->desc); + meta_display_focus_the_no_focus_window (display, + window->screen, + timestamp); + } + } +} + +static gboolean +window_focus_on_pointer_rest_callback (gpointer data) +{ + MetaFocusData *focus_data = data; + MetaWindow *window = focus_data->window; + MetaDisplay *display = window->display; + MetaScreen *screen = window->screen; + int root_x, root_y; + guint32 timestamp; + ClutterActor *child; + + if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) + goto out; + + meta_cursor_tracker_get_pointer (screen->cursor_tracker, + &root_x, &root_y, NULL); + + if (root_x != focus_data->pointer_x || + root_y != focus_data->pointer_y) + { + focus_data->pointer_x = root_x; + focus_data->pointer_y = root_y; + return TRUE; + } + + child = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (clutter_stage_get_default ()), + CLUTTER_PICK_REACTIVE, root_x, root_y); + if (!META_IS_SURFACE_ACTOR (child)) + goto out; + + window = + meta_stack_get_default_focus_window_at_point (screen->stack, + screen->active_workspace, + NULL, root_x, root_y); + + if (window == NULL) + goto out; + + timestamp = meta_display_get_current_time_roundtrip (display); + mouse_mode_focus (window, timestamp); + + out: + display->focus_timeout_id = 0; + return FALSE; +} + +/* The interval, in milliseconds, we use in focus-follows-mouse + * mode to check whether the pointer has stopped moving after a + * crossing event. + */ +#define FOCUS_TIMEOUT_DELAY 25 + +static void +queue_focus_callback (MetaDisplay *display, + MetaWindow *window, + int pointer_x, + int pointer_y) +{ + MetaFocusData *focus_data; + + focus_data = g_new (MetaFocusData, 1); + focus_data->window = window; + focus_data->pointer_x = pointer_x; + focus_data->pointer_y = pointer_y; + + if (display->focus_timeout_id != 0) + g_source_remove (display->focus_timeout_id); + + display->focus_timeout_id = + g_timeout_add_full (G_PRIORITY_DEFAULT, + FOCUS_TIMEOUT_DELAY, + window_focus_on_pointer_rest_callback, + focus_data, + g_free); +} + +void +meta_window_handle_enter (MetaWindow *window, + guint32 timestamp, + guint root_x, + guint root_y) +{ + MetaDisplay *display = window->display; + + switch (meta_prefs_get_focus_mode ()) + { + case G_DESKTOP_FOCUS_MODE_SLOPPY: + case G_DESKTOP_FOCUS_MODE_MOUSE: + display->mouse_mode = TRUE; + if (window->type != META_WINDOW_DOCK) + { + if (meta_prefs_get_focus_change_on_pointer_rest()) + queue_focus_callback (display, window, root_x, root_y); + else + mouse_mode_focus (window, timestamp); + + /* stop ignoring stuff */ + reset_ignored_crossing_serials (display); + } + break; + case G_DESKTOP_FOCUS_MODE_CLICK: + break; + } +} + +void +meta_window_set_surface_mapped (MetaWindow *window, + gboolean surface_mapped) +{ + if (window->surface_mapped == (guint) surface_mapped) + return; + + window->surface_mapped = surface_mapped; + meta_window_queue (window, META_QUEUE_CALC_SHOWING); +} + +Window +meta_window_get_toplevel_xwindow (MetaWindow *window) +{ + return window->frame ? window->frame->xwindow : window->xwindow; +} + +void +meta_window_set_custom_frame_extents (MetaWindow *window, + GtkBorder *extents) +{ + if (extents) + { + window->has_custom_frame_extents = TRUE; + window->custom_frame_extents = *extents; + } + else + { + window->has_custom_frame_extents = FALSE; + } + + meta_window_queue (window, META_QUEUE_MOVE_RESIZE); } gboolean @@ -11466,3 +9387,17 @@ meta_window_allows_resize (MetaWindow *window) { return META_WINDOW_ALLOWS_RESIZE (window); } + +void +meta_window_set_urgent (MetaWindow *window, + gboolean urgent) +{ + if (window->urgent == urgent) + return; + + window->urgent = urgent; + g_object_notify (G_OBJECT (window), "urgent"); + + if (urgent) + g_signal_emit_by_name (window->display, "window-marked-urgent", window); +} diff --git a/src/core/workspace.c b/src/core/workspace.c index f1e2527a1..ca87c0bf7 100644 --- a/src/core/workspace.c +++ b/src/core/workspace.c @@ -665,7 +665,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace, meta_screen_free_workspace_layout (&layout1); meta_screen_free_workspace_layout (&layout2); - meta_compositor_switch_workspace (comp, screen, old, workspace, direction); + meta_compositor_switch_workspace (comp, old, workspace, direction); /* This needs to be done after telling the compositor we are switching * workspaces since focusing a window will cause it to be immediately diff --git a/src/libmutter-wayland.pc.in b/src/libmutter-wayland.pc.in new file mode 100644 index 000000000..6537c4f75 --- /dev/null +++ b/src/libmutter-wayland.pc.in @@ -0,0 +1,18 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +girdir=@libdir@/mutter-wayland +typelibdir=@libdir@/mutter-wayland + +mutter_major_version=@MUTTER_MAJOR_VERSION@ +mutter_minor_version=@MUTTER_MINOR_VERSION@ +mutter_micro_version=@MUTTER_MICRO_VERSION@ +mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@ + +Name: libmutter-wayland +Description: Mutter window manager library (Wayland branch) +Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11 wayland-server +Version: @VERSION@ +Libs: -L${libdir} -lmutter-wayland +Cflags: -I${includedir}/mutter-wayland -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} diff --git a/src/libmutter.pc.in b/src/libmutter.pc.in deleted file mode 100644 index 1f819af80..000000000 --- a/src/libmutter.pc.in +++ /dev/null @@ -1,18 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -girdir=@libdir@/mutter -typelibdir=@libdir@/mutter - -mutter_major_version=@MUTTER_MAJOR_VERSION@ -mutter_minor_version=@MUTTER_MINOR_VERSION@ -mutter_micro_version=@MUTTER_MICRO_VERSION@ -mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@ - -Name: libmutter -Description: Mutter window manager library -Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11 -Version: @VERSION@ -Libs: -L${libdir} -lmutter -Cflags: -I${includedir}/mutter -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} diff --git a/src/meta/atomnames.h b/src/meta/atomnames.h index 0fb31bebc..46e1a664e 100644 --- a/src/meta/atomnames.h +++ b/src/meta/atomnames.h @@ -79,7 +79,9 @@ item(TIMESTAMP) item(VERSION) item(ATOM_PAIR) item(Backlight) +item(_XKB_RULES_NAMES) item(hotplug_mode_update) +item(WL_SURFACE_ID) /* Oddities: These are used, and we need atoms for them, * but when we need all _NET_WM hints (i.e. when we're making @@ -90,7 +92,6 @@ item(hotplug_mode_update) item(_NET_WM_SYNC_REQUEST) item(_NET_WM_SYNC_REQUEST_COUNTER) item(_NET_WM_VISIBLE_NAME) -item(_NET_WM_VISIBLE_ICON_NAME) item(_NET_SUPPORTING_WM_CHECK) /* But I suppose it's quite reasonable not to advertise using @@ -131,7 +132,6 @@ item(_NET_CLIENT_LIST) item(_NET_CLIENT_LIST_STACKING) item(_NET_WM_STATE_SKIP_TASKBAR) item(_NET_WM_STATE_SKIP_PAGER) -item(_NET_WM_ICON_NAME) item(_NET_WM_ICON) item(_NET_WM_ICON_GEOMETRY) item(_NET_WM_MOVERESIZE) diff --git a/src/meta/common.h b/src/meta/common.h index 583cc6e60..6ae1d8918 100644 --- a/src/meta/common.h +++ b/src/meta/common.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -162,13 +163,6 @@ typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu, * @META_GRAB_OP_KEYBOARD_RESIZING_NE: Resizing NE with keyboard * @META_GRAB_OP_KEYBOARD_RESIZING_SW: Resizing SW with keyboard * @META_GRAB_OP_KEYBOARD_RESIZING_NW: Resizing NS with keyboard - * @META_GRAB_OP_KEYBOARD_TABBING_NORMAL: Tabbing - * @META_GRAB_OP_KEYBOARD_TABBING_DOCK: Tabbing through docks - * @META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL: Escaping - * @META_GRAB_OP_KEYBOARD_ESCAPING_DOCK: Escaping through docks - * @META_GRAB_OP_KEYBOARD_ESCAPING_GROUP: Escaping through groups - * @META_GRAB_OP_KEYBOARD_TABBING_GROUP: Tabbing through groups - * @META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING: Switch to another workspace * @META_GRAB_OP_CLICKING_MINIMIZE: Clicked minimize button * @META_GRAB_OP_CLICKING_MAXIMIZE: Clicked maximize button * @META_GRAB_OP_CLICKING_UNMAXIMIZE: Clicked unmaximize button @@ -227,7 +221,10 @@ typedef enum META_GRAB_OP_CLICKING_UNSTICK, /* Special grab op when the compositor asked for a grab */ - META_GRAB_OP_COMPOSITOR + META_GRAB_OP_COMPOSITOR, + + /* For when a client takes a popup grab */ + META_GRAB_OP_WAYLAND_CLIENT, } MetaGrabOp; /** diff --git a/src/meta/compositor.h b/src/meta/compositor.h index d1be47e36..57be80afd 100644 --- a/src/meta/compositor.h +++ b/src/meta/compositor.h @@ -57,22 +57,21 @@ typedef enum MetaCompositor *meta_compositor_new (MetaDisplay *display); void meta_compositor_destroy (MetaCompositor *compositor); -void meta_compositor_manage_screen (MetaCompositor *compositor, - MetaScreen *screen); -void meta_compositor_unmanage_screen (MetaCompositor *compositor, - MetaScreen *screen); +void meta_compositor_manage (MetaCompositor *compositor); +void meta_compositor_unmanage (MetaCompositor *compositor); void meta_compositor_window_shape_changed (MetaCompositor *compositor, MetaWindow *window); void meta_compositor_window_opacity_changed (MetaCompositor *compositor, MetaWindow *window); +void meta_compositor_window_surface_changed (MetaCompositor *compositor, + MetaWindow *window); gboolean meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, MetaWindow *window); gboolean meta_compositor_filter_keybinding (MetaCompositor *compositor, - MetaScreen *screen, MetaKeyBinding *binding); void meta_compositor_add_window (MetaCompositor *compositor, @@ -86,7 +85,6 @@ void meta_compositor_hide_window (MetaCompositor *compositor, MetaWindow *window, MetaCompEffect effect); void meta_compositor_switch_workspace (MetaCompositor *compositor, - MetaScreen *screen, MetaWorkspace *from, MetaWorkspace *to, MetaMotionDirection direction); @@ -111,10 +109,8 @@ void meta_compositor_queue_frame_drawn (MetaCompositor *compositor, gboolean no_delay_frame); void meta_compositor_sync_stack (MetaCompositor *compositor, - MetaScreen *screen, GList *stack); void meta_compositor_sync_screen_size (MetaCompositor *compositor, - MetaScreen *screen, guint width, guint height); @@ -122,11 +118,9 @@ void meta_compositor_flash_screen (MetaCompositor *compositor, MetaScreen *screen); void meta_compositor_show_tile_preview (MetaCompositor *compositor, - MetaScreen *screen, MetaWindow *window, MetaRectangle *tile_rect, int tile_monitor_number); -void meta_compositor_hide_tile_preview (MetaCompositor *compositor, - MetaScreen *screen); +void meta_compositor_hide_tile_preview (MetaCompositor *compositor); #endif /* META_COMPOSITOR_H */ diff --git a/src/meta/display.h b/src/meta/display.h index 60e9ab14d..694d7e95a 100644 --- a/src/meta/display.h +++ b/src/meta/display.h @@ -73,12 +73,9 @@ int meta_display_get_xinput_opcode (MetaDisplay *display); gboolean meta_display_supports_extended_barriers (MetaDisplay *display); Display *meta_display_get_xdisplay (MetaDisplay *display); MetaCompositor *meta_display_get_compositor (MetaDisplay *display); -GSList *meta_display_get_screens (MetaDisplay *display); gboolean meta_display_has_shape (MetaDisplay *display); -MetaScreen *meta_display_screen_for_root (MetaDisplay *display, - Window xroot); MetaWindow *meta_display_get_focus_window (MetaDisplay *display); gboolean meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display, @@ -95,8 +92,6 @@ guint32 meta_display_get_last_user_time (MetaDisplay *display); guint32 meta_display_get_current_time (MetaDisplay *display); guint32 meta_display_get_current_time_roundtrip (MetaDisplay *display); -unsigned int meta_display_get_ignored_modifier_mask (MetaDisplay *display); - GList* meta_display_get_tab_list (MetaDisplay *display, MetaTabList type, MetaScreen *screen, @@ -104,14 +99,12 @@ GList* meta_display_get_tab_list (MetaDisplay *display, MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace, MetaWindow *window, gboolean backward); MetaWindow* meta_display_get_tab_current (MetaDisplay *display, MetaTabList type, - MetaScreen *screen, MetaWorkspace *workspace); gboolean meta_display_begin_grab_op (MetaDisplay *display, @@ -163,10 +156,6 @@ void meta_display_set_input_focus_window (MetaDisplay *display, gboolean focus_frame, guint32 timestamp); -void meta_display_request_take_focus (MetaDisplay *display, - MetaWindow *window, - guint32 timestamp); - /* meta_display_focus_the_no_focus_window is called when the * designated no_focus_window should be focused, but is otherwise the * same as meta_display_set_input_focus_window @@ -178,8 +167,6 @@ void meta_display_focus_the_no_focus_window (MetaDisplay *display, GSList *meta_display_sort_windows_by_stacking (MetaDisplay *display, GSList *windows); -Window meta_display_get_leader_window (MetaDisplay *display); - void meta_display_add_ignored_crossing_serial (MetaDisplay *display, unsigned long serial); diff --git a/src/meta/errors.h b/src/meta/errors.h index d2aa27b6b..36bd9b703 100644 --- a/src/meta/errors.h +++ b/src/meta/errors.h @@ -30,7 +30,6 @@ void meta_error_trap_push (MetaDisplay *display); void meta_error_trap_pop (MetaDisplay *display); -void meta_error_trap_push_with_return (MetaDisplay *display); /* returns X error code, or 0 for no error */ int meta_error_trap_pop_with_return (MetaDisplay *display); diff --git a/src/meta/main.h b/src/meta/main.h index 35eb73da7..82f05a018 100644 --- a/src/meta/main.h +++ b/src/meta/main.h @@ -28,6 +28,7 @@ GOptionContext *meta_get_option_context (void); void meta_init (void); int meta_run (void); void meta_register_with_session (void); +gboolean meta_activate_session (void); /* Actually defined in meta-backend.c */ gboolean meta_get_replace_current_wm (void); /* Actually defined in util.c */ void meta_set_wm_name (const char *wm_name); diff --git a/src/meta/meta-background.h b/src/meta/meta-background.h index c171df326..a861600f8 100644 --- a/src/meta/meta-background.h +++ b/src/meta/meta-background.h @@ -91,7 +91,6 @@ void meta_background_load_gradient (MetaBackground *self, ClutterColor *second_color); void meta_background_load_color (MetaBackground *self, ClutterColor *color); -void meta_background_load_still_frame (MetaBackground *self); void meta_background_load_file_async (MetaBackground *self, const char *filename, GDesktopBackgroundStyle style, diff --git a/src/meta/meta-plugin.h b/src/meta/meta-plugin.h index cef785397..983db7a47 100644 --- a/src/meta/meta-plugin.h +++ b/src/meta/meta-plugin.h @@ -254,9 +254,6 @@ struct _MetaPluginInfo GType meta_plugin_get_type (void); -gboolean meta_plugin_running (MetaPlugin *plugin); -gboolean meta_plugin_debug_mode (MetaPlugin *plugin); - const MetaPluginInfo * meta_plugin_get_info (MetaPlugin *plugin); /** @@ -408,8 +405,7 @@ meta_plugin_end_modal (MetaPlugin *plugin, MetaScreen *meta_plugin_get_screen (MetaPlugin *plugin); -void -_meta_plugin_effect_started (MetaPlugin *plugin); +void _meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor); /* XXX: Putting this in here so it's in the public header. */ void meta_plugin_manager_set_plugin_type (GType gtype); diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h index b0870bf95..80b23f2ea 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -75,9 +75,6 @@ CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, CoglTexture *mask_texture); -void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex, - cairo_region_t *shape_region); - void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, cairo_region_t *opaque_region); diff --git a/src/meta/prefs.h b/src/meta/prefs.h index 49d5076e7..677110a18 100644 --- a/src/meta/prefs.h +++ b/src/meta/prefs.h @@ -376,17 +376,17 @@ typedef enum * @display: a #MetaDisplay * @screen: a #MetaScreen * @window: a #MetaWindow - * @event: (type gpointer): a #XIDeviceEvent + * @event: (type gpointer): a #ClutterKeyEvent * @binding: a #MetaKeyBinding * @user_data: data passed to the function * */ -typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display, - MetaScreen *screen, - MetaWindow *window, - XIDeviceEvent *event, - MetaKeyBinding *binding, - gpointer user_data); +typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display, + MetaScreen *screen, + MetaWindow *window, + ClutterKeyEvent *event, + MetaKeyBinding *binding, + gpointer user_data); GType meta_key_binding_get_type (void); diff --git a/src/meta/screen.h b/src/meta/screen.h index 6e0cde7ee..4c3c52e3f 100644 --- a/src/meta/screen.h +++ b/src/meta/screen.h @@ -44,12 +44,6 @@ void meta_screen_get_size (MetaScreen *screen, int *width, int *height); -gpointer meta_screen_get_compositor_data (MetaScreen *screen); -void meta_screen_set_compositor_data (MetaScreen *screen, - gpointer info); - -MetaScreen *meta_screen_for_x_screen (Screen *xscreen); - void meta_screen_set_cm_selection (MetaScreen *screen); void meta_screen_unset_cm_selection (MetaScreen *screen); diff --git a/src/meta/util.h b/src/meta/util.h index 9328a26b9..4644de5a1 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -31,6 +31,7 @@ gboolean meta_is_verbose (void); gboolean meta_is_debugging (void); gboolean meta_is_syncing (void); +gboolean meta_is_wayland_compositor (void); void meta_debug_spew_real (const char *format, ...) G_GNUC_PRINTF (1, 2); diff --git a/src/meta/window.h b/src/meta/window.h index 671060f4c..3677790b5 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -81,6 +81,16 @@ typedef enum META_MAXIMIZE_BOTH = (1 << 0 | 1 << 1), } MetaMaximizeFlags; +/** + * MetaWindowClientType: + * @META_WINDOW_CLIENT_TYPE_WAYLAND: A Wayland based window + * @META_WINDOW_CLIENT_TYPE_X11: An X11 based window + */ +typedef enum { + META_WINDOW_CLIENT_TYPE_WAYLAND, + META_WINDOW_CLIENT_TYPE_X11 +} MetaWindowClientType; + #define META_TYPE_WINDOW (meta_window_get_type ()) #define META_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW, MetaWindow)) #define META_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW, MetaWindowClass)) @@ -115,7 +125,6 @@ MetaScreen *meta_window_get_screen (MetaWindow *window); MetaDisplay *meta_window_get_display (MetaWindow *window); Window meta_window_get_xwindow (MetaWindow *window); MetaWindowType meta_window_get_window_type (MetaWindow *window); -Atom meta_window_get_window_type_atom (MetaWindow *window); MetaWorkspace *meta_window_get_workspace (MetaWindow *window); int meta_window_get_monitor (MetaWindow *window); gboolean meta_window_is_on_all_workspaces (MetaWindow *window); @@ -155,7 +164,6 @@ void meta_window_change_workspace (MetaWindow *window, MetaWorkspace *workspace); GObject *meta_window_get_compositor_private (MetaWindow *window); void meta_window_set_compositor_private (MetaWindow *window, GObject *priv); -void meta_window_configure_notify (MetaWindow *window, XConfigureEvent *event); const char *meta_window_get_role (MetaWindow *window); MetaStackLayer meta_window_get_layer (MetaWindow *window); MetaWindow* meta_window_find_root_ancestor (MetaWindow *window); @@ -195,7 +203,6 @@ void meta_window_raise (MetaWindow *window); void meta_window_lower (MetaWindow *window); const char *meta_window_get_title (MetaWindow *window); MetaWindow *meta_window_get_transient_for (MetaWindow *window); -Window meta_window_get_transient_for_as_xid (MetaWindow *window); void meta_window_delete (MetaWindow *window, guint32 timestamp); guint meta_window_get_stable_sequence (MetaWindow *window); @@ -203,7 +210,6 @@ guint32 meta_window_get_user_time (MetaWindow *window); int meta_window_get_pid (MetaWindow *window); const char *meta_window_get_client_machine (MetaWindow *window); gboolean meta_window_is_remote (MetaWindow *window); -gboolean meta_window_is_modal (MetaWindow *window); gboolean meta_window_is_attached_dialog (MetaWindow *window); const char *meta_window_get_mutter_hints (MetaWindow *window); diff --git a/src/mutter-plugins.pc.in b/src/mutter-plugins.pc.in deleted file mode 100644 index 5d42232ee..000000000 --- a/src/mutter-plugins.pc.in +++ /dev/null @@ -1,17 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -plugindir=@MUTTER_PLUGIN_DIR@ -libgnome_serverdir=@libexecdir@ -mutter_major_version=@MUTTER_MAJOR_VERSION@ -mutter_minor_version=@MUTTER_MINOR_VERSION@ -mutter_micro_version=@MUTTER_MICRO_VERSION@ -mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@ - -Name: mutter-plugins -Description: Dev parameters for mutter plugins -Requires: @CLUTTER_PACKAGE@ -Version: @VERSION@ -Libs: @CLUTTER_LIBS@ -Cflags: @CLUTTER_CFLAGS@ -DWITH_CLUTTER -I${includedir}/mutter/mutter-private -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} -DMUTTER_PLUGIN_DIR=\"${plugindir}\" diff --git a/src/mutter.desktop.in b/src/mutter-wayland.desktop.in similarity index 74% rename from src/mutter.desktop.in rename to src/mutter-wayland.desktop.in index 3bfb88d2d..9f213166a 100644 --- a/src/mutter.desktop.in +++ b/src/mutter-wayland.desktop.in @@ -1,7 +1,7 @@ [Desktop Entry] Type=Application -_Name=Mutter -Exec=mutter +_Name=Mutter (wayland compositor) +Exec=mutter-launch -- mutter --wayland --display-server NoDisplay=true # name of loadable control center module X-GNOME-WMSettingsModule=metacity @@ -12,6 +12,5 @@ X-GnomeWMSettingsLibrary=metacity X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=mutter X-GNOME-Bugzilla-Component=general -X-GNOME-Autostart-Phase=WindowManager -X-GNOME-Provides=windowmanager +X-GNOME-Autostart-Phase=DisplayServer X-GNOME-Autostart-Notify=true diff --git a/src/mutter-wm.desktop.in b/src/mutter-wm.desktop.in deleted file mode 100644 index 2b60c7e0f..000000000 --- a/src/mutter-wm.desktop.in +++ /dev/null @@ -1,20 +0,0 @@ -[Desktop Entry] -Type=Application -_Name=Mutter -Exec=mutter -# name of loadable control center module -X-GNOME-WMSettingsModule=metacity -# name we put on the WM spec check window -X-GNOME-WMName=Mutter -# back compat only -X-GnomeWMSettingsLibrary=metacity -X-GNOME-Bugzilla-Bugzilla=GNOME -X-GNOME-Bugzilla-Product=mutter -X-GNOME-Bugzilla-Component=general -X-GNOME-Autostart-Phase=WindowManager -X-GNOME-Provides=windowmanager -X-GNOME-Autostart-Notify=true - -[Window Manager] -SessionManaged=true - diff --git a/src/xrandr.xml b/src/org.gnome.Mutter.DisplayConfig.xml similarity index 100% rename from src/xrandr.xml rename to src/org.gnome.Mutter.DisplayConfig.xml diff --git a/src/idle-monitor.xml b/src/org.gnome.Mutter.IdleMonitor.xml similarity index 100% rename from src/idle-monitor.xml rename to src/org.gnome.Mutter.IdleMonitor.xml diff --git a/src/org.gnome.mutter.wayland.gschema.xml.in b/src/org.gnome.mutter.wayland.gschema.xml.in new file mode 100644 index 000000000..4bb5c1dfd --- /dev/null +++ b/src/org.gnome.mutter.wayland.gschema.xml.in @@ -0,0 +1,33 @@ + + + + F1']]]> + <_summary>Switch to VT 1 + + + F2']]]> + <_summary>Switch to VT 2 + + + F3']]]> + <_summary>Switch to VT 3 + + + F4']]]> + <_summary>Switch to VT 4 + + + F5']]]> + <_summary>Switch to VT 5 + + + F6']]]> + <_summary>Switch to VT 6 + + + F7']]]> + <_summary>Switch to VT 7 + + + diff --git a/src/run-mutter.sh b/src/run-mutter.sh deleted file mode 100755 index b64834f7a..000000000 --- a/src/run-mutter.sh +++ /dev/null @@ -1,109 +0,0 @@ -#! /bin/bash - -if test -z "$XNEST_DISPLAY"; then - XNEST_DISPLAY=:8 -fi - -if test -z "$CLIENT_DISPLAY"; then - CLIENT_DISPLAY=:8 -fi - -if test -z "$MUTTER_DISPLAY"; then - export MUTTER_DISPLAY=$CLIENT_DISPLAY -fi - -if test -z "$SCREENS"; then - SCREENS=1 -fi - -MAX_SCREEN=`echo $SCREENS-1 | bc` - -if test "$DEBUG" = none; then - DEBUG= -elif test -z "$DEBUG"; then - DEBUG= -fi - -if test -z "$CLIENTS"; then - CLIENTS=0 -fi - -if test -z "$SM_CLIENTS"; then - SM_CLIENTS=0 -fi - -if test -n "$EVIL_TEST"; then - TEST_CLIENT='./wm-tester/wm-tester --evil' -fi - -if test -n "$ICON_TEST"; then - TEST_CLIENT='./wm-tester/wm-tester --icon-windows' -fi - -if test -n "$DEMO_TEST"; then - TEST_CLIENT='./tools/mutter-window-demo' -fi - -if test -n "$XINERAMA"; then - XINERAMA_FLAGS='+xinerama' -fi - -export EF_ALLOW_MALLOC_0=1 - -if test -z "$ONLY_WM"; then - echo "Launching Xnest" - Xnest -ac $XNEST_DISPLAY -scrns $SCREENS -geometry 640x480 -bw 15 $XINERAMA_FLAGS & - ## usleep 800000 - sleep 1 - - if test -n "$XMON_DIR"; then - echo "Launching xmond" - $XMON_DIR/xmonui | $XMON_DIR/xmond -server localhost:$XNEST_DISPLAY & - sleep 1 - fi - - if test -n "$XSCOPE_DIR"; then - ## xscope doesn't like to die when it should, it backgrounds itself - killall -9 xscope - killall -9 xscope - echo "Launching xscope" - DISPLAY= $XSCOPE_DIR/xscope -o1 -i28 > xscoped-replies.txt & - export MUTTER_DISPLAY=localhost:28 - sleep 1 - fi - - echo "Launching clients" - if test -n "$TEST_CLIENT"; then - for I in `seq 0 $MAX_SCREEN`; do - DISPLAY=$CLIENT_DISPLAY.$I $TEST_CLIENT & - done - fi - - if test $CLIENTS != 0; then - for I in `seq 1 $CLIENTS`; do - echo "Launching xterm $I" - DISPLAY=$CLIENT_DISPLAY xterm -geometry 25x15 & - done - fi - - if test $SM_CLIENTS != 0; then - for I in `seq 1 $SM_CLIENTS`; do - echo "Launching gnome-terminal $I" - DISPLAY=$CLIENT_DISPLAY gnome-terminal --geometry 25x15 & - done - fi - - if test -e ~/.Xmodmap; then - DISPLAY=$CLIENT_DISPLAY xmodmap ~/.Xmodmap - fi - - usleep 50000 - - for I in `seq 0 $MAX_SCREEN`; do - DISPLAY=$CLIENT_DISPLAY.$I xsetroot -solid royalblue3 - done -fi - -if test -z "$ONLY_SETUP"; then - MUTTER_VERBOSE=1 MUTTER_USE_LOGFILE=1 MUTTER_DEBUG_BUTTON_GRABS=1 exec $DEBUG ./mutter $OPTIONS -fi diff --git a/src/ui/ui.c b/src/ui/ui.c index c89028820..a4b8f9138 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -32,11 +32,6 @@ #include #include -static void meta_ui_accelerator_parse (const char *accel, - guint *keysym, - guint *keycode, - GdkModifierType *keymask); - struct _MetaUI { Display *xdisplay; @@ -54,6 +49,8 @@ struct _MetaUI void meta_ui_init (void) { + gdk_set_allowed_backends ("x11"); + if (!gtk_init_check (NULL, NULL)) meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL)); @@ -241,58 +238,17 @@ maybe_redirect_mouse_event (XEvent *xevent) return TRUE; } -typedef struct _EventFunc EventFunc; - -struct _EventFunc -{ - MetaEventFunc func; - gpointer data; -}; - -static EventFunc *ef = NULL; - static GdkFilterReturn -filter_func (GdkXEvent *xevent, - GdkEvent *event, - gpointer data) +ui_filter_func (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) { - g_return_val_if_fail (ef != NULL, GDK_FILTER_CONTINUE); - - if ((* ef->func) (xevent, ef->data) || - maybe_redirect_mouse_event (xevent)) + if (maybe_redirect_mouse_event (xevent)) return GDK_FILTER_REMOVE; else return GDK_FILTER_CONTINUE; } -void -meta_ui_add_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data) -{ - g_return_if_fail (ef == NULL); - - ef = g_new (EventFunc, 1); - ef->func = func; - ef->data = data; - - gdk_window_add_filter (NULL, filter_func, ef); -} - -/* removal is by data due to proxy function */ -void -meta_ui_remove_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data) -{ - g_return_if_fail (ef != NULL); - - gdk_window_remove_filter (NULL, filter_func, ef); - - g_free (ef); - ef = NULL; -} - MetaUI* meta_ui_new (Display *xdisplay, Screen *screen) @@ -316,6 +272,8 @@ meta_ui_new (Display *xdisplay, */ gtk_widget_show (GTK_WIDGET (ui->frames)); + gdk_window_add_filter (NULL, ui_filter_func, NULL); + g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui); return ui; @@ -331,6 +289,8 @@ meta_ui_free (MetaUI *ui) gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay); g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL); + gdk_window_remove_filter (NULL, ui_filter_func, NULL); + g_free (ui); } @@ -700,38 +660,6 @@ meta_ui_window_should_not_cause_focus (Display *xdisplay, return FALSE; } -char* -meta_text_property_to_utf8 (Display *xdisplay, - const XTextProperty *prop) -{ - GdkDisplay *display; - char **list; - int count; - char *retval; - - list = NULL; - - display = gdk_x11_lookup_xdisplay (xdisplay); - count = gdk_text_property_to_utf8_list_for_display (display, - gdk_x11_xatom_to_atom_for_display (display, prop->encoding), - prop->format, - prop->value, - prop->nitems, - &list); - - if (count == 0) - retval = NULL; - else - { - retval = list[0]; - list[0] = g_strdup (""); /* something to free */ - } - - g_strfreev (list); - - return retval; -} - void meta_ui_theme_get_frame_borders (MetaUI *ui, MetaFrameType type, @@ -797,196 +725,6 @@ meta_ui_have_a_theme (void) return meta_theme_get_current () != NULL; } -static void -meta_ui_accelerator_parse (const char *accel, - guint *keysym, - guint *keycode, - GdkModifierType *keymask) -{ - const char *above_tab; - - if (accel[0] == '0' && accel[1] == 'x') - { - *keysym = 0; - *keycode = (guint) strtoul (accel, NULL, 16); - *keymask = 0; - - return; - } - - /* The key name 'Above_Tab' is special - it's not an actual keysym name, - * but rather refers to the key above the tab key. In order to use - * the GDK parsing for modifiers in combination with it, we substitute - * it with 'Tab' temporarily before calling gtk_accelerator_parse(). - */ -#define is_word_character(c) (g_ascii_isalnum(c) || ((c) == '_')) -#define ABOVE_TAB "Above_Tab" -#define ABOVE_TAB_LEN 9 - - above_tab = strstr (accel, ABOVE_TAB); - if (above_tab && - (above_tab == accel || !is_word_character (above_tab[-1])) && - !is_word_character (above_tab[ABOVE_TAB_LEN])) - { - char *before = g_strndup (accel, above_tab - accel); - char *after = g_strdup (above_tab + ABOVE_TAB_LEN); - char *replaced = g_strconcat (before, "Tab", after, NULL); - - gtk_accelerator_parse (replaced, NULL, keymask); - - g_free (before); - g_free (after); - g_free (replaced); - - *keysym = META_KEY_ABOVE_TAB; - return; - } - -#undef is_word_character -#undef ABOVE_TAB -#undef ABOVE_TAB_LEN - - gtk_accelerator_parse (accel, keysym, keymask); -} - -gboolean -meta_ui_parse_accelerator (const char *accel, - unsigned int *keysym, - unsigned int *keycode, - MetaVirtualModifier *mask) -{ - GdkModifierType gdk_mask = 0; - guint gdk_sym = 0; - guint gdk_code = 0; - - *keysym = 0; - *keycode = 0; - *mask = 0; - - if (!accel[0] || strcmp (accel, "disabled") == 0) - return TRUE; - - meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask); - if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0) - return FALSE; - - if (gdk_sym == None && gdk_code == 0) - return FALSE; - - if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ - return FALSE; - - *keysym = gdk_sym; - *keycode = gdk_code; - - if (gdk_mask & GDK_SHIFT_MASK) - *mask |= META_VIRTUAL_SHIFT_MASK; - if (gdk_mask & GDK_CONTROL_MASK) - *mask |= META_VIRTUAL_CONTROL_MASK; - if (gdk_mask & GDK_MOD1_MASK) - *mask |= META_VIRTUAL_ALT_MASK; - if (gdk_mask & GDK_MOD2_MASK) - *mask |= META_VIRTUAL_MOD2_MASK; - if (gdk_mask & GDK_MOD3_MASK) - *mask |= META_VIRTUAL_MOD3_MASK; - if (gdk_mask & GDK_MOD4_MASK) - *mask |= META_VIRTUAL_MOD4_MASK; - if (gdk_mask & GDK_MOD5_MASK) - *mask |= META_VIRTUAL_MOD5_MASK; - if (gdk_mask & GDK_SUPER_MASK) - *mask |= META_VIRTUAL_SUPER_MASK; - if (gdk_mask & GDK_HYPER_MASK) - *mask |= META_VIRTUAL_HYPER_MASK; - if (gdk_mask & GDK_META_MASK) - *mask |= META_VIRTUAL_META_MASK; - - return TRUE; -} - -/* Caller responsible for freeing return string of meta_ui_accelerator_name! */ -gchar* -meta_ui_accelerator_name (unsigned int keysym, - MetaVirtualModifier mask) -{ - GdkModifierType mods = 0; - - if (keysym == 0 && mask == 0) - { - return g_strdup ("disabled"); - } - - if (mask & META_VIRTUAL_SHIFT_MASK) - mods |= GDK_SHIFT_MASK; - if (mask & META_VIRTUAL_CONTROL_MASK) - mods |= GDK_CONTROL_MASK; - if (mask & META_VIRTUAL_ALT_MASK) - mods |= GDK_MOD1_MASK; - if (mask & META_VIRTUAL_MOD2_MASK) - mods |= GDK_MOD2_MASK; - if (mask & META_VIRTUAL_MOD3_MASK) - mods |= GDK_MOD3_MASK; - if (mask & META_VIRTUAL_MOD4_MASK) - mods |= GDK_MOD4_MASK; - if (mask & META_VIRTUAL_MOD5_MASK) - mods |= GDK_MOD5_MASK; - if (mask & META_VIRTUAL_SUPER_MASK) - mods |= GDK_SUPER_MASK; - if (mask & META_VIRTUAL_HYPER_MASK) - mods |= GDK_HYPER_MASK; - if (mask & META_VIRTUAL_META_MASK) - mods |= GDK_META_MASK; - - return gtk_accelerator_name (keysym, mods); - -} - -gboolean -meta_ui_parse_modifier (const char *accel, - MetaVirtualModifier *mask) -{ - GdkModifierType gdk_mask = 0; - guint gdk_sym = 0; - guint gdk_code = 0; - - *mask = 0; - - if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0) - return TRUE; - - meta_ui_accelerator_parse (accel, &gdk_sym, &gdk_code, &gdk_mask); - if (gdk_mask == 0 && gdk_sym == 0 && gdk_code == 0) - return FALSE; - - if (gdk_sym != None || gdk_code != 0) - return FALSE; - - if (gdk_mask & GDK_RELEASE_MASK) /* we don't allow this */ - return FALSE; - - if (gdk_mask & GDK_SHIFT_MASK) - *mask |= META_VIRTUAL_SHIFT_MASK; - if (gdk_mask & GDK_CONTROL_MASK) - *mask |= META_VIRTUAL_CONTROL_MASK; - if (gdk_mask & GDK_MOD1_MASK) - *mask |= META_VIRTUAL_ALT_MASK; - if (gdk_mask & GDK_MOD2_MASK) - *mask |= META_VIRTUAL_MOD2_MASK; - if (gdk_mask & GDK_MOD3_MASK) - *mask |= META_VIRTUAL_MOD3_MASK; - if (gdk_mask & GDK_MOD4_MASK) - *mask |= META_VIRTUAL_MOD4_MASK; - if (gdk_mask & GDK_MOD5_MASK) - *mask |= META_VIRTUAL_MOD5_MASK; - if (gdk_mask & GDK_SUPER_MASK) - *mask |= META_VIRTUAL_SUPER_MASK; - if (gdk_mask & GDK_HYPER_MASK) - *mask |= META_VIRTUAL_HYPER_MASK; - if (gdk_mask & GDK_META_MASK) - *mask |= META_VIRTUAL_META_MASK; - - return TRUE; -} - gboolean meta_ui_window_is_widget (MetaUI *ui, Window xwindow) diff --git a/src/ui/ui.h b/src/ui/ui.h index ca52f4c45..56e19fce8 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -46,13 +46,6 @@ Display* meta_ui_get_display (void); gint meta_ui_get_screen_number (void); -void meta_ui_add_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data); -void meta_ui_remove_event_func (Display *xdisplay, - MetaEventFunc func, - gpointer data); - MetaUI* meta_ui_new (Display *xdisplay, Screen *screen); void meta_ui_free (MetaUI *ui); @@ -149,28 +142,9 @@ GdkPixbuf* meta_ui_get_default_mini_icon (MetaUI *ui); gboolean meta_ui_window_should_not_cause_focus (Display *xdisplay, Window xwindow); -char* meta_text_property_to_utf8 (Display *xdisplay, - const XTextProperty *prop); - void meta_ui_set_current_theme (const char *name); gboolean meta_ui_have_a_theme (void); -/* Not a real key symbol but means "key above the tab key"; this is - * used as the default keybinding for cycle_group. - * 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are - * randomly chosen */ -#define META_KEY_ABOVE_TAB 0x2f7259c9 - -gboolean meta_ui_parse_accelerator (const char *accel, - unsigned int *keysym, - unsigned int *keycode, - MetaVirtualModifier *mask); -gboolean meta_ui_parse_modifier (const char *accel, - MetaVirtualModifier *mask); - -/* Caller responsible for freeing return string of meta_ui_accelerator_name! */ -gchar* meta_ui_accelerator_name (unsigned int keysym, - MetaVirtualModifier mask); gboolean meta_ui_window_is_widget (MetaUI *ui, Window xwindow); diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c new file mode 100644 index 000000000..c45476112 --- /dev/null +++ b/src/wayland/meta-wayland-data-device.c @@ -0,0 +1,548 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* The file is based on src/data-device.c from Weston */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "meta-wayland-data-device.h" +#include "meta-wayland-seat.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-private.h" + +static void +data_offer_accept (struct wl_client *client, + struct wl_resource *resource, + guint32 serial, + const char *mime_type) +{ + MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); + + /* FIXME: Check that client is currently focused by the input + * device that is currently dragging this data source. Should + * this be a wl_data_device request? */ + + if (offer->source) + wl_data_source_send_target (offer->source->resource, mime_type); +} + +static void +data_offer_receive (struct wl_client *client, struct wl_resource *resource, + const char *mime_type, int32_t fd) +{ + MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); + + if (offer->source) + wl_data_source_send_send (offer->source->resource, mime_type, fd); + + close (fd); +} + +static void +data_offer_destroy (struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wl_data_offer_interface data_offer_interface = { + data_offer_accept, + data_offer_receive, + data_offer_destroy, +}; + +static void +destroy_data_offer (struct wl_resource *resource) +{ + MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource); + + if (offer->source) + wl_list_remove (&offer->source_destroy_listener.link); + + g_slice_free (MetaWaylandDataOffer, offer); +} + +static void +destroy_offer_data_source (struct wl_listener *listener, void *data) +{ + MetaWaylandDataOffer *offer; + + offer = wl_container_of (listener, offer, source_destroy_listener); + + offer->source = NULL; +} + +static struct wl_resource * +meta_wayland_data_source_send_offer (MetaWaylandDataSource *source, + struct wl_resource *target) +{ + MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer); + char **p; + + offer->source = source; + offer->source_destroy_listener.notify = destroy_offer_data_source; + + offer->resource = wl_resource_create (wl_resource_get_client (target), + &wl_data_offer_interface, + MIN (META_WL_DATA_OFFER_VERSION, + wl_resource_get_version (target)), 0); + wl_resource_set_implementation (offer->resource, &data_offer_interface, + offer, destroy_data_offer); + wl_resource_add_destroy_listener (source->resource, + &offer->source_destroy_listener); + + wl_data_device_send_data_offer (target, offer->resource); + + wl_array_for_each (p, &source->mime_types) + wl_data_offer_send_offer (offer->resource, *p); + + return offer->resource; +} + +static void +data_source_offer (struct wl_client *client, + struct wl_resource *resource, const char *type) +{ + MetaWaylandDataSource *source = wl_resource_get_user_data (resource); + char **p; + + p = wl_array_add (&source->mime_types, sizeof *p); + if (p) + *p = strdup (type); + if (!p || !*p) + wl_resource_post_no_memory (resource); +} + +static void +data_source_destroy (struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static struct wl_data_source_interface data_source_interface = { + data_source_offer, + data_source_destroy +}; + +typedef struct { + MetaWaylandPointerGrab generic; + + MetaWaylandSeat *seat; + struct wl_client *drag_client; + + MetaWaylandSurface *drag_focus; + struct wl_resource *drag_focus_data_device; + struct wl_listener drag_focus_listener; + + MetaWaylandSurface *drag_surface; + struct wl_listener drag_icon_listener; + + MetaWaylandDataSource *drag_data_source; + struct wl_listener drag_data_source_listener; +} MetaWaylandDragGrab; + +static void +destroy_drag_focus (struct wl_listener *listener, void *data) +{ + MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener); + + grab->drag_focus_data_device = NULL; +} + +static void +drag_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface) +{ + MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; + MetaWaylandSeat *seat = drag_grab->seat; + struct wl_resource *resource, *offer = NULL; + struct wl_display *display; + guint32 serial; + wl_fixed_t sx, sy; + + if (drag_grab->drag_focus == surface) + return; + + if (drag_grab->drag_focus_data_device) + { + wl_data_device_send_leave (drag_grab->drag_focus_data_device); + wl_list_remove (&drag_grab->drag_focus_listener.link); + drag_grab->drag_focus_data_device = NULL; + drag_grab->drag_focus = NULL; + } + + if (!surface) + return; + + if (!drag_grab->drag_data_source && + wl_resource_get_client (surface->resource) != drag_grab->drag_client) + return; + + resource = + wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (surface->resource)); + if (!resource) + return; + + display = wl_client_get_display (wl_resource_get_client (resource)); + serial = wl_display_next_serial (display); + + if (drag_grab->drag_data_source) + offer = meta_wayland_data_source_send_offer (drag_grab->drag_data_source, + resource); + + meta_wayland_pointer_get_relative_coordinates (grab->pointer, surface, &sx, &sy); + wl_data_device_send_enter (resource, serial, surface->resource, + sx, sy, offer); + + drag_grab->drag_focus = surface; + + drag_grab->drag_focus_data_device = resource; + drag_grab->drag_focus_listener.notify = destroy_drag_focus; + wl_resource_add_destroy_listener (resource, &drag_grab->drag_focus_listener); +} + +static void +drag_grab_motion (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; + wl_fixed_t sx, sy; + + if (drag_grab->drag_focus_data_device) + { + meta_wayland_pointer_get_relative_coordinates (grab->pointer, + drag_grab->drag_focus, + &sx, &sy); + wl_data_device_send_motion (drag_grab->drag_focus_data_device, + clutter_event_get_time (event), + sx, sy); + } +} + +static void +data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab) +{ + if (drag_grab->drag_surface) + { + drag_grab->drag_surface = NULL; + wl_list_remove (&drag_grab->drag_icon_listener.link); + } + + if (drag_grab->drag_data_source) + wl_list_remove (&drag_grab->drag_data_source_listener.link); + + drag_grab_focus (&drag_grab->generic, NULL); + + meta_wayland_pointer_end_grab (drag_grab->generic.pointer); + g_slice_free (MetaWaylandDragGrab, drag_grab); +} + +static void +drag_grab_button (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab; + MetaWaylandSeat *seat = drag_grab->seat; + ClutterEventType event_type = clutter_event_type (event); + + if (drag_grab->drag_focus_data_device && + drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) && + event_type == CLUTTER_BUTTON_RELEASE) + wl_data_device_send_drop (drag_grab->drag_focus_data_device); + + if (seat->pointer.button_count == 0 && + event_type == CLUTTER_BUTTON_RELEASE) + data_device_end_drag_grab (drag_grab); +} + +static const MetaWaylandPointerGrabInterface drag_grab_interface = { + drag_grab_focus, + drag_grab_motion, + drag_grab_button, +}; + +static void +destroy_data_device_source (struct wl_listener *listener, void *data) +{ + MetaWaylandDragGrab *drag_grab = + wl_container_of (listener, drag_grab, drag_data_source_listener); + + drag_grab->drag_data_source = NULL; + data_device_end_drag_grab (drag_grab); +} + +static void +destroy_data_device_icon (struct wl_listener *listener, void *data) +{ + MetaWaylandDragGrab *drag_grab = + wl_container_of (listener, drag_grab, drag_data_source_listener); + + drag_grab->drag_surface = NULL; +} + +static void +data_device_start_drag (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *source_resource, + struct wl_resource *origin_resource, + struct wl_resource *icon_resource, guint32 serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + MetaWaylandDragGrab *drag_grab; + + if ((seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + !seat->pointer.focus_surface || + seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource))) + return; + + /* FIXME: Check that the data source type array isn't empty. */ + + if (seat->pointer.grab != &seat->pointer.default_grab) + return; + + drag_grab = g_slice_new0 (MetaWaylandDragGrab); + + drag_grab->generic.interface = &drag_grab_interface; + drag_grab->generic.pointer = &seat->pointer; + + drag_grab->drag_client = client; + drag_grab->seat = seat; + + if (source_resource) + { + drag_grab->drag_data_source = wl_resource_get_user_data (source_resource); + drag_grab->drag_data_source_listener.notify = destroy_data_device_source; + wl_resource_add_destroy_listener (source_resource, + &drag_grab->drag_data_source_listener); + } + + if (icon_resource) + { + drag_grab->drag_surface = wl_resource_get_user_data (icon_resource); + drag_grab->drag_icon_listener.notify = destroy_data_device_icon; + wl_resource_add_destroy_listener (icon_resource, + &drag_grab->drag_icon_listener); + } + + meta_wayland_pointer_set_focus (&seat->pointer, NULL); + meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab); +} + +static void +destroy_selection_data_source (struct wl_listener *listener, void *data) +{ + MetaWaylandSeat *seat = + wl_container_of (listener, seat, selection_data_source_listener); + struct wl_resource *data_device; + struct wl_resource *focus = NULL; + + seat->selection_data_source = NULL; + + focus = seat->keyboard.focus_resource; + + if (focus) + { + data_device = + wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (focus)); + if (data_device) + wl_data_device_send_selection (data_device, NULL); + } +} + +static void +meta_wayland_seat_set_selection (MetaWaylandSeat *seat, + MetaWaylandDataSource *source, + guint32 serial) +{ + struct wl_resource *data_device, *offer; + struct wl_resource *focus = NULL; + + if (seat->selection_data_source && + seat->selection_serial - serial < UINT32_MAX / 2) + return; + + if (seat->selection_data_source) + { + wl_data_source_send_cancelled (seat->selection_data_source->resource); + wl_list_remove (&seat->selection_data_source_listener.link); + seat->selection_data_source = NULL; + } + + seat->selection_data_source = source; + seat->selection_serial = serial; + + focus = seat->keyboard.focus_resource; + + if (focus) + { + data_device = + wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (focus)); + if (data_device && source) + { + offer = + meta_wayland_data_source_send_offer (seat->selection_data_source, + data_device); + wl_data_device_send_selection (data_device, offer); + } + else if (data_device) + { + wl_data_device_send_selection (data_device, NULL); + } + } + + if (source) + { + seat->selection_data_source_listener.notify = + destroy_selection_data_source; + wl_resource_add_destroy_listener (source->resource, + &seat->selection_data_source_listener); + } +} + +static void +data_device_set_selection (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *source_resource, + guint32 serial) +{ + if (!source_resource) + return; + + /* FIXME: Store serial and check against incoming serial here. */ + meta_wayland_seat_set_selection (wl_resource_get_user_data (resource), + wl_resource_get_user_data (source_resource), + serial); +} + +static const struct wl_data_device_interface data_device_interface = { + data_device_start_drag, + data_device_set_selection, +}; + +static void +destroy_data_source (struct wl_resource *resource) +{ + MetaWaylandDataSource *source = wl_resource_get_user_data (resource); + char **p; + + wl_array_for_each (p, &source->mime_types) free (*p); + + wl_array_release (&source->mime_types); + + g_slice_free (MetaWaylandDataSource, source); +} + +static void +create_data_source (struct wl_client *client, + struct wl_resource *resource, guint32 id) +{ + MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource); + + source->resource = wl_resource_create (client, &wl_data_source_interface, + MIN (META_WL_DATA_SOURCE_VERSION, + wl_resource_get_version (resource)), id); + wl_resource_set_implementation (source->resource, &data_source_interface, + source, destroy_data_source); + + wl_array_init (&source->mime_types); +} + +static void +unbind_data_device (struct wl_resource *resource) +{ + wl_list_remove (wl_resource_get_link (resource)); +} + +static void +get_data_device (struct wl_client *client, + struct wl_resource *manager_resource, + guint32 id, struct wl_resource *seat_resource) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_data_device_interface, + MIN (META_WL_DATA_DEVICE_VERSION, + wl_resource_get_version (manager_resource)), id); + wl_resource_set_implementation (resource, &data_device_interface, seat, unbind_data_device); + wl_list_insert (&seat->data_device_resource_list, wl_resource_get_link (resource)); +} + +static const struct wl_data_device_manager_interface manager_interface = { + create_data_source, + get_data_device +}; + +static void +bind_manager (struct wl_client *client, + void *data, guint32 version, guint32 id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_data_device_manager_interface, + MIN (version, META_WL_DATA_DEVICE_MANAGER_VERSION), id); + wl_resource_set_implementation (resource, &manager_interface, NULL, NULL); +} + +void +meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat) +{ + struct wl_resource *data_device, *focus, *offer; + MetaWaylandDataSource *source; + + focus = seat->keyboard.focus_resource; + if (!focus) + return; + + data_device = wl_resource_find_for_client (&seat->data_device_resource_list, + wl_resource_get_client (focus)); + if (!data_device) + return; + + source = seat->selection_data_source; + if (source) + { + offer = meta_wayland_data_source_send_offer (source, data_device); + wl_data_device_send_selection (data_device, offer); + } +} + +int +meta_wayland_data_device_manager_init (struct wl_display *display) +{ + if (wl_global_create (display, + &wl_data_device_manager_interface, + META_WL_DATA_DEVICE_MANAGER_VERSION, + NULL, bind_manager) == NULL) + return -1; + + return 0; +} diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h new file mode 100644 index 000000000..87f977437 --- /dev/null +++ b/src/wayland/meta-wayland-data-device.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __META_WAYLAND_DATA_DEVICE_H__ +#define __META_WAYLAND_DATA_DEVICE_H__ + +#include + +#include "meta-wayland-seat.h" + +void +meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat); + +int +meta_wayland_data_device_manager_init (struct wl_display *display); + +#endif /* __META_WAYLAND_DATA_DEVICE_H__ */ diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c new file mode 100644 index 000000000..5aac8fba7 --- /dev/null +++ b/src/wayland/meta-wayland-keyboard.c @@ -0,0 +1,534 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * 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. + */ + +/* + * Copyright © 2010-2011 Intel Corporation + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2012 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* The file is based on src/input.c from Weston */ + +#define _GNU_SOURCE + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "meta-wayland-private.h" + +static int +create_anonymous_file (off_t size, + GError **error) +{ + static const char template[] = "mutter-shared-XXXXXX"; + char *path; + int fd, flags; + + fd = g_file_open_tmp (template, &path, error); + + if (fd == -1) + return -1; + + unlink (path); + g_free (path); + + flags = fcntl (fd, F_GETFD); + if (flags == -1) + goto err; + + if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) + goto err; + + if (ftruncate (fd, size) < 0) + goto err; + + return fd; + + err: + g_set_error_literal (error, + G_FILE_ERROR, + g_file_error_from_errno (errno), + strerror (errno)); + close (fd); + + return -1; +} + +static void +inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard, + int flags) +{ + MetaWaylandCompositor *compositor; + struct wl_client *xclient; + struct wl_resource *keyboard_resource; + + compositor = meta_wayland_compositor_get_default (); + xclient = compositor->xwayland_manager.client; + + wl_resource_for_each (keyboard_resource, &keyboard->resource_list) + { + if ((flags & META_WAYLAND_KEYBOARD_SKIP_XCLIENTS) && + wl_resource_get_client (keyboard_resource) == xclient) + continue; + + wl_keyboard_send_keymap (keyboard_resource, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + keyboard->xkb_info.keymap_fd, + keyboard->xkb_info.keymap_size); + } +} + +static void +meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard, + struct xkb_keymap *keymap, + int flags) +{ + MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info; + GError *error = NULL; + char *keymap_str; + size_t previous_size; + + if (keymap == NULL) + { + g_warning ("Attempting to set null keymap (compilation probably failed)"); + return; + } + + xkb_keymap_unref (xkb_info->keymap); + xkb_info->keymap = keymap; + + xkb_state_unref (xkb_info->state); + xkb_info->state = xkb_state_new (keymap); + + keymap_str = xkb_map_get_as_string (xkb_info->keymap); + if (keymap_str == NULL) + { + g_warning ("failed to get string version of keymap"); + return; + } + previous_size = xkb_info->keymap_size; + xkb_info->keymap_size = strlen (keymap_str) + 1; + + if (xkb_info->keymap_fd >= 0) + close (xkb_info->keymap_fd); + + xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error); + if (xkb_info->keymap_fd < 0) + { + g_warning ("creating a keymap file for %lu bytes failed: %s", + (unsigned long) xkb_info->keymap_size, + error->message); + g_clear_error (&error); + goto err_keymap_str; + } + + if (xkb_info->keymap_area) + munmap (xkb_info->keymap_area, previous_size); + + xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, xkb_info->keymap_fd, 0); + if (xkb_info->keymap_area == MAP_FAILED) + { + g_warning ("failed to mmap() %lu bytes\n", + (unsigned long) xkb_info->keymap_size); + goto err_dev_zero; + } + strcpy (xkb_info->keymap_area, keymap_str); + free (keymap_str); + +#if defined(CLUTTER_WINDOWING_EGL) + /* XXX -- the evdev backend can be used regardless of the + * windowing backend. To do this properly we need a Clutter + * API to check the input backend. */ + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + ClutterDeviceManager *manager; + manager = clutter_device_manager_get_default (); + clutter_evdev_set_keyboard_map (manager, xkb_info->keymap); + } +#endif + + inform_clients_of_new_keymap (keyboard, flags); + + return; + +err_dev_zero: + close (xkb_info->keymap_fd); + xkb_info->keymap_fd = -1; +err_keymap_str: + free (keymap_str); + return; +} + +static void +keyboard_handle_focus_surface_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_surface_listener); + + keyboard->focus_surface = NULL; + + if (keyboard->focus_resource) + { + wl_list_remove (&keyboard->focus_resource_listener.link); + keyboard->focus_resource = NULL; + } +} + +static void +keyboard_handle_focus_resource_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_resource_listener); + + keyboard->focus_resource = NULL; +} + +static gboolean +default_grab_key (MetaWaylandKeyboardGrab *grab, + uint32_t time, uint32_t key, uint32_t state) +{ + MetaWaylandKeyboard *keyboard = grab->keyboard; + struct wl_resource *resource; + uint32_t serial; + + resource = keyboard->focus_resource; + if (resource) + { + struct wl_client *client = wl_resource_get_client (resource); + struct wl_display *display = wl_client_get_display (client); + serial = wl_display_next_serial (display); + wl_keyboard_send_key (resource, serial, time, key, state); + } + + return resource != NULL; +} + +static struct wl_resource * +find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface) +{ + struct wl_client *client; + + if (!surface) + return NULL; + + if (!surface->resource) + return NULL; + + client = wl_resource_get_client (surface->resource); + + return wl_resource_find_for_client (list, client); +} + +static void +default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + MetaWaylandKeyboard *keyboard = grab->keyboard; + + if (keyboard->focus_resource) + { + wl_keyboard_send_modifiers (keyboard->focus_resource, serial, mods_depressed, + mods_latched, mods_locked, group); + } +} + +static const MetaWaylandKeyboardGrabInterface + default_keyboard_grab_interface = { + default_grab_key, + default_grab_modifiers, +}; + +gboolean +meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, + struct wl_display *display) +{ + memset (keyboard, 0, sizeof *keyboard); + keyboard->xkb_info.keymap_fd = -1; + + wl_list_init (&keyboard->resource_list); + wl_array_init (&keyboard->keys); + + keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy; + keyboard->focus_resource_listener.notify = keyboard_handle_focus_resource_destroy; + + keyboard->default_grab.interface = &default_keyboard_grab_interface; + keyboard->default_grab.keyboard = keyboard; + keyboard->grab = &keyboard->default_grab; + + keyboard->display = display; + + keyboard->xkb_context = xkb_context_new (0 /* flags */); + + /* Compute a default until gnome-settings-daemon starts and sets + the appropriate values + */ + meta_wayland_keyboard_set_keymap_names (keyboard, + "evdev", + "pc105", + "us", "", "", 0); + + return TRUE; +} + +static void +meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info) +{ + xkb_keymap_unref (xkb_info->keymap); + xkb_state_unref (xkb_info->state); + + if (xkb_info->keymap_area) + munmap (xkb_info->keymap_area, xkb_info->keymap_size); + if (xkb_info->keymap_fd >= 0) + close (xkb_info->keymap_fd); +} + +static void +update_pressed_keys (MetaWaylandKeyboard *keyboard, + uint32_t evdev_code, + gboolean is_press) +{ + if (is_press) + { + uint32_t *end = (void *) ((char *) keyboard->keys.data + + keyboard->keys.size); + uint32_t *k; + + /* Make sure we don't already have this key. */ + for (k = keyboard->keys.data; k < end; k++) + if (*k == evdev_code) + return; + + /* Otherwise add the key to the list of pressed keys */ + k = wl_array_add (&keyboard->keys, sizeof (*k)); + *k = evdev_code; + } + else + { + uint32_t *end = (void *) ((char *) keyboard->keys.data + + keyboard->keys.size); + uint32_t *k; + + /* Remove the key from the array */ + for (k = keyboard->keys.data; k < end; k++) + if (*k == evdev_code) + { + *k = *(end - 1); + keyboard->keys.size -= sizeof (*k); + return; + } + + g_warning ("unexpected key release event for key 0x%x", evdev_code); + } +} + +static guint +evdev_code (const ClutterKeyEvent *event) +{ + /* clutter-xkb-utils.c adds a fixed offset of 8 to go into XKB's + * range, so we do the reverse here. */ + return event->hardware_keycode - 8; +} + +void +meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event) +{ + MetaWaylandKeyboardGrab *grab = keyboard->grab; + gboolean is_press = event->type == CLUTTER_KEY_PRESS; + struct xkb_state *state = keyboard->xkb_info.state; + enum xkb_state_component changed_state; + + update_pressed_keys (keyboard, evdev_code (event), is_press); + + changed_state = xkb_state_update_key (state, + event->hardware_keycode, + is_press ? XKB_KEY_DOWN : XKB_KEY_UP); + if (changed_state == 0) + return; + + grab->interface->modifiers (grab, + wl_display_next_serial (keyboard->display), + xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), + xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE)); +} + +gboolean +meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event) +{ + gboolean is_press = event->type == CLUTTER_KEY_PRESS; + gboolean handled; + + /* Synthetic key events are for autorepeat. Ignore those, as + * autorepeat in Wayland is done on the client side. */ + if (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC) + return FALSE; + + meta_verbose ("Handling key %s event code %d\n", + is_press ? "press" : "release", + event->hardware_keycode); + + handled = keyboard->grab->interface->key (keyboard->grab, + event->time, + evdev_code (event), + is_press); + + if (handled) + meta_verbose ("Sent event to wayland client\n"); + else + meta_verbose ("No wayland surface is focused, continuing normal operation\n"); + + return handled; +} + +void +meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard, + MetaWaylandSurface *surface) +{ + if (keyboard->focus_surface == surface && keyboard->focus_resource != NULL) + return; + + if (keyboard->focus_surface != NULL) + { + if (keyboard->focus_resource) + { + if (keyboard->focus_surface->resource) + { + struct wl_client *client = wl_resource_get_client (keyboard->focus_resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + wl_keyboard_send_leave (keyboard->focus_resource, serial, keyboard->focus_surface->resource); + } + + wl_list_remove (&keyboard->focus_resource_listener.link); + keyboard->focus_resource = NULL; + } + + wl_list_remove (&keyboard->focus_surface_listener.link); + keyboard->focus_surface = NULL; + } + + if (surface != NULL) + { + keyboard->focus_surface = surface; + wl_resource_add_destroy_listener (keyboard->focus_surface->resource, &keyboard->focus_surface_listener); + + keyboard->focus_resource = find_resource_for_surface (&keyboard->resource_list, surface); + if (keyboard->focus_resource) + { + struct wl_client *client = wl_resource_get_client (keyboard->focus_resource); + struct wl_display *display = wl_client_get_display (client); + struct xkb_state *state = keyboard->xkb_info.state; + uint32_t serial = wl_display_next_serial (display); + + wl_keyboard_send_modifiers (keyboard->focus_resource, serial, + xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED), + xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), + xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE)); + wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource, + &keyboard->keys); + + wl_resource_add_destroy_listener (keyboard->focus_resource, &keyboard->focus_resource_listener); + keyboard->focus_serial = serial; + } + } +} + +void +meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard, + MetaWaylandKeyboardGrab *grab) +{ + keyboard->grab = grab; + grab->keyboard = keyboard; + + /* XXX focus? */ +} + +void +meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard) +{ + keyboard->grab = &keyboard->default_grab; +} + +void +meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard) +{ + meta_wayland_xkb_info_destroy (&keyboard->xkb_info); + xkb_context_unref (keyboard->xkb_context); + + /* XXX: What about keyboard->resource_list? */ + wl_array_release (&keyboard->keys); +} + +void +meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard, + const char *rules, + const char *model, + const char *layout, + const char *variant, + const char *options, + int flags) +{ + struct xkb_rule_names xkb_names; + + xkb_names.rules = rules; + xkb_names.model = model; + xkb_names.layout = layout; + xkb_names.variant = variant; + xkb_names.options = options; + + meta_wayland_keyboard_take_keymap (keyboard, + xkb_keymap_new_from_names (keyboard->xkb_context, + &xkb_names, + 0 /* flags */), + flags); +} + diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h new file mode 100644 index 000000000..13fbf0a0b --- /dev/null +++ b/src/wayland/meta-wayland-keyboard.h @@ -0,0 +1,143 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * 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. + */ + +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2012 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __META_WAYLAND_KEYBOARD_H__ +#define __META_WAYLAND_KEYBOARD_H__ + +#include +#include +#include + +struct _MetaWaylandKeyboardGrabInterface +{ + gboolean (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time, + uint32_t key, uint32_t state); + void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group); +}; + +struct _MetaWaylandKeyboardGrab +{ + const MetaWaylandKeyboardGrabInterface *interface; + MetaWaylandKeyboard *keyboard; + MetaWaylandSurface *focus; + uint32_t key; +}; + +typedef struct +{ + struct xkb_keymap *keymap; + struct xkb_state *state; + int keymap_fd; + size_t keymap_size; + char *keymap_area; +} MetaWaylandXkbInfo; + +struct _MetaWaylandKeyboard +{ + struct wl_list resource_list; + + MetaWaylandSurface *focus_surface; + struct wl_listener focus_surface_listener; + struct wl_resource *focus_resource; + struct wl_listener focus_resource_listener; + uint32_t focus_serial; + + MetaWaylandKeyboardGrab *grab; + MetaWaylandKeyboardGrab default_grab; + uint32_t grab_key; + uint32_t grab_serial; + uint32_t grab_time; + + struct wl_array keys; + + struct wl_display *display; + + struct xkb_context *xkb_context; + MetaWaylandXkbInfo xkb_info; + + MetaWaylandKeyboardGrab input_method_grab; + struct wl_resource *input_method_resource; +}; + +gboolean +meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, + struct wl_display *display); + +typedef enum { + META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1, +} MetaWaylandKeyboardSetKeymapFlags; + +void +meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard, + const char *rules, + const char *model, + const char *layout, + const char *variant, + const char *options, + int flags); +gboolean +meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event); + +void +meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard, + MetaWaylandSurface *surface); + +void +meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device, + MetaWaylandKeyboardGrab *grab); + +void +meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard); + +void +meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard); + +void +meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event); + +#endif /* __META_WAYLAND_KEYBOARD_H__ */ diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c new file mode 100644 index 000000000..9e423a4e6 --- /dev/null +++ b/src/wayland/meta-wayland-pointer.c @@ -0,0 +1,598 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +/* + * Copyright © 2008 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* The file is based on src/input.c from Weston */ + +#include "config.h" + +#include +#include +#include + +#include "meta-wayland-pointer.h" +#include "meta-wayland-private.h" + +#include + +static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer); + +static void +pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener); + + pointer->focus_surface = NULL; + + if (pointer->focus_resource) + { + wl_list_remove (&pointer->focus_resource_listener.link); + pointer->focus_resource = NULL; + } +} + +static void +pointer_handle_focus_resource_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_resource_listener); + + pointer->focus_resource = NULL; +} + +static void +default_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface) +{ + MetaWaylandPointer *pointer = grab->pointer; + + if (pointer->button_count > 0) + return; + + meta_wayland_pointer_set_focus (pointer, surface); +} + +static void +default_grab_motion (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + struct wl_resource *resource; + + resource = grab->pointer->focus_resource; + if (resource) + { + wl_fixed_t sx, sy; + + meta_wayland_pointer_get_relative_coordinates (grab->pointer, + grab->pointer->focus_surface, + &sx, &sy); + wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy); + } +} + +static void +default_grab_button (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandPointer *pointer = grab->pointer; + struct wl_resource *resource; + ClutterEventType event_type; + + event_type = clutter_event_type (event); + + resource = pointer->focus_resource; + if (resource) + { + struct wl_client *client = wl_resource_get_client (resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t button; + uint32_t serial; + + button = clutter_event_get_button (event); + switch (button) + { + /* The evdev input right and middle button numbers are swapped + relative to how Clutter numbers them */ + case 2: + button = BTN_MIDDLE; + break; + + case 3: + button = BTN_RIGHT; + break; + + default: + button = button + BTN_LEFT - 1; + break; + } + + serial = wl_display_next_serial (display); + wl_pointer_send_button (resource, serial, + clutter_event_get_time (event), button, + event_type == CLUTTER_BUTTON_PRESS ? 1 : 0); + } + + if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE) + meta_wayland_pointer_set_focus (pointer, pointer->current); +} + +static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = { + default_grab_focus, + default_grab_motion, + default_grab_button +}; + +/* + * The pointer constrain code is mostly a rip-off of the XRandR code from Xorg. + * (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder) + * + * Copyright © 2006 Keith Packard + * Copyright 2010 Red Hat, Inc + * + */ + +static gboolean +check_all_screen_monitors(MetaMonitorInfo *monitors, + unsigned n_monitors, + float x, + float y) +{ + unsigned int i; + + for (i = 0; i < n_monitors; i++) + { + MetaMonitorInfo *monitor = &monitors[i]; + int left, right, top, bottom; + + left = monitor->rect.x; + right = left + monitor->rect.width; + top = monitor->rect.y; + bottom = left + monitor->rect.height; + + if ((x >= left) && (x < right) && (y >= top) && (y < bottom)) + return TRUE; + } + + return FALSE; +} + +static void +constrain_all_screen_monitors (ClutterInputDevice *device, + MetaMonitorInfo *monitors, + unsigned n_monitors, + float *x, + float *y) +{ + ClutterPoint current; + unsigned int i; + + clutter_input_device_get_coords (device, NULL, ¤t); + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + for (i = 0; i < n_monitors; i++) + { + MetaMonitorInfo *monitor = &monitors[i]; + int left, right, top, bottom; + float nx, ny; + + left = monitor->rect.x; + right = left + monitor->rect.width; + top = monitor->rect.y; + bottom = left + monitor->rect.height; + + nx = current.x; + ny = current.y; + + if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) + { + if (*x < left) + *x = left; + if (*x >= right) + *x = right - 1; + if (*y < top) + *y = top; + if (*y >= bottom) + *y = bottom - 1; + + return; + } + } +} + +static void +pointer_constrain_callback (ClutterInputDevice *device, + guint32 time, + float *new_x, + float *new_y, + gpointer user_data) +{ + MetaMonitorManager *monitor_manager; + MetaMonitorInfo *monitors; + unsigned int n_monitors; + gboolean ret; + + monitor_manager = meta_monitor_manager_get (); + monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors); + + /* if we're moving inside a monitor, we're fine */ + ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y); + if (ret == TRUE) + return; + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y); +} + +void +meta_wayland_pointer_init (MetaWaylandPointer *pointer) +{ + ClutterDeviceManager *manager; + ClutterInputDevice *device; + ClutterPoint current; + + memset (pointer, 0, sizeof *pointer); + wl_list_init (&pointer->resource_list); + + pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy; + pointer->focus_resource_listener.notify = pointer_handle_focus_resource_destroy; + + pointer->default_grab.interface = &default_pointer_grab_interface; + pointer->default_grab.pointer = pointer; + pointer->grab = &pointer->default_grab; + + manager = clutter_device_manager_get_default (); + device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE); + +#if defined(CLUTTER_WINDOWING_EGL) + /* XXX -- the evdev backend can be used regardless of the + * windowing backend. To do this properly we need a Clutter + * API to check the input backend. */ + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL)) + { + clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback, + pointer, NULL); + } +#endif + + clutter_input_device_get_coords (device, NULL, ¤t); + pointer->x = wl_fixed_from_double (current.x); + pointer->y = wl_fixed_from_double (current.y); +} + +void +meta_wayland_pointer_release (MetaWaylandPointer *pointer) +{ + /* Do nothing. */ +} + +static struct wl_resource * +find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface) +{ + struct wl_client *client; + + if (!surface) + return NULL; + + g_assert (surface->resource); + client = wl_resource_get_client (surface->resource); + + return wl_resource_find_for_client (list, client); +} + +void +meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + if (pointer->focus_surface == surface && pointer->focus_resource != NULL) + return; + + if (pointer->focus_surface) + { + if (pointer->focus_resource) + { + if (pointer->focus_surface->resource) + { + struct wl_client *client = wl_resource_get_client (pointer->focus_resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + wl_pointer_send_leave (pointer->focus_resource, serial, pointer->focus_surface->resource); + } + + wl_list_remove (&pointer->focus_resource_listener.link); + pointer->focus_resource = NULL; + } + + wl_list_remove (&pointer->focus_surface_listener.link); + pointer->focus_surface = NULL; + } + + if (surface != NULL) + { + pointer->focus_surface = surface; + wl_resource_add_destroy_listener (pointer->focus_surface->resource, &pointer->focus_surface_listener); + + pointer->focus_resource = find_resource_for_surface (&pointer->resource_list, surface); + if (pointer->focus_resource) + { + struct wl_client *client = wl_resource_get_client (pointer->focus_resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + + meta_window_handle_enter (pointer->focus_surface->window, + /* XXX -- can we reliably get a timestamp for setting focus? */ + clutter_get_current_event_time (), + wl_fixed_to_int (pointer->x), + wl_fixed_to_int (pointer->y)); + + { + wl_fixed_t sx, sy; + + meta_wayland_pointer_get_relative_coordinates (pointer, pointer->focus_surface, &sx, &sy); + wl_pointer_send_enter (pointer->focus_resource, serial, pointer->focus_surface->resource, sx, sy); + } + + wl_resource_add_destroy_listener (pointer->focus_resource, &pointer->focus_resource_listener); + pointer->focus_serial = serial; + } + } +} + +void +meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, + MetaWaylandPointerGrab *grab) +{ + const MetaWaylandPointerGrabInterface *interface; + + pointer->grab = grab; + interface = pointer->grab->interface; + grab->pointer = pointer; + + if (pointer->current) + interface->focus (pointer->grab, pointer->current); +} + +void +meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer) +{ + const MetaWaylandPointerGrabInterface *interface; + + pointer->grab = &pointer->default_grab; + interface = pointer->grab->interface; + interface->focus (pointer->grab, pointer->current); +} + +typedef struct { + MetaWaylandPointerGrab generic; + + struct wl_client *grab_client; + struct wl_list all_popups; +} MetaWaylandPopupGrab; + +typedef struct { + MetaWaylandPopupGrab *grab; + MetaWaylandSurface *surface; + struct wl_listener surface_destroy_listener; + + struct wl_list link; +} MetaWaylandPopup; + +static void +popup_grab_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface) +{ + MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab; + + /* Popup grabs are in owner-events mode (ie, events for the same client + are reported as normal) */ + if (surface && wl_resource_get_client (surface->resource) == popup_grab->grab_client) + default_grab_focus (grab, surface); + else + meta_wayland_pointer_set_focus (grab->pointer, NULL); +} + +static void +popup_grab_motion (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + default_grab_motion (grab, event); +} + +static void +popup_grab_button (MetaWaylandPointerGrab *grab, + const ClutterEvent *event) +{ + MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab; + MetaWaylandPointer *pointer = grab->pointer; + + if (pointer->focus_resource) + { + /* This is ensured by popup_grab_focus */ + g_assert (wl_resource_get_client (pointer->focus_resource) == popup_grab->grab_client); + + default_grab_button (grab, event); + } + else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE && + pointer->button_count == 0) + meta_wayland_pointer_end_popup_grab (grab->pointer); +} + +static MetaWaylandPointerGrabInterface popup_grab_interface = { + popup_grab_focus, + popup_grab_motion, + popup_grab_button +}; + +static void +meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer) +{ + MetaWaylandPopupGrab *popup_grab; + MetaWaylandPopup *popup, *tmp; + + popup_grab = (MetaWaylandPopupGrab*)pointer->grab; + + g_assert (popup_grab->generic.interface == &popup_grab_interface); + + wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link) + { + meta_wayland_surface_popup_done (popup->surface); + wl_list_remove (&popup->surface_destroy_listener.link); + wl_list_remove (&popup->link); + g_slice_free (MetaWaylandPopup, popup); + } + + { + MetaDisplay *display = meta_get_display (); + meta_display_end_grab_op (display, + meta_display_get_current_time_roundtrip (display)); + } + + meta_wayland_pointer_end_grab (pointer); + g_slice_free (MetaWaylandPopupGrab, popup_grab); +} + +static void +on_popup_surface_destroy (struct wl_listener *listener, + void *data) +{ + MetaWaylandPopup *popup = + wl_container_of (listener, popup, surface_destroy_listener); + MetaWaylandPopupGrab *popup_grab = popup->grab; + + wl_list_remove (&popup->link); + g_slice_free (MetaWaylandPopup, popup); + + if (wl_list_empty (&popup_grab->all_popups)) + meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer); +} + +gboolean +meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + MetaWaylandPopupGrab *grab; + MetaWaylandPopup *popup; + + if (pointer->grab != &pointer->default_grab) + { + if (pointer->grab->interface != &popup_grab_interface) + return FALSE; + + grab = (MetaWaylandPopupGrab*)pointer->grab; + + if (wl_resource_get_client (surface->resource) != grab->grab_client) + return FALSE; + } + + if (pointer->grab == &pointer->default_grab) + { + MetaWindow *window = surface->window; + + grab = g_slice_new0 (MetaWaylandPopupGrab); + grab->generic.interface = &popup_grab_interface; + grab->generic.pointer = pointer; + grab->grab_client = wl_resource_get_client (surface->resource); + wl_list_init (&grab->all_popups); + + meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab); + + meta_display_begin_grab_op (window->display, + window->screen, + window, + META_GRAB_OP_WAYLAND_CLIENT, + FALSE, /* pointer_already_grabbed */ + FALSE, /* frame_action */ + 1, /* button. XXX? */ + 0, /* modmask */ + meta_display_get_current_time_roundtrip (window->display), + wl_fixed_to_int (pointer->grab_x), + wl_fixed_to_int (pointer->grab_y)); + + } + else + grab = (MetaWaylandPopupGrab*)pointer->grab; + + popup = g_slice_new0 (MetaWaylandPopup); + popup->grab = grab; + popup->surface = surface; + popup->surface_destroy_listener.notify = on_popup_surface_destroy; + if (surface->xdg_popup.resource) + wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener); + else if (surface->wl_shell_surface.resource) + wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener); + + wl_list_insert (&grab->all_popups, &popup->link); + return TRUE; +} + +void +meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface, + wl_fixed_t *sx, + wl_fixed_t *sy) +{ + float xf = 0.0f, yf = 0.0f; + + if (surface->window) + { + ClutterActor *actor = + CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window)); + + if (actor) + clutter_actor_transform_stage_point (actor, + wl_fixed_to_double (pointer->x), + wl_fixed_to_double (pointer->y), + &xf, &yf); + } + + *sx = wl_fixed_from_double (xf); + *sy = wl_fixed_from_double (yf); +} + +void +meta_wayland_pointer_update_current_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface) +{ + pointer->current = surface; + if (surface != pointer->focus_surface) + { + const MetaWaylandPointerGrabInterface *interface = + pointer->grab->interface; + interface->focus (pointer->grab, surface); + } +} diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h new file mode 100644 index 000000000..d5e303838 --- /dev/null +++ b/src/wayland/meta-wayland-pointer.h @@ -0,0 +1,101 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __META_WAYLAND_POINTER_H__ +#define __META_WAYLAND_POINTER_H__ + +#include + +#include + +#include "meta-wayland-types.h" + +struct _MetaWaylandPointerGrabInterface +{ + void (*focus) (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface); + void (*motion) (MetaWaylandPointerGrab *grab, + const ClutterEvent *event); + void (*button) (MetaWaylandPointerGrab *grab, + const ClutterEvent *event); +}; + +struct _MetaWaylandPointerGrab +{ + const MetaWaylandPointerGrabInterface *interface; + MetaWaylandPointer *pointer; +}; + +struct _MetaWaylandPointer +{ + struct wl_list resource_list; + + MetaWaylandSurface *focus_surface; + struct wl_listener focus_surface_listener; + struct wl_resource *focus_resource; + struct wl_listener focus_resource_listener; + guint32 focus_serial; + guint32 click_serial; + + MetaWaylandPointerGrab *grab; + MetaWaylandPointerGrab default_grab; + wl_fixed_t grab_x, grab_y; + wl_fixed_t focus_x, focus_y; + guint32 grab_button; + guint32 grab_serial; + guint32 grab_time; + + wl_fixed_t x, y; /* TODO: remove, use ClutterInputDevice instead */ + MetaWaylandSurface *current; + + guint32 button_count; +}; + +void +meta_wayland_pointer_init (MetaWaylandPointer *pointer); + +void +meta_wayland_pointer_release (MetaWaylandPointer *pointer); + +void +meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface); + +void +meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, + MetaWaylandPointerGrab *grab); + +void +meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer); + +gboolean +meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, + MetaWaylandSurface *popup); + +void +meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface, + wl_fixed_t *x, + wl_fixed_t *y); + +void +meta_wayland_pointer_update_current_focus (MetaWaylandPointer *pointer, + MetaWaylandSurface *surface); + +#endif /* __META_WAYLAND_POINTER_H__ */ diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h new file mode 100644 index 000000000..d575e2f0c --- /dev/null +++ b/src/wayland/meta-wayland-private.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * 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. + */ + +#ifndef META_WAYLAND_PRIVATE_H +#define META_WAYLAND_PRIVATE_H + +#include +#include + +#include +#include + +#include "window-private.h" +#include + +#include "meta-wayland.h" +#include "meta-wayland-versions.h" +#include "meta-wayland-surface.h" +#include "meta-wayland-seat.h" + +typedef struct +{ + struct wl_resource *resource; + cairo_region_t *region; +} MetaWaylandRegion; + +typedef struct +{ + GSource source; + GPollFD pfd; + struct wl_display *display; +} WaylandEventSource; + +typedef struct +{ + struct wl_list link; + + /* Pointer back to the compositor */ + MetaWaylandCompositor *compositor; + + struct wl_resource *resource; +} MetaWaylandFrameCallback; + +typedef struct +{ + int display_index; + char *lockfile; + int abstract_fd; + int unix_fd; + pid_t pid; + struct wl_client *client; + struct wl_resource *xserver_resource; + char *display_name; + + GMainLoop *init_loop; +} MetaXWaylandManager; + +struct _MetaWaylandCompositor +{ + struct wl_display *wayland_display; + char *display_name; + struct wl_event_loop *wayland_loop; + ClutterActor *stage; + GHashTable *outputs; + GSource *wayland_event_source; + GList *surfaces; + struct wl_list frame_callbacks; + + MetaXWaylandManager xwayland_manager; + + MetaWaylandSeat *seat; +}; + +MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource); +void meta_wayland_buffer_ref (MetaWaylandBuffer *buffer); +void meta_wayland_buffer_unref (MetaWaylandBuffer *buffer); + +#endif /* META_WAYLAND_PRIVATE_H */ diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c new file mode 100644 index 000000000..f5e3867a4 --- /dev/null +++ b/src/wayland/meta-wayland-seat.c @@ -0,0 +1,503 @@ +/* + * Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * 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 "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include "meta-wayland-seat.h" +#include "meta-wayland-private.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-data-device.h" +#include "meta-window-actor-private.h" +#include "meta/meta-shaped-texture.h" +#include "meta-shaped-texture-private.h" +#include "meta-wayland-stage.h" +#include "meta-cursor-tracker-private.h" +#include "meta-surface-actor-wayland.h" + +#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10) + +static void +unbind_resource (struct wl_resource *resource) +{ + wl_list_remove (wl_resource_get_link (resource)); +} + +static void +set_cursor_surface (MetaWaylandSeat *seat, + MetaWaylandSurface *surface) +{ + if (seat->cursor_surface == surface) + return; + + if (seat->cursor_surface) + wl_list_remove (&seat->cursor_surface_destroy_listener.link); + + seat->cursor_surface = surface; + + if (seat->cursor_surface) + wl_resource_add_destroy_listener (seat->cursor_surface->resource, + &seat->cursor_surface_destroy_listener); +} + +void +meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat) +{ + MetaCursorReference *cursor; + + if (seat->cursor_tracker == NULL) + return; + + if (seat->cursor_surface && seat->cursor_surface->buffer) + { + struct wl_resource *buffer = seat->cursor_surface->buffer->resource; + cursor = meta_cursor_reference_from_buffer (seat->cursor_tracker, + buffer, + seat->hotspot_x, + seat->hotspot_y); + } + else + cursor = NULL; + + meta_cursor_tracker_set_window_cursor (seat->cursor_tracker, cursor); + + if (cursor) + meta_cursor_reference_unref (cursor); +} + +static void +pointer_set_cursor (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + struct wl_resource *surface_resource, + int32_t x, int32_t y) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface; + + surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL); + + if (seat->pointer.focus_surface == NULL) + return; + if (wl_resource_get_client (seat->pointer.focus_surface->resource) != client) + return; + if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2) + return; + + seat->hotspot_x = x; + seat->hotspot_y = y; + set_cursor_surface (seat, surface); + meta_wayland_seat_update_cursor_surface (seat); +} + +static void +pointer_release (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wl_pointer_interface pointer_interface = { + pointer_set_cursor, + pointer_release, +}; + +static void +seat_get_pointer (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + struct wl_resource *cr; + + cr = wl_resource_create (client, &wl_pointer_interface, + MIN (META_WL_POINTER_VERSION, wl_resource_get_version (resource)), id); + wl_resource_set_implementation (cr, &pointer_interface, seat, unbind_resource); + wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr)); + + if (seat->pointer.focus_surface && + wl_resource_get_client (seat->pointer.focus_surface->resource) == client) + meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus_surface); +} + +static void +keyboard_release (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct wl_keyboard_interface keyboard_interface = { + keyboard_release, +}; + +static void +seat_get_keyboard (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (resource); + struct wl_resource *cr; + + cr = wl_resource_create (client, &wl_keyboard_interface, + MIN (META_WL_KEYBOARD_VERSION, wl_resource_get_version (resource)), id); + wl_resource_set_implementation (cr, NULL, seat, unbind_resource); + wl_list_insert (&seat->keyboard.resource_list, wl_resource_get_link (cr)); + + wl_keyboard_send_keymap (cr, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + seat->keyboard.xkb_info.keymap_fd, + seat->keyboard.xkb_info.keymap_size); + + if (seat->keyboard.focus_surface && + wl_resource_get_client (seat->keyboard.focus_surface->resource) == client) + { + meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus_surface); + meta_wayland_data_device_set_keyboard_focus (seat); + } +} + +static void +seat_get_touch (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + /* Touch not supported */ +} + +static const struct wl_seat_interface +seat_interface = + { + seat_get_pointer, + seat_get_keyboard, + seat_get_touch + }; + +static void +bind_seat (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandSeat *seat = data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_seat_interface, + MIN (META_WL_SEAT_VERSION, version), id); + wl_resource_set_implementation (resource, &seat_interface, seat, unbind_resource); + wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource)); + + wl_seat_send_capabilities (resource, + WL_SEAT_CAPABILITY_POINTER | + WL_SEAT_CAPABILITY_KEYBOARD); + + if (version >= META_WL_SEAT_HAS_NAME) + wl_seat_send_name (resource, "seat0"); +} + +static void +pointer_handle_cursor_surface_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandSeat *seat = wl_container_of (listener, seat, cursor_surface_destroy_listener); + + set_cursor_surface (seat, NULL); + meta_wayland_seat_update_cursor_surface (seat); +} + +MetaWaylandSeat * +meta_wayland_seat_new (struct wl_display *display) +{ + MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1); + + seat->selection_data_source = NULL; + wl_list_init (&seat->base_resource_list); + wl_list_init (&seat->data_device_resource_list); + + meta_wayland_pointer_init (&seat->pointer); + meta_wayland_keyboard_init (&seat->keyboard, display); + + seat->display = display; + + seat->current_stage = 0; + + seat->cursor_surface = NULL; + seat->cursor_surface_destroy_listener.notify = pointer_handle_cursor_surface_destroy; + seat->hotspot_x = 16; + seat->hotspot_y = 16; + + wl_global_create (display, &wl_seat_interface, META_WL_SEAT_VERSION, seat, bind_seat); + + return seat; +} + +static void +notify_motion (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + MetaWaylandPointer *pointer = &seat->pointer; + + meta_wayland_seat_repick (seat, event); + + pointer->grab->interface->motion (pointer->grab, event); +} + +static void +handle_motion_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + notify_motion (seat, event); +} + +static void +handle_button_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + MetaWaylandPointer *pointer = &seat->pointer; + gboolean implicit_grab; + + notify_motion (seat, event); + + implicit_grab = (event->type == CLUTTER_BUTTON_PRESS) && (pointer->button_count == 1); + if (implicit_grab) + { + pointer->grab_button = clutter_event_get_button (event); + pointer->grab_time = clutter_event_get_time (event); + pointer->grab_x = pointer->x; + pointer->grab_y = pointer->y; + } + + pointer->grab->interface->button (pointer->grab, event); + + if (implicit_grab) + pointer->grab_serial = wl_display_get_serial (seat->display); +} + +static void +handle_scroll_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + wl_fixed_t x_value = 0, y_value = 0; + + notify_motion (seat, event); + + if (!seat->pointer.focus_resource) + return; + + if (clutter_event_is_pointer_emulated (event)) + return; + + switch (clutter_event_get_scroll_direction (event)) + { + case CLUTTER_SCROLL_UP: + y_value = -DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_DOWN: + y_value = DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_LEFT: + x_value = -DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_RIGHT: + x_value = DEFAULT_AXIS_STEP_DISTANCE; + break; + + case CLUTTER_SCROLL_SMOOTH: + { + double dx, dy; + clutter_event_get_scroll_delta (event, &dx, &dy); + x_value = wl_fixed_from_double (dx); + y_value = wl_fixed_from_double (dy); + } + break; + + default: + return; + } + + if (x_value) + wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event), + WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value); + if (y_value) + wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event), + WL_POINTER_AXIS_VERTICAL_SCROLL, y_value); +} + +static int +count_buttons (const ClutterEvent *event) +{ + static gint maskmap[5] = + { + CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON2_MASK, CLUTTER_BUTTON3_MASK, + CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK + }; + ClutterModifierType mod_mask; + int i, count; + + mod_mask = clutter_event_get_state (event); + count = 0; + for (i = 0; i < 5; i++) + { + if (mod_mask & maskmap[i]) + count++; + } + + return count; +} + +static void +meta_wayland_seat_update_pointer (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + float x, y; + + clutter_event_get_coords (event, &x, &y); + seat->pointer.x = wl_fixed_from_double (x); + seat->pointer.y = wl_fixed_from_double (y); + + seat->pointer.button_count = count_buttons (event); + + if (seat->cursor_tracker) + { + meta_cursor_tracker_update_position (seat->cursor_tracker, + wl_fixed_to_int (seat->pointer.x), + wl_fixed_to_int (seat->pointer.y)); + + if (seat->pointer.current == NULL) + meta_cursor_tracker_unset_window_cursor (seat->cursor_tracker); + } +} + +void +meta_wayland_seat_update (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + switch (event->type) + { + case CLUTTER_MOTION: + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + case CLUTTER_SCROLL: + meta_wayland_seat_update_pointer (seat, event); + break; + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + meta_wayland_keyboard_update (&seat->keyboard, (const ClutterKeyEvent *) event); + break; + default: + break; + } +} + +gboolean +meta_wayland_seat_handle_event (MetaWaylandSeat *seat, + const ClutterEvent *event) +{ + switch (event->type) + { + case CLUTTER_MOTION: + handle_motion_event (seat, event); + break; + + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + handle_button_event (seat, event); + break; + + case CLUTTER_KEY_PRESS: + case CLUTTER_KEY_RELEASE: + return meta_wayland_keyboard_handle_event (&seat->keyboard, + (const ClutterKeyEvent *) event); + + case CLUTTER_SCROLL: + handle_scroll_event (seat, event); + break; + + default: + break; + } + + return FALSE; +} + +/* The actor argument can be NULL in which case a Clutter pick will be + performed to determine the right actor. An actor should only be + passed if the repick is being performed due to an event in which + case Clutter will have already performed a pick so we can avoid + redundantly doing another one */ +void +meta_wayland_seat_repick (MetaWaylandSeat *seat, + const ClutterEvent *for_event) +{ + ClutterActor *actor = NULL; + MetaWaylandPointer *pointer = &seat->pointer; + MetaWaylandSurface *surface = NULL; + MetaDisplay *display = meta_get_display (); + + if (meta_grab_op_is_wayland (display->grab_op)) + { + meta_wayland_pointer_update_current_focus (pointer, NULL); + return; + } + + if (for_event) + { + actor = clutter_event_get_source (for_event); + } + else if (seat->current_stage) + { + ClutterStage *stage = CLUTTER_STAGE (seat->current_stage); + actor = clutter_stage_get_actor_at_pos (stage, + CLUTTER_PICK_REACTIVE, + wl_fixed_to_double (pointer->x), + wl_fixed_to_double (pointer->y)); + } + + if (actor) + seat->current_stage = clutter_actor_get_stage (actor); + else + seat->current_stage = NULL; + + if (META_IS_SURFACE_ACTOR_WAYLAND (actor)) + surface = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor)); + + meta_wayland_pointer_update_current_focus (pointer, surface); +} + +void +meta_wayland_seat_free (MetaWaylandSeat *seat) +{ + set_cursor_surface (seat, NULL); + + meta_wayland_pointer_release (&seat->pointer); + meta_wayland_keyboard_release (&seat->keyboard); + + g_slice_free (MetaWaylandSeat, seat); +} diff --git a/src/wayland/meta-wayland-seat.h b/src/wayland/meta-wayland-seat.h new file mode 100644 index 000000000..a038e2e32 --- /dev/null +++ b/src/wayland/meta-wayland-seat.h @@ -0,0 +1,91 @@ +/* + * Wayland Support + * + * Copyright (C) 2012 Intel Corporation + * + * 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. + */ + +#ifndef __META_WAYLAND_SEAT_H__ +#define __META_WAYLAND_SEAT_H__ + +#include +#include +#include +#include + +#include +#include "meta-wayland-types.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" + +struct _MetaWaylandDataOffer +{ + struct wl_resource *resource; + MetaWaylandDataSource *source; + struct wl_listener source_destroy_listener; +}; + +struct _MetaWaylandDataSource +{ + struct wl_resource *resource; + struct wl_array mime_types; +}; + +struct _MetaWaylandSeat +{ + struct wl_list base_resource_list; + + uint32_t selection_serial; + MetaWaylandDataSource *selection_data_source; + struct wl_listener selection_data_source_listener; + + struct wl_list data_device_resource_list; + MetaWaylandPointer pointer; + MetaWaylandKeyboard keyboard; + + struct wl_display *display; + + MetaCursorTracker *cursor_tracker; + MetaWaylandSurface *cursor_surface; + int hotspot_x, hotspot_y; + struct wl_listener cursor_surface_destroy_listener; + + ClutterActor *current_stage; +}; + +MetaWaylandSeat * +meta_wayland_seat_new (struct wl_display *display); + +void +meta_wayland_seat_update (MetaWaylandSeat *seat, + const ClutterEvent *event); + +gboolean +meta_wayland_seat_handle_event (MetaWaylandSeat *seat, + const ClutterEvent *event); + +void +meta_wayland_seat_repick (MetaWaylandSeat *seat, + const ClutterEvent *for_event); + +void +meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat); + +void +meta_wayland_seat_free (MetaWaylandSeat *seat); + +#endif /* __META_WAYLAND_SEAT_H__ */ diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c new file mode 100644 index 000000000..b795dd570 --- /dev/null +++ b/src/wayland/meta-wayland-stage.c @@ -0,0 +1,68 @@ +/* + * Wayland Support + * + * Copyright (C) 2012 Intel Corporation + * + * 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 + +#include +#include +#include + +#include "meta-wayland-stage.h" +#include "meta-wayland-private.h" +#include "meta/meta-window-actor.h" +#include "meta/meta-shaped-texture.h" +#include "meta-cursor-tracker-private.h" + +G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE); + +static void +meta_wayland_stage_paint (ClutterActor *actor) +{ + MetaWaylandCompositor *compositor; + + CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->paint (actor); + + compositor = meta_wayland_compositor_get_default (); + if (compositor->seat->cursor_tracker) + meta_cursor_tracker_paint (compositor->seat->cursor_tracker); +} + +static void +meta_wayland_stage_class_init (MetaWaylandStageClass *klass) +{ + ClutterActorClass *actor_class = (ClutterActorClass *) klass; + + actor_class->paint = meta_wayland_stage_paint; +} + +static void +meta_wayland_stage_init (MetaWaylandStage *self) +{ + clutter_stage_set_user_resizable (CLUTTER_STAGE (self), FALSE); +} + +ClutterActor * +meta_wayland_stage_new (void) +{ + return g_object_new (META_TYPE_WAYLAND_STAGE, + "cursor-visible", FALSE, + NULL); +} diff --git a/src/wayland/meta-wayland-stage.h b/src/wayland/meta-wayland-stage.h new file mode 100644 index 000000000..4dcfb6418 --- /dev/null +++ b/src/wayland/meta-wayland-stage.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 Intel Corporation + * + * 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. + */ + +#ifndef META_WAYLAND_STAGE_H +#define META_WAYLAND_STAGE_H + +#include +#include + +#include "window-private.h" + +G_BEGIN_DECLS + +#define META_TYPE_WAYLAND_STAGE (meta_wayland_stage_get_type ()) +#define META_WAYLAND_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WAYLAND_STAGE, MetaWaylandStage)) +#define META_WAYLAND_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WAYLAND_STAGE, MetaWaylandStageClass)) +#define META_IS_WAYLAND_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WAYLAND_STAGE)) +#define META_IS_WAYLAND_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WAYLAND_STAGE)) +#define META_WAYLAND_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WAYLAND_STAGE, MetaWaylandStageClass)) + +typedef struct _MetaWaylandStage MetaWaylandStage; +typedef struct _MetaWaylandStageClass MetaWaylandStageClass; + +struct _MetaWaylandStageClass +{ + ClutterStageClass parent_class; +}; + +struct _MetaWaylandStage +{ + ClutterStage parent; +}; + +GType meta_wayland_stage_get_type (void) G_GNUC_CONST; + +ClutterActor *meta_wayland_stage_new (void); + +G_END_DECLS + +#endif /* META_WAYLAND_STAGE_H */ diff --git a/src/wayland/meta-wayland-surface-private.h b/src/wayland/meta-wayland-surface-private.h new file mode 100644 index 000000000..9b882dfb1 --- /dev/null +++ b/src/wayland/meta-wayland-surface-private.h @@ -0,0 +1,32 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef META_WAYLAND_SURFACE_PRIVATE_H +#define META_WAYLAND_SURFACE_PRIVATE_H + +#include "meta-wayland-types.h" + +void meta_wayland_surface_commit (MetaWaylandSurface *surface); + +#endif /* META_WAYLAND_SURFACE_PRIVATE_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c new file mode 100644 index 000000000..a9aae3540 --- /dev/null +++ b/src/wayland/meta-wayland-surface.c @@ -0,0 +1,1836 @@ +/* + * Wayland Support + * + * Copyright (C) 2012,2013 Intel Corporation + * 2013 Red Hat, Inc. + * + * 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "gtk-shell-server-protocol.h" +#include "xdg-shell-server-protocol.h" + +#include "meta-wayland-private.h" +#include "meta-xwayland-private.h" +#include "meta-wayland-stage.h" +#include "meta-wayland-seat.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-data-device.h" +#include "meta-wayland-surface-private.h" + +#include "meta-cursor-tracker-private.h" +#include "display-private.h" +#include "window-private.h" +#include +#include +#include "frame.h" + +#include "meta-surface-actor.h" +#include "meta-surface-actor-wayland.h" + +typedef enum +{ + META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE, + META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW +} MetaWaylandSubsurfacePlacement; + +typedef struct +{ + MetaWaylandSubsurfacePlacement placement; + MetaWaylandSurface *sibling; + struct wl_listener sibling_destroy_listener; +} MetaWaylandSubsurfacePlacementOp; + +static void +surface_set_buffer (MetaWaylandSurface *surface, + MetaWaylandBuffer *buffer) +{ + if (surface->buffer == buffer) + return; + + if (surface->buffer) + { + wl_list_remove (&surface->buffer_destroy_listener.link); + meta_wayland_buffer_unref (surface->buffer); + } + + surface->buffer = buffer; + + if (surface->buffer) + { + meta_wayland_buffer_ref (surface->buffer); + wl_signal_add (&surface->buffer->destroy_signal, &surface->buffer_destroy_listener); + } +} + +static void +surface_handle_buffer_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandSurface *surface = wl_container_of (listener, surface, buffer_destroy_listener); + + surface_set_buffer (surface, NULL); +} + +static void +surface_process_damage (MetaWaylandSurface *surface, + cairo_region_t *region) +{ + int i, n_rectangles = cairo_region_num_rectangles (region); + + for (i = 0; i < n_rectangles; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + meta_surface_actor_process_damage (surface->surface_actor, + rect.x, rect.y, rect.width, rect.height); + } +} + +static void +empty_region (cairo_region_t *region) +{ + cairo_rectangle_int_t rectangle = { 0, 0, 0, 0 }; + cairo_region_intersect_rectangle (region, &rectangle); +} + +static void +ensure_buffer_texture (MetaWaylandBuffer *buffer) +{ + CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + CoglError *catch_error = NULL; + CoglTexture *texture; + + texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx, + buffer->resource, + &catch_error)); + if (!texture) + { + cogl_error_free (catch_error); + meta_warning ("Could not import pending buffer, ignoring commit\n"); + return; + } + + buffer->texture = texture; +} + +static gboolean +commit_attached_surface (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + /* wl_surface.attach */ + if (pending->newly_attached && surface->buffer != pending->buffer) + { + surface_set_buffer (surface, pending->buffer); + return TRUE; + } + else + return FALSE; +} + +static void +cursor_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + if (commit_attached_surface (surface, pending)) + meta_wayland_seat_update_cursor_surface (surface->compositor->seat); +} + +static gboolean +actor_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + MetaSurfaceActor *surface_actor = surface->surface_actor; + MetaWaylandBuffer *buffer = pending->buffer; + gboolean buffer_changed; + + buffer_changed = commit_attached_surface (surface, pending); + + if (buffer_changed && buffer) + { + ensure_buffer_texture (buffer); + meta_surface_actor_wayland_set_buffer (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), buffer); + } + + surface_process_damage (surface, pending->damage); + + if (pending->opaque_region) + meta_surface_actor_set_opaque_region (surface_actor, pending->opaque_region); + if (pending->input_region) + meta_surface_actor_set_input_region (surface_actor, pending->input_region); + + return buffer_changed; +} + +static void +toplevel_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + if (actor_surface_commit (surface, pending)) + { + MetaWindow *window = surface->window; + MetaWaylandBuffer *buffer = pending->buffer; + + meta_window_set_surface_mapped (window, buffer != NULL); + /* We resize X based surfaces according to X events */ + if (buffer != NULL && window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) + { + int new_width, new_height; + + new_width = cogl_texture_get_width (buffer->texture); + new_height = cogl_texture_get_height (buffer->texture); + + if (new_width != window->rect.width || + new_height != window->rect.height || + pending->dx != 0 || + pending->dy != 0) + meta_window_move_resize_wayland (window, new_width, new_height, pending->dx, pending->dy); + } + } + + if (pending->frame_extents_changed) + meta_window_set_custom_frame_extents (surface->window, &pending->frame_extents); +} + +static void +surface_handle_pending_buffer_destroy (struct wl_listener *listener, void *data) +{ + MetaWaylandDoubleBufferedState *state = + wl_container_of (listener, state, buffer_destroy_listener); + + state->buffer = NULL; +} + +static void +double_buffered_state_init (MetaWaylandDoubleBufferedState *state) +{ + state->newly_attached = FALSE; + state->buffer = NULL; + state->dx = 0; + state->dy = 0; + + state->damage = cairo_region_create (); + state->buffer_destroy_listener.notify = + surface_handle_pending_buffer_destroy; + wl_list_init (&state->frame_callback_list); + + state->frame_extents_changed = FALSE; +} + +static void +double_buffered_state_destroy (MetaWaylandDoubleBufferedState *state) +{ + MetaWaylandFrameCallback *cb, *next; + + g_clear_pointer (&state->damage, cairo_region_destroy); + g_clear_pointer (&state->input_region, cairo_region_destroy); + g_clear_pointer (&state->opaque_region, cairo_region_destroy); + + if (state->buffer) + wl_list_remove (&state->buffer_destroy_listener.link); + wl_list_for_each_safe (cb, next, &state->frame_callback_list, link) + wl_resource_destroy (cb->resource); +} + +static void +double_buffered_state_reset (MetaWaylandDoubleBufferedState *state) +{ + double_buffered_state_destroy (state); + double_buffered_state_init (state); +} + +static void +move_double_buffered_state (MetaWaylandDoubleBufferedState *from, + MetaWaylandDoubleBufferedState *to) +{ + if (from->buffer) + wl_list_remove (&from->buffer_destroy_listener.link); + + to->newly_attached = from->newly_attached; + from->newly_attached = FALSE; + + to->buffer = from->buffer; + from->buffer = NULL; + if (to->buffer) + wl_signal_add (&to->buffer->destroy_signal, &to->buffer_destroy_listener); + + to->dx = from->dx; + to->dy = from->dy; + from->dx = from->dy = 0; + + empty_region (to->damage); + cairo_region_union (to->damage, from->damage); + empty_region (from->damage); + + g_clear_pointer (&to->input_region, cairo_region_destroy); + g_clear_pointer (&to->opaque_region, cairo_region_destroy); + to->input_region = from->input_region; + to->opaque_region = from->opaque_region; + from->input_region = from->opaque_region = NULL; + + wl_list_init (&to->frame_callback_list); + wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list); + wl_list_init (&from->frame_callback_list); +} + +static void +subsurface_surface_commit (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + /* + * If the sub-surface is in synchronous mode, post-pone the commit of its + * state until the sub-surface parent commits. + * + * This is done by moving the various states (damage, input region, buffer + * etc.) from the buffered state pending commit to the sub-surface's pending + * buffered state. + * + * The sub-surface's pending buffered state will be committed to the + * associated surface when its parent surface is committed, or if the user + * issues a wl_subsurface.set_desync request. + */ + if (surface->sub.synchronous) + { + move_double_buffered_state (pending, &surface->sub.pending_surface_state); + } + else + { + if (actor_surface_commit (surface, pending)) + { + MetaSurfaceActor *surface_actor = surface->surface_actor; + MetaWaylandBuffer *buffer = pending->buffer; + float x, y; + + if (buffer != NULL) + clutter_actor_show (CLUTTER_ACTOR (surface_actor)); + else + clutter_actor_hide (CLUTTER_ACTOR (surface_actor)); + + clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y); + x += pending->dx; + y += pending->dy; + clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y); + } + } +} + +static void +subsurface_parent_surface_committed (MetaWaylandSurface *surface); + +static void +parent_surface_committed (gpointer data, gpointer user_data) +{ + subsurface_parent_surface_committed (data); +} + +static void +commit_double_buffered_state (MetaWaylandSurface *surface, + MetaWaylandDoubleBufferedState *pending) +{ + MetaWaylandCompositor *compositor = surface->compositor; + + if (surface == compositor->seat->cursor_surface) + cursor_surface_commit (surface, pending); + else if (surface->window) + toplevel_surface_commit (surface, pending); + else if (surface->subsurface.resource) + subsurface_surface_commit (surface, pending); + else + { + /* Unknown surface type. In this case, it's most likely a XWayland + * surface that we haven't gotten the ClientMessage for yet. Make + * sure *not* to reset the double-buffered state or do anything too + * fancy. */ + return; + } + + g_list_foreach (surface->subsurfaces, + parent_surface_committed, + NULL); + + if (pending->buffer) + { + wl_list_remove (&pending->buffer_destroy_listener.link); + pending->buffer = NULL; + } + + /* wl_surface.frame */ + wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list); + wl_list_init (&pending->frame_callback_list); + + double_buffered_state_reset (pending); +} + +void +meta_wayland_surface_commit (MetaWaylandSurface *surface) +{ + commit_double_buffered_state (surface, &surface->pending); +} + +static void +wl_surface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +wl_surface_attach (struct wl_client *client, + struct wl_resource *surface_resource, + struct wl_resource *buffer_resource, + gint32 dx, gint32 dy) +{ + MetaWaylandSurface *surface = + wl_resource_get_user_data (surface_resource); + MetaWaylandBuffer *buffer; + + /* X11 unmanaged window */ + if (!surface) + return; + + if (buffer_resource) + buffer = meta_wayland_buffer_from_resource (buffer_resource); + else + buffer = NULL; + + /* Attach without commit in between does not send wl_buffer.release */ + if (surface->pending.buffer) + wl_list_remove (&surface->pending.buffer_destroy_listener.link); + + surface->pending.dx = dx; + surface->pending.dy = dy; + surface->pending.buffer = buffer; + surface->pending.newly_attached = TRUE; + + if (buffer) + wl_signal_add (&buffer->destroy_signal, + &surface->pending.buffer_destroy_listener); +} + +static void +wl_surface_damage (struct wl_client *client, + struct wl_resource *surface_resource, + gint32 x, + gint32 y, + gint32 width, + gint32 height) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + cairo_rectangle_int_t rectangle = { x, y, width, height }; + + /* X11 unmanaged window */ + if (!surface) + return; + + cairo_region_union_rectangle (surface->pending.damage, &rectangle); +} + +static void +destroy_frame_callback (struct wl_resource *callback_resource) +{ + MetaWaylandFrameCallback *callback = + wl_resource_get_user_data (callback_resource); + + wl_list_remove (&callback->link); + g_slice_free (MetaWaylandFrameCallback, callback); +} + +static void +wl_surface_frame (struct wl_client *client, + struct wl_resource *surface_resource, + guint32 callback_id) +{ + MetaWaylandFrameCallback *callback; + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + callback = g_slice_new0 (MetaWaylandFrameCallback); + callback->compositor = surface->compositor; + callback->resource = wl_resource_create (client, &wl_callback_interface, META_WL_CALLBACK_VERSION, callback_id); + wl_resource_set_implementation (callback->resource, NULL, callback, destroy_frame_callback); + + wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link); +} + +static void +wl_surface_set_opaque_region (struct wl_client *client, + struct wl_resource *surface_resource, + struct wl_resource *region_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy); + if (region_resource) + { + MetaWaylandRegion *region = wl_resource_get_user_data (region_resource); + surface->pending.opaque_region = cairo_region_copy (region->region); + } +} + +static void +wl_surface_set_input_region (struct wl_client *client, + struct wl_resource *surface_resource, + struct wl_resource *region_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + g_clear_pointer (&surface->pending.input_region, cairo_region_destroy); + if (region_resource) + { + MetaWaylandRegion *region = wl_resource_get_user_data (region_resource); + surface->pending.input_region = cairo_region_copy (region->region); + } +} + +static void +wl_surface_commit (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + meta_wayland_surface_commit (surface); +} + +static void +wl_surface_set_buffer_transform (struct wl_client *client, + struct wl_resource *resource, + int32_t transform) +{ + g_warning ("TODO: support set_buffer_transform request"); +} + +static void +wl_surface_set_buffer_scale (struct wl_client *client, + struct wl_resource *resource, + int scale) +{ + if (scale != 1) + g_warning ("TODO: support set_buffer_scale request"); +} + +const struct wl_surface_interface meta_wayland_wl_surface_interface = { + wl_surface_destroy, + wl_surface_attach, + wl_surface_damage, + wl_surface_frame, + wl_surface_set_opaque_region, + wl_surface_set_input_region, + wl_surface_commit, + wl_surface_set_buffer_transform, + wl_surface_set_buffer_scale +}; + +void +meta_wayland_surface_set_window (MetaWaylandSurface *surface, + MetaWindow *window) +{ + gboolean has_window = (window != NULL); + + clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor), has_window); + surface->window = window; +} + +static void +destroy_window (MetaWaylandSurface *surface) +{ + if (surface->window) + { + MetaDisplay *display = meta_get_display (); + guint32 timestamp = meta_display_get_current_time_roundtrip (display); + + meta_window_unmanage (surface->window, timestamp); + } + + g_assert (surface->window == NULL); +} + +static void +wl_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandCompositor *compositor = surface->compositor; + + /* If we still have a window at the time of destruction, that means that + * the client is disconnecting, as the resources are destroyed in a random + * order. Simply destroy the window in this case. */ + if (surface->window) + destroy_window (surface); + + compositor->surfaces = g_list_remove (compositor->surfaces, surface); + + surface_set_buffer (surface, NULL); + double_buffered_state_destroy (&surface->pending); + + g_object_unref (surface->surface_actor); + + if (surface->resource) + wl_resource_set_user_data (surface->resource, NULL); + g_slice_free (MetaWaylandSurface, surface); + + meta_wayland_compositor_repick (compositor); +} + +MetaWaylandSurface * +meta_wayland_surface_create (MetaWaylandCompositor *compositor, + struct wl_client *client, + guint32 id, + guint32 version) +{ + MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface); + + surface->compositor = compositor; + + surface->resource = wl_resource_create (client, &wl_surface_interface, version, id); + wl_resource_set_implementation (surface->resource, &meta_wayland_wl_surface_interface, surface, wl_surface_destructor); + + surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy; + surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface)); + + double_buffered_state_init (&surface->pending); + return surface; +} + +static void +destroy_surface_extension (MetaWaylandSurfaceExtension *extension) +{ + extension->resource = NULL; +} + +static int +get_resource_version (struct wl_resource *master_resource, + int max_version) +{ + return MIN (max_version, wl_resource_get_version (master_resource)); +} + +static gboolean +create_surface_extension (MetaWaylandSurfaceExtension *extension, + int max_version, + const struct wl_interface *interface, + const void *implementation, + wl_resource_destroy_func_t destructor, + MetaWaylandSurface *surface, + struct wl_resource *master_resource, + guint32 id) +{ + struct wl_client *client; + + if (extension->resource != NULL) + return FALSE; + + client = wl_resource_get_client (surface->resource); + extension->resource = wl_resource_create (client, interface, get_resource_version (master_resource, max_version), id); + wl_resource_set_implementation (extension->resource, implementation, surface, destructor); + + return TRUE; +} + +static void +xdg_shell_use_unstable_version (struct wl_client *client, + struct wl_resource *resource, + int32_t version) +{ + if (version != XDG_SHELL_VERSION_CURRENT) + g_warning ("Bad xdg_shell version: %d", version); +} + +static void +xdg_shell_pong (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaDisplay *display = meta_get_display (); + + meta_display_pong_for_serial (display, serial); +} + +static void +xdg_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_window (surface); + destroy_surface_extension (&surface->xdg_surface); +} + +static void +xdg_surface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +xdg_surface_set_transient_for (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWindow *transient_for = NULL; + + if (parent_resource) + { + MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent_resource); + transient_for = parent_surface->window; + } + + meta_window_set_transient_for (surface->window, transient_for); +} + +static void +xdg_surface_set_margin (struct wl_client *client, + struct wl_resource *resource, + int32_t left_margin, + int32_t right_margin, + int32_t top_margin, + int32_t bottom_margin) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->pending.frame_extents_changed = TRUE; + surface->pending.frame_extents.left = left_margin; + surface->pending.frame_extents.right = right_margin; + surface->pending.frame_extents.top = top_margin; + surface->pending.frame_extents.bottom = bottom_margin; +} + +static void +xdg_surface_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_title (surface->window, title); +} + +static void +xdg_surface_set_app_id (struct wl_client *client, + struct wl_resource *resource, + const char *app_id) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_wm_class (surface->window, app_id, app_id); +} + +static gboolean +begin_grab_op_on_surface (MetaWaylandSurface *surface, + MetaWaylandSeat *seat, + MetaGrabOp grab_op) +{ + MetaWindow *window = surface->window; + + if (grab_op == META_GRAB_OP_NONE) + return FALSE; + + return meta_display_begin_grab_op (window->display, + window->screen, + window, + grab_op, + TRUE, /* pointer_already_grabbed */ + FALSE, /* frame_action */ + 1, /* button. XXX? */ + 0, /* modmask */ + meta_display_get_current_time_roundtrip (window->display), + wl_fixed_to_int (seat->pointer.grab_x), + wl_fixed_to_int (seat->pointer.grab_y)); +} + +static void +xdg_surface_move (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + guint32 serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING); +} + +static MetaGrabOp +grab_op_for_xdg_surface_resize_edge (int edge) +{ + switch (edge) + { + case XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: + return META_GRAB_OP_RESIZING_NW; + case XDG_SURFACE_RESIZE_EDGE_TOP: + return META_GRAB_OP_RESIZING_N; + case XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: + return META_GRAB_OP_RESIZING_NE; + case XDG_SURFACE_RESIZE_EDGE_RIGHT: + return META_GRAB_OP_RESIZING_E; + case XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: + return META_GRAB_OP_RESIZING_SE; + case XDG_SURFACE_RESIZE_EDGE_BOTTOM: + return META_GRAB_OP_RESIZING_S; + case XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: + return META_GRAB_OP_RESIZING_SW; + case XDG_SURFACE_RESIZE_EDGE_LEFT: + return META_GRAB_OP_RESIZING_W; + default: + g_warning ("invalid edge: %d", edge); + return META_GRAB_OP_NONE; + } +} + +static void +xdg_surface_resize (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + guint32 serial, + guint32 edges) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, grab_op_for_xdg_surface_resize_edge (edges)); +} + +static void +xdg_surface_set_output (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output) +{ + g_warning ("TODO: support xdg_surface.set_output"); +} + +static void +xdg_surface_request_change_state (struct wl_client *client, + struct wl_resource *resource, + uint32_t state_type, + uint32_t value, + uint32_t serial) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->state_changed_serial = serial; + + switch (state_type) + { + case XDG_SURFACE_STATE_MAXIMIZED: + if (value) + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); + else + meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); + break; + case XDG_SURFACE_STATE_FULLSCREEN: + if (value) + meta_window_make_fullscreen (surface->window); + else + meta_window_unmake_fullscreen (surface->window); + } +} + +static void +xdg_surface_ack_change_state (struct wl_client *client, + struct wl_resource *resource, + uint32_t state_type, + uint32_t value, + uint32_t serial) +{ + /* Do nothing for now. In the future, we'd imagine that + * we'd ignore attaches when we have a state pending that + * we haven't had the client ACK'd, to prevent a race + * condition when we have an in-flight attach when the + * client gets the new state. */ +} + +static void +xdg_surface_set_minimized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_minimize (surface->window); +} + +static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = { + xdg_surface_destroy, + xdg_surface_set_transient_for, + xdg_surface_set_margin, + xdg_surface_set_title, + xdg_surface_set_app_id, + xdg_surface_move, + xdg_surface_resize, + xdg_surface_set_output, + xdg_surface_request_change_state, + xdg_surface_ack_change_state, + xdg_surface_set_minimized, +}; + +static void +xdg_shell_get_xdg_surface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWindow *window; + + if (!create_surface_extension (&surface->xdg_surface, + META_XDG_SURFACE_VERSION, + &xdg_surface_interface, + &meta_wayland_xdg_surface_interface, + xdg_surface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_shell::get_xdg_surface already requested"); + return; + } + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static void +xdg_popup_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_window (surface); + destroy_surface_extension (&surface->xdg_popup); +} + +static void +xdg_popup_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { + xdg_popup_destroy, +}; + +static void +xdg_shell_get_xdg_popup (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *parent_resource, + struct wl_resource *seat_resource, + uint32_t serial, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWindow *window; + + if (parent_surf == NULL || parent_surf->window == NULL) + return; + + if (!create_surface_extension (&surface->xdg_popup, + META_XDG_POPUP_VERSION, + &xdg_popup_interface, + &meta_wayland_xdg_popup_interface, + xdg_popup_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_shell::get_xdg_popup already requested"); + return; + } + + window = meta_window_wayland_new (meta_get_display (), surface); + window->rect.x = parent_surf->window->rect.x + x; + window->rect.y = parent_surf->window->rect.y + y; + window->showing_for_first_time = FALSE; + window->placed = TRUE; + meta_window_set_transient_for (window, parent_surf->window); + meta_window_set_type (window, META_WINDOW_DROPDOWN_MENU); + + meta_wayland_surface_set_window (surface, window); + + meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); +} + +static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = { + xdg_shell_use_unstable_version, + xdg_shell_get_xdg_surface, + xdg_shell_get_xdg_popup, + xdg_shell_pong, +}; + +typedef struct { + struct wl_resource *resource; + struct wl_listener client_destroy_listener; +} XdgShell; + +static void +xdg_shell_handle_client_destroy (struct wl_listener *listener, void *data) +{ + XdgShell *xdg_shell = wl_container_of (listener, xdg_shell, client_destroy_listener); + g_slice_free (XdgShell, xdg_shell); +} + +static struct wl_resource * +get_xdg_shell_for_client (struct wl_client *client) +{ + struct wl_listener *listener; + XdgShell *xdg_shell; + + listener = wl_client_get_destroy_listener (client, xdg_shell_handle_client_destroy); + + /* No xdg_shell has been bound for this client */ + if (listener == NULL) + return NULL; + + xdg_shell = wl_container_of (listener, xdg_shell, client_destroy_listener); + return xdg_shell->resource; +} + +static void +bind_xdg_shell (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + XdgShell *xdg_shell; + + if (version != 1) + { + g_warning ("using xdg-shell without stable version 1\n"); + return; + } + + xdg_shell = g_slice_new (XdgShell); + + resource = wl_resource_create (client, &xdg_shell_interface, 1, id); + wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, data, NULL); + xdg_shell->resource = wl_resource_create (client, &xdg_shell_interface, 1, id); + wl_resource_set_implementation (xdg_shell->resource, &meta_wayland_xdg_shell_interface, data, NULL); + + xdg_shell->client_destroy_listener.notify = xdg_shell_handle_client_destroy; + wl_client_add_destroy_listener (client, &xdg_shell->client_destroy_listener); +} + +static void +wl_shell_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_surface_extension (&surface->wl_shell_surface); +} + +static void +wl_shell_surface_pong (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaDisplay *display = meta_get_display (); + + meta_display_pong_for_serial (display, serial); +} + +static void +wl_shell_surface_move (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING); +} + +static MetaGrabOp +grab_op_for_wl_shell_surface_resize_edge (int edge) +{ + switch (edge) + { + case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: + return META_GRAB_OP_RESIZING_NW; + case WL_SHELL_SURFACE_RESIZE_TOP: + return META_GRAB_OP_RESIZING_N; + case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: + return META_GRAB_OP_RESIZING_NE; + case WL_SHELL_SURFACE_RESIZE_RIGHT: + return META_GRAB_OP_RESIZING_E; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: + return META_GRAB_OP_RESIZING_SE; + case WL_SHELL_SURFACE_RESIZE_BOTTOM: + return META_GRAB_OP_RESIZING_S; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: + return META_GRAB_OP_RESIZING_SW; + case WL_SHELL_SURFACE_RESIZE_LEFT: + return META_GRAB_OP_RESIZING_W; + default: + g_warning ("invalid edge: %d", edge); + return META_GRAB_OP_NONE; + } +} + +static void +wl_shell_surface_resize (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + uint32_t edges) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, grab_op_for_wl_shell_surface_resize_edge (edges)); +} + +typedef enum { + SURFACE_STATE_TOPLEVEL, + SURFACE_STATE_FULLSCREEN, + SURFACE_STATE_MAXIMIZED, +} SurfaceState; + +static void +wl_shell_surface_set_state (MetaWaylandSurface *surface, + SurfaceState state) +{ + if (state == SURFACE_STATE_FULLSCREEN) + meta_window_make_fullscreen (surface->window); + else + meta_window_unmake_fullscreen (surface->window); + + if (state == SURFACE_STATE_MAXIMIZED) + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); + else + meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); +} + +static void +wl_shell_surface_set_toplevel (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); +} + +static void +wl_shell_surface_set_transient (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_move (surface->window, FALSE, + parent_surf->window->rect.x + x, + parent_surf->window->rect.y + y); + surface->window->placed = TRUE; +} + +static void +wl_shell_surface_set_fullscreen (struct wl_client *client, + struct wl_resource *resource, + uint32_t method, + uint32_t framerate, + struct wl_resource *output) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_FULLSCREEN); +} + +static void +wl_shell_surface_set_popup (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + struct wl_resource *parent_resource, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_move (surface->window, FALSE, + parent_surf->window->rect.x + x, + parent_surf->window->rect.y + y); + surface->window->placed = TRUE; + + meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); +} + +static void +wl_shell_surface_set_maximized (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_MAXIMIZED); +} + +static void +wl_shell_surface_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_title (surface->window, title); +} + +static void +wl_shell_surface_set_class (struct wl_client *client, + struct wl_resource *resource, + const char *class_) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_wm_class (surface->window, class_, class_); +} + +static const struct wl_shell_surface_interface meta_wayland_wl_shell_surface_interface = { + wl_shell_surface_pong, + wl_shell_surface_move, + wl_shell_surface_resize, + wl_shell_surface_set_toplevel, + wl_shell_surface_set_transient, + wl_shell_surface_set_fullscreen, + wl_shell_surface_set_popup, + wl_shell_surface_set_maximized, + wl_shell_surface_set_title, + wl_shell_surface_set_class, +}; + +static void +wl_shell_get_shell_surface (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWindow *window; + + if (!create_surface_extension (&surface->wl_shell_surface, + META_WL_SHELL_SURFACE_VERSION, + &wl_shell_surface_interface, + &meta_wayland_wl_shell_surface_interface, + wl_shell_surface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_shell::get_shell_surface already requested"); + return; + } + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static const struct wl_shell_interface meta_wayland_wl_shell_interface = { + wl_shell_get_shell_surface, +}; + +static void +bind_wl_shell (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_shell_interface, + MIN (META_WL_SHELL_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_wl_shell_interface, data, NULL); +} + +static void +gtk_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + destroy_surface_extension (&surface->gtk_surface); +} + +static void +set_dbus_properties (struct wl_client *client, + struct wl_resource *resource, + const char *application_id, + const char *app_menu_path, + const char *menubar_path, + const char *window_object_path, + const char *application_object_path, + const char *unique_bus_name) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + /* Broken client, let it die instead of us */ + if (!surface->window) + { + meta_warning ("meta-wayland-surface: set_dbus_properties called with invalid window!\n"); + return; + } + + meta_window_set_gtk_dbus_properties (surface->window, + application_id, + unique_bus_name, + app_menu_path, + menubar_path, + application_object_path, + window_object_path); +} + +static const struct gtk_surface_interface meta_wayland_gtk_surface_interface = { + set_dbus_properties +}; + +static void +get_gtk_surface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + + if (!create_surface_extension (&surface->gtk_surface, + META_GTK_SURFACE_VERSION, + >k_surface_interface, + &meta_wayland_gtk_surface_interface, + gtk_surface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "gtk_shell::get_gtk_surface already requested"); + return; + } +} + +static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = { + get_gtk_surface +}; + +static void +bind_gtk_shell (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, >k_shell_interface, + MIN (META_GTK_SHELL_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL); + + /* FIXME: ask the plugin */ + gtk_shell_send_capabilities (resource, GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU); +} + +static void +subsurface_parent_surface_committed (MetaWaylandSurface *surface) +{ + MetaWaylandDoubleBufferedState *pending_surface_state = &surface->sub.pending_surface_state; + + if (surface->sub.pending_pos) + { + clutter_actor_set_position (CLUTTER_ACTOR (surface->surface_actor), + surface->sub.pending_x, + surface->sub.pending_y); + surface->sub.pending_pos = FALSE; + } + + if (surface->sub.pending_placement_ops) + { + GSList *it; + for (it = surface->sub.pending_placement_ops; it; it = it->next) + { + MetaWaylandSubsurfacePlacementOp *op = it->data; + ClutterActor *surface_actor; + ClutterActor *parent_actor; + ClutterActor *sibling_actor; + + if (!op->sibling) + { + g_slice_free (MetaWaylandSubsurfacePlacementOp, op); + continue; + } + + surface_actor = CLUTTER_ACTOR (surface->surface_actor); + parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->sub.parent)); + sibling_actor = CLUTTER_ACTOR (op->sibling->surface_actor); + + switch (op->placement) + { + case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE: + clutter_actor_set_child_above_sibling (parent_actor, surface_actor, sibling_actor); + break; + case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW: + clutter_actor_set_child_below_sibling (parent_actor, surface_actor, sibling_actor); + break; + } + + wl_list_remove (&op->sibling_destroy_listener.link); + g_slice_free (MetaWaylandSubsurfacePlacementOp, op); + } + + g_slist_free (surface->sub.pending_placement_ops); + surface->sub.pending_placement_ops = NULL; + } + + if (surface->sub.synchronous) + commit_double_buffered_state (surface, pending_surface_state); +} + +static void +unparent_actor (MetaWaylandSurface *surface) +{ + ClutterActor *parent_actor; + parent_actor = clutter_actor_get_parent (CLUTTER_ACTOR (surface->surface_actor)); + clutter_actor_remove_child (parent_actor, CLUTTER_ACTOR (surface->surface_actor)); +} + +static void +wl_subsurface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (surface->sub.parent) + { + wl_list_remove (&surface->sub.parent_destroy_listener.link); + surface->sub.parent->subsurfaces = + g_list_remove (surface->sub.parent->subsurfaces, surface); + unparent_actor (surface); + surface->sub.parent = NULL; + } + + double_buffered_state_destroy (&surface->sub.pending_surface_state); + destroy_surface_extension (&surface->subsurface); +} + +static void +wl_subsurface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +wl_subsurface_set_position (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->sub.pending_x = x; + surface->sub.pending_y = y; + surface->sub.pending_pos = TRUE; +} + +static gboolean +is_valid_sibling (MetaWaylandSurface *surface, MetaWaylandSurface *sibling) +{ + if (surface->sub.parent == sibling) + return TRUE; + if (surface->sub.parent == sibling->sub.parent) + return TRUE; + return FALSE; +} + +static void +subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener, void *data) +{ + MetaWaylandSubsurfacePlacementOp *op = + wl_container_of (listener, op, sibling_destroy_listener); + + op->sibling = NULL; +} + +static void +queue_subsurface_placement (MetaWaylandSurface *surface, + MetaWaylandSurface *sibling, + MetaWaylandSubsurfacePlacement placement) +{ + MetaWaylandSubsurfacePlacementOp *op = + g_slice_new (MetaWaylandSubsurfacePlacementOp); + + op->placement = placement; + op->sibling = sibling; + op->sibling_destroy_listener.notify = + subsurface_handle_pending_sibling_destroyed; + wl_resource_add_destroy_listener (sibling->resource, + &op->sibling_destroy_listener); + + surface->sub.pending_placement_ops = + g_slist_append (surface->sub.pending_placement_ops, op); +} + +static void +wl_subsurface_place_above (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *sibling_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource); + + if (!is_valid_sibling (surface, sibling)) + { + wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, + "wl_subsurface::place_above: wl_surface@%d is " + "not a valid parent or sibling", + wl_resource_get_id (sibling->resource)); + return; + } + + queue_subsurface_placement (surface, + sibling, + META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE); +} + +static void +wl_subsurface_place_below (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *sibling_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *sibling = wl_resource_get_user_data (sibling_resource); + + if (!is_valid_sibling (surface, sibling)) + { + wl_resource_post_error (resource, WL_SUBSURFACE_ERROR_BAD_SURFACE, + "wl_subsurface::place_below: wl_surface@%d is " + "not a valid parent or sibling", + wl_resource_get_id (sibling->resource)); + return; + } + + queue_subsurface_placement (surface, + sibling, + META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW); +} + +static void +wl_subsurface_set_sync (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->sub.synchronous = TRUE; +} + +static void +wl_subsurface_set_desync (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (surface->sub.synchronous) + subsurface_parent_surface_committed (surface); + + surface->sub.synchronous = FALSE; +} + +static const struct wl_subsurface_interface meta_wayland_subsurface_interface = { + wl_subsurface_destroy, + wl_subsurface_set_position, + wl_subsurface_place_above, + wl_subsurface_place_below, + wl_subsurface_set_sync, + wl_subsurface_set_desync, +}; + +static void +wl_subcompositor_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +surface_handle_parent_surface_destroyed (struct wl_listener *listener, + void *data) +{ + MetaWaylandSurface *surface = wl_container_of (listener, + surface, + sub.parent_destroy_listener); + + surface->sub.parent = NULL; + unparent_actor (surface); +} + +static void +wl_subcompositor_get_subsurface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource, + struct wl_resource *parent_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource); + + if (!create_surface_extension (&surface->subsurface, + META_GTK_SURFACE_VERSION, + &wl_subsurface_interface, + &meta_wayland_subsurface_interface, + wl_subsurface_destructor, + surface, resource, id)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_subcompositor::get_subsurface already requested"); + return; + } + + double_buffered_state_init (&surface->sub.pending_surface_state); + surface->sub.parent = parent; + surface->sub.parent_destroy_listener.notify = + surface_handle_parent_surface_destroyed; + wl_resource_add_destroy_listener (parent->resource, + &surface->sub.parent_destroy_listener); + parent->subsurfaces = g_list_append (parent->subsurfaces, surface); + + clutter_actor_add_child (CLUTTER_ACTOR (parent->surface_actor), + CLUTTER_ACTOR (surface->surface_actor)); +} + +static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = { + wl_subcompositor_destroy, + wl_subcompositor_get_subsurface, +}; + +static void +bind_subcompositor (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_subcompositor_interface, + MIN (META_WL_SUBCOMPOSITOR_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_subcompositor_interface, data, NULL); +} + +void +meta_wayland_init_shell (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &xdg_shell_interface, 1, + compositor, bind_xdg_shell) == NULL) + g_error ("Failed to register a global xdg-shell object"); + + if (wl_global_create (compositor->wayland_display, + &wl_shell_interface, 1, + compositor, bind_wl_shell) == NULL) + g_error ("Failed to register a global wl-shell object"); + + if (wl_global_create (compositor->wayland_display, + >k_shell_interface, + META_GTK_SHELL_VERSION, + compositor, bind_gtk_shell) == NULL) + g_error ("Failed to register a global gtk-shell object"); + + if (wl_global_create (compositor->wayland_display, + &wl_subcompositor_interface, + META_WL_SUBCOMPOSITOR_VERSION, + compositor, bind_subcompositor) == NULL) + g_error ("Failed to register a global wl-subcompositor object"); +} + +void +meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, + int new_width, + int new_height) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_configure (surface->xdg_surface.resource, + new_width, new_height); + else if (surface->wl_shell_surface.resource) + wl_shell_surface_send_configure (surface->wl_shell_surface.resource, + 0, new_width, new_height); +} + +static void +send_change_state (MetaWaylandSurface *surface, + uint32_t state_type, + uint32_t value) +{ + if (surface->xdg_surface.resource) + { + uint32_t serial; + + if (surface->state_changed_serial != 0) + { + serial = surface->state_changed_serial; + surface->state_changed_serial = 0; + } + else + { + struct wl_client *client = wl_resource_get_client (surface->xdg_surface.resource); + struct wl_display *display = wl_client_get_display (client); + serial = wl_display_next_serial (display); + } + + xdg_surface_send_change_state (surface->xdg_surface.resource, state_type, value, serial); + } +} + +void +meta_wayland_surface_send_maximized (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, TRUE); +} + +void +meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_MAXIMIZED, FALSE); +} + +void +meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, TRUE); +} + +void +meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface) +{ + send_change_state (surface, XDG_SURFACE_STATE_FULLSCREEN, FALSE); +} + +void +meta_wayland_surface_activated (MetaWaylandSurface *surface) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_activated (surface->xdg_surface.resource); +} + +void +meta_wayland_surface_deactivated (MetaWaylandSurface *surface) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_deactivated (surface->xdg_surface.resource); +} + +void +meta_wayland_surface_ping (MetaWaylandSurface *surface, + guint32 serial) +{ + if (surface->xdg_surface.resource) + { + struct wl_client *client = wl_resource_get_client (surface->resource); + struct wl_resource *xdg_shell = get_xdg_shell_for_client (client); + + if (xdg_shell == NULL) + { + g_warning ("Trying to ping a surface without an xdg_shell bound. How does this happen?"); + return; + } + + xdg_shell_send_ping (xdg_shell, serial); + } + else if (surface->wl_shell_surface.resource) + { + wl_shell_surface_send_ping (surface->wl_shell_surface.resource, serial); + } +} + +void +meta_wayland_surface_delete (MetaWaylandSurface *surface) +{ + if (surface->xdg_surface.resource) + xdg_surface_send_delete (surface->xdg_surface.resource); +} + +void +meta_wayland_surface_popup_done (MetaWaylandSurface *surface) +{ + struct wl_client *client = wl_resource_get_client (surface->resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + + if (surface->xdg_popup.resource) + xdg_popup_send_popup_done (surface->xdg_popup.resource, serial); + else if (surface->wl_shell_surface.resource) + wl_shell_surface_send_popup_done (surface->wl_shell_surface.resource); +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h new file mode 100644 index 000000000..25fe83c11 --- /dev/null +++ b/src/wayland/meta-wayland-surface.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * 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. + */ + +#ifndef META_WAYLAND_SURFACE_H +#define META_WAYLAND_SURFACE_H + +#include +#include +#include + +#include +#include + +#include +#include "meta-wayland-types.h" +#include "meta-surface-actor.h" + +struct _MetaWaylandBuffer +{ + struct wl_resource *resource; + struct wl_signal destroy_signal; + struct wl_listener destroy_listener; + + CoglTexture *texture; + uint32_t ref_count; +}; + +typedef struct +{ + /* wl_surface.attach */ + gboolean newly_attached; + MetaWaylandBuffer *buffer; + struct wl_listener buffer_destroy_listener; + int32_t dx; + int32_t dy; + + /* wl_surface.damage */ + cairo_region_t *damage; + + cairo_region_t *input_region; + cairo_region_t *opaque_region; + + /* wl_surface.frame */ + struct wl_list frame_callback_list; + + gboolean frame_extents_changed; + GtkBorder frame_extents; +} MetaWaylandDoubleBufferedState; + +typedef struct +{ + struct wl_resource *resource; +} MetaWaylandSurfaceExtension; + +struct _MetaWaylandSurface +{ + struct wl_resource *resource; + MetaWaylandCompositor *compositor; + MetaSurfaceActor *surface_actor; + MetaWindow *window; + MetaWaylandSurfaceExtension xdg_surface; + MetaWaylandSurfaceExtension xdg_popup; + MetaWaylandSurfaceExtension wl_shell_surface; + MetaWaylandSurfaceExtension gtk_surface; + MetaWaylandSurfaceExtension subsurface; + + MetaWaylandBuffer *buffer; + struct wl_listener buffer_destroy_listener; + + GList *subsurfaces; + + struct { + MetaWaylandSurface *parent; + struct wl_listener parent_destroy_listener; + + gboolean synchronous; + MetaWaylandDoubleBufferedState pending_surface_state; + + int32_t pending_x; + int32_t pending_y; + gboolean pending_pos; + GSList *pending_placement_ops; + } sub; + + uint32_t state_changed_serial; + + /* All the pending state, that wl_surface.commit will apply. */ + MetaWaylandDoubleBufferedState pending; +}; + +void meta_wayland_init_shell (MetaWaylandCompositor *compositor); + +MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *compositor, + struct wl_client *client, + guint32 id, + guint32 version); + +void meta_wayland_surface_set_window (MetaWaylandSurface *surface, + MetaWindow *window); + +void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, + int width, + int height); +void meta_wayland_surface_send_maximized (MetaWaylandSurface *surface); +void meta_wayland_surface_send_unmaximized (MetaWaylandSurface *surface); +void meta_wayland_surface_send_fullscreened (MetaWaylandSurface *surface); +void meta_wayland_surface_send_unfullscreened (MetaWaylandSurface *surface); + +void meta_wayland_surface_activated (MetaWaylandSurface *surface); +void meta_wayland_surface_deactivated (MetaWaylandSurface *surface); + +void meta_wayland_surface_ping (MetaWaylandSurface *surface, + guint32 serial); +void meta_wayland_surface_delete (MetaWaylandSurface *surface); + +void meta_wayland_surface_popup_done (MetaWaylandSurface *surface); + + +#endif diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h new file mode 100644 index 000000000..adecb057d --- /dev/null +++ b/src/wayland/meta-wayland-types.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * 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. + */ + +#ifndef META_WAYLAND_TYPES_H +#define META_WAYLAND_TYPES_H + +typedef struct _MetaWaylandCompositor MetaWaylandCompositor; + +typedef struct _MetaWaylandSeat MetaWaylandSeat; +typedef struct _MetaWaylandPointer MetaWaylandPointer; +typedef struct _MetaWaylandPointerGrab MetaWaylandPointerGrab; +typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface; +typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard; +typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab; +typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface; +typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer; +typedef struct _MetaWaylandDataSource MetaWaylandDataSource; + +typedef struct _MetaWaylandBuffer MetaWaylandBuffer; +typedef struct _MetaWaylandBufferReference MetaWaylandBufferReference; + +typedef struct _MetaWaylandSurface MetaWaylandSurface; + +#endif diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h new file mode 100644 index 000000000..d599908fa --- /dev/null +++ b/src/wayland/meta-wayland-versions.h @@ -0,0 +1,66 @@ +/* + * Wayland Support + * + * Copyright (C) 2012,2013 Intel Corporation + * 2013 Red Hat, Inc. + * + * 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. + */ + +#ifndef META_WAYLAND_VERSIONS_H +#define META_WAYLAND_VERSIONS_H + +/* Protocol objects, will never change version */ +/* #define META_WL_DISPLAY_VERSION 1 */ +/* #define META_WL_REGISTRY_VERSION 1 */ +#define META_WL_CALLBACK_VERSION 1 + +/* Not handled by mutter-wayland directly */ +/* #define META_WL_SHM_VERSION 1 */ +/* #define META_WL_SHM_POOL_VERSION 1 */ +/* #define META_WL_DRM_VERSION 1 */ +/* #define META_WL_BUFFER_VERSION 1 */ + +/* Global/master objects (version exported by wl_registry and negotiated through bind) */ +#define META_WL_COMPOSITOR_VERSION 3 +#define META_WL_DATA_DEVICE_MANAGER_VERSION 1 +#define META_WL_SHELL_VERSION 1 +#define META_WL_SEAT_VERSION 3 +#define META_WL_OUTPUT_VERSION 2 +#define META_XSERVER_VERSION 1 +#define META_GTK_SHELL_VERSION 1 +#define META_WL_SUBCOMPOSITOR_VERSION 1 + +/* Slave objects (version inherited from a master object) */ +#define META_WL_DATA_OFFER_VERSION 1 /* from wl_data_device */ +#define META_WL_DATA_SOURCE_VERSION 1 /* from wl_data_device */ +#define META_WL_DATA_DEVICE_VERSION 1 /* from wl_data_device_manager */ +#define META_WL_SURFACE_VERSION 3 /* from wl_compositor */ +#define META_WL_POINTER_VERSION 3 /* from wl_seat */ +#define META_WL_KEYBOARD_VERSION 3 /* from wl_seat */ +#define META_WL_TOUCH_VERSION 0 /* from wl_seat; wl_touch not supported */ +#define META_WL_REGION_VERSION 1 /* from wl_compositor */ +#define META_XDG_SURFACE_VERSION 1 /* from xdg_shell */ +#define META_XDG_POPUP_VERSION 1 /* from xdg_shell */ +#define META_WL_SHELL_SURFACE_VERSION 1 /* from wl_shell */ +#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */ +#define META_WL_SUBSURFACE_VERSION 1 /* from wl_subcompositor */ + +/* The first version to implement a specific event */ +#define META_WL_SEAT_HAS_NAME 2 +#define META_WL_OUTPUT_HAS_DONE 2 + +#endif diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c new file mode 100644 index 000000000..1d9be56ad --- /dev/null +++ b/src/wayland/meta-wayland.c @@ -0,0 +1,683 @@ +/* + * Wayland Support + * + * Copyright (C) 2012,2013 Intel Corporation + * + * 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "backends/meta-backend.h" + +#include "meta-wayland-private.h" +#include "meta-xwayland-private.h" +#include "meta-wayland-stage.h" +#include "meta-window-actor-private.h" +#include "meta-wayland-seat.h" +#include "meta-wayland-keyboard.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-data-device.h" +#include "meta-cursor-tracker-private.h" +#include "display-private.h" +#include "window-private.h" +#include +#include +#include "frame.h" +#include "meta-monitor-manager.h" + +static MetaWaylandCompositor _meta_wayland_compositor; + +MetaWaylandCompositor * +meta_wayland_compositor_get_default (void) +{ + return &_meta_wayland_compositor; +} + +static guint32 +get_time (void) +{ + struct timeval tv; + gettimeofday (&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +static gboolean +wayland_event_source_prepare (GSource *base, int *timeout) +{ + WaylandEventSource *source = (WaylandEventSource *)base; + + *timeout = -1; + + wl_display_flush_clients (source->display); + + return FALSE; +} + +static gboolean +wayland_event_source_check (GSource *base) +{ + WaylandEventSource *source = (WaylandEventSource *)base; + return source->pfd.revents; +} + +static gboolean +wayland_event_source_dispatch (GSource *base, + GSourceFunc callback, + void *data) +{ + WaylandEventSource *source = (WaylandEventSource *)base; + struct wl_event_loop *loop = wl_display_get_event_loop (source->display); + + wl_event_loop_dispatch (loop, 0); + + return TRUE; +} + +static GSourceFuncs wayland_event_source_funcs = +{ + wayland_event_source_prepare, + wayland_event_source_check, + wayland_event_source_dispatch, + NULL +}; + +static GSource * +wayland_event_source_new (struct wl_display *display) +{ + WaylandEventSource *source; + struct wl_event_loop *loop = wl_display_get_event_loop (display); + + source = (WaylandEventSource *) g_source_new (&wayland_event_source_funcs, + sizeof (WaylandEventSource)); + source->display = display; + source->pfd.fd = wl_event_loop_get_fd (loop); + source->pfd.events = G_IO_IN | G_IO_ERR; + g_source_add_poll (&source->source, &source->pfd); + + return &source->source; +} + +static void +meta_wayland_buffer_destroy_handler (struct wl_listener *listener, + void *data) +{ + MetaWaylandBuffer *buffer = + wl_container_of (listener, buffer, destroy_listener); + + wl_signal_emit (&buffer->destroy_signal, buffer); + g_slice_free (MetaWaylandBuffer, buffer); +} + +void +meta_wayland_buffer_ref (MetaWaylandBuffer *buffer) +{ + buffer->ref_count++; +} + +void +meta_wayland_buffer_unref (MetaWaylandBuffer *buffer) +{ + buffer->ref_count--; + if (buffer->ref_count == 0) + { + g_clear_pointer (&buffer->texture, cogl_object_unref); + wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE); + } +} + +MetaWaylandBuffer * +meta_wayland_buffer_from_resource (struct wl_resource *resource) +{ + MetaWaylandBuffer *buffer; + struct wl_listener *listener; + + listener = + wl_resource_get_destroy_listener (resource, + meta_wayland_buffer_destroy_handler); + + if (listener) + { + buffer = wl_container_of (listener, buffer, destroy_listener); + } + else + { + buffer = g_slice_new0 (MetaWaylandBuffer); + + buffer->resource = resource; + wl_signal_init (&buffer->destroy_signal); + buffer->destroy_listener.notify = meta_wayland_buffer_destroy_handler; + wl_resource_add_destroy_listener (resource, &buffer->destroy_listener); + } + + return buffer; +} + +void +meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor, + MetaWindow *window) +{ + MetaWaylandSurface *surface = window ? window->surface : NULL; + + meta_wayland_keyboard_set_focus (&compositor->seat->keyboard, + surface); + meta_wayland_data_device_set_keyboard_focus (compositor->seat); +} + +void +meta_wayland_compositor_repick (MetaWaylandCompositor *compositor) +{ + meta_wayland_seat_repick (compositor->seat, NULL); +} + +static void +meta_wayland_compositor_create_surface (struct wl_client *wayland_client, + struct wl_resource *wayland_compositor_resource, + guint32 id) +{ + MetaWaylandCompositor *compositor = + wl_resource_get_user_data (wayland_compositor_resource); + MetaWaylandSurface *surface; + + surface = meta_wayland_surface_create (compositor, + wayland_client, id, + MIN (META_WL_SURFACE_VERSION, + wl_resource_get_version (wayland_compositor_resource))); + + compositor->surfaces = g_list_prepend (compositor->surfaces, surface); +} + +static void +meta_wayland_region_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +meta_wayland_region_add (struct wl_client *client, + struct wl_resource *resource, + gint32 x, + gint32 y, + gint32 width, + gint32 height) +{ + MetaWaylandRegion *region = wl_resource_get_user_data (resource); + cairo_rectangle_int_t rectangle = { x, y, width, height }; + + cairo_region_union_rectangle (region->region, &rectangle); +} + +static void +meta_wayland_region_subtract (struct wl_client *client, + struct wl_resource *resource, + gint32 x, + gint32 y, + gint32 width, + gint32 height) +{ + MetaWaylandRegion *region = wl_resource_get_user_data (resource); + cairo_rectangle_int_t rectangle = { x, y, width, height }; + + cairo_region_subtract_rectangle (region->region, &rectangle); +} + +const struct wl_region_interface meta_wayland_region_interface = { + meta_wayland_region_destroy, + meta_wayland_region_add, + meta_wayland_region_subtract +}; + +static void +meta_wayland_region_resource_destroy_cb (struct wl_resource *resource) +{ + MetaWaylandRegion *region = wl_resource_get_user_data (resource); + + cairo_region_destroy (region->region); + g_slice_free (MetaWaylandRegion, region); +} + +static void +meta_wayland_compositor_create_region (struct wl_client *wayland_client, + struct wl_resource *compositor_resource, + uint32_t id) +{ + MetaWaylandRegion *region = g_slice_new0 (MetaWaylandRegion); + + region->resource = wl_resource_create (wayland_client, + &wl_region_interface, + MIN (META_WL_REGION_VERSION, + wl_resource_get_version (compositor_resource)), + id); + wl_resource_set_implementation (region->resource, + &meta_wayland_region_interface, region, + meta_wayland_region_resource_destroy_cb); + + region->region = cairo_region_create (); +} + +typedef struct { + MetaOutput *output; + struct wl_global *global; + int x, y; + enum wl_output_transform transform; + + GList *resources; +} MetaWaylandOutput; + +static void +output_resource_destroy (struct wl_resource *res) +{ + MetaWaylandOutput *wayland_output; + + wayland_output = wl_resource_get_user_data (res); + wayland_output->resources = g_list_remove (wayland_output->resources, res); +} + +static void +bind_output (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandOutput *wayland_output = data; + MetaOutput *output = wayland_output->output; + struct wl_resource *resource; + guint mode_flags; + + resource = wl_resource_create (client, &wl_output_interface, + MIN (META_WL_OUTPUT_VERSION, version), id); + wayland_output->resources = g_list_prepend (wayland_output->resources, resource); + + wl_resource_set_user_data (resource, wayland_output); + wl_resource_set_destructor (resource, output_resource_destroy); + + meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n", + output, output->name, + output->crtc->rect.x, output->crtc->rect.y, + output->crtc->rect.width, output->crtc->rect.height, + output->crtc->current_mode->refresh_rate); + + wl_resource_post_event (resource, + WL_OUTPUT_GEOMETRY, + (int)output->crtc->rect.x, + (int)output->crtc->rect.y, + output->width_mm, + output->height_mm, + /* Cogl values reflect XRandR values, + and so does wayland */ + output->subpixel_order, + output->vendor, + output->product, + output->crtc->transform); + + g_assert (output->crtc->current_mode != NULL); + + mode_flags = WL_OUTPUT_MODE_CURRENT; + if (output->crtc->current_mode == output->preferred_mode) + mode_flags |= WL_OUTPUT_MODE_PREFERRED; + + wl_resource_post_event (resource, + WL_OUTPUT_MODE, + mode_flags, + (int)output->crtc->current_mode->width, + (int)output->crtc->current_mode->height, + (int)output->crtc->current_mode->refresh_rate); + + if (version >= META_WL_OUTPUT_HAS_DONE) + wl_resource_post_event (resource, + WL_OUTPUT_DONE); +} + +static void +wayland_output_destroy_notify (gpointer data) +{ + MetaWaylandOutput *wayland_output = data; + GList *resources; + + /* Make sure the destructors don't mess with the list */ + resources = wayland_output->resources; + wayland_output->resources = NULL; + + wl_global_destroy (wayland_output->global); + g_list_free (resources); + + g_slice_free (MetaWaylandOutput, wayland_output); +} + +static void +wayland_output_update_for_output (MetaWaylandOutput *wayland_output, + MetaOutput *output) +{ + GList *iter; + guint mode_flags; + + g_assert (output->crtc->current_mode != NULL); + + mode_flags = WL_OUTPUT_MODE_CURRENT; + if (output->crtc->current_mode == output->preferred_mode) + mode_flags |= WL_OUTPUT_MODE_PREFERRED; + + for (iter = wayland_output->resources; iter; iter = iter->next) + { + struct wl_resource *resource = iter->data; + + if (wayland_output->x != output->crtc->rect.x || + wayland_output->y != output->crtc->rect.y || + wayland_output->transform != output->crtc->transform) + { + wl_resource_post_event (resource, + WL_OUTPUT_GEOMETRY, + (int)output->crtc->rect.x, + (int)output->crtc->rect.y, + output->width_mm, + output->height_mm, + output->subpixel_order, + output->vendor, + output->product, + output->crtc->transform); + } + + wl_resource_post_event (resource, + WL_OUTPUT_MODE, + mode_flags, + (int)output->crtc->current_mode->width, + (int)output->crtc->current_mode->height, + (int)output->crtc->current_mode->refresh_rate); + } + + /* It's very important that we change the output pointer here, as + the old structure is about to be freed by MetaMonitorManager */ + wayland_output->output = output; + wayland_output->x = output->crtc->rect.x; + wayland_output->y = output->crtc->rect.y; + wayland_output->transform = output->crtc->transform; +} + +static GHashTable * +meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor, + MetaMonitorManager *monitors) +{ + MetaOutput *outputs; + unsigned int i, n_outputs; + GHashTable *new_table; + + outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs); + new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify); + + for (i = 0; i < n_outputs; i++) + { + MetaOutput *output = &outputs[i]; + MetaWaylandOutput *wayland_output; + + /* wayland does not expose disabled outputs */ + if (output->crtc == NULL) + { + g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id)); + continue; + } + + wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id)); + + if (wayland_output) + { + g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id)); + } + else + { + wayland_output = g_slice_new0 (MetaWaylandOutput); + wayland_output->global = wl_global_create (compositor->wayland_display, + &wl_output_interface, + META_WL_OUTPUT_VERSION, + wayland_output, bind_output); + } + + wayland_output_update_for_output (wayland_output, output); + g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output); + } + + g_hash_table_destroy (compositor->outputs); + return new_table; +} + +const static struct wl_compositor_interface meta_wayland_compositor_interface = { + meta_wayland_compositor_create_surface, + meta_wayland_compositor_create_region +}; + +void +meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor) +{ + while (!wl_list_empty (&compositor->frame_callbacks)) + { + MetaWaylandFrameCallback *callback = + wl_container_of (compositor->frame_callbacks.next, callback, link); + + wl_callback_send_done (callback->resource, get_time ()); + wl_resource_destroy (callback->resource); + } +} + +static void +compositor_bind (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandCompositor *compositor = data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_compositor_interface, + MIN (META_WL_COMPOSITOR_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_compositor_interface, compositor, NULL); +} + +static void +stage_destroy_cb (void) +{ + meta_quit (META_EXIT_SUCCESS); +} + +/** + * meta_wayland_compositor_update: + * @compositor: the #MetaWaylandCompositor instance + * @event: the #ClutterEvent used to update @seat's state + * + * This is used to update display server state like updating cursor + * position and keeping track of buttons and keys pressed. It must be + * called for all input events coming from the underlying devices. + */ +void +meta_wayland_compositor_update (MetaWaylandCompositor *compositor, + const ClutterEvent *event) +{ + meta_wayland_seat_update (compositor->seat, event); +} + +/** + * meta_wayland_compositor_handle_event: + * @compositor: the #MetaWaylandCompositor instance + * @event: the #ClutterEvent to be sent + * + * This method sends events to the focused wayland client, if any. + * + * Return value: whether @event was sent to a wayland client. + */ +gboolean +meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor, + const ClutterEvent *event) +{ + return meta_wayland_seat_handle_event (compositor->seat, event); +} + +static void +on_monitors_changed (MetaMonitorManager *monitors, + MetaWaylandCompositor *compositor) +{ + compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors); +} + +static void +set_gnome_env (const char *name, + const char *value) +{ + GDBusConnection *session_bus; + GError *error = NULL; + + setenv (name, value, TRUE); + + session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_assert (session_bus); + + g_dbus_connection_call_sync (session_bus, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + "Setenv", + g_variant_new ("(ss)", name, value), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (error) + { + if (g_strcmp0 (g_dbus_error_get_remote_error (error), "org.gnome.SessionManager.NotInInitialization") != 0) + meta_warning ("Failed to set environment variable %s for gnome-session: %s\n", name, error->message); + + g_error_free (error); + } +} + +static void +meta_wayland_log_func (const char *fmt, + va_list arg) +{ + char *str = g_strdup_vprintf (fmt, arg); + g_warning ("WL: %s", str); + g_free (str); +} + +void +meta_wayland_init (void) +{ + MetaWaylandCompositor *compositor = &_meta_wayland_compositor; + MetaMonitorManager *monitors; + + memset (compositor, 0, sizeof (MetaWaylandCompositor)); + + compositor->wayland_display = wl_display_create (); + if (compositor->wayland_display == NULL) + g_error ("failed to create wayland display"); + + wl_display_init_shm (compositor->wayland_display); + wl_log_set_handler_server(meta_wayland_log_func); + + wl_list_init (&compositor->frame_callbacks); + + if (!wl_global_create (compositor->wayland_display, + &wl_compositor_interface, + META_WL_COMPOSITOR_VERSION, + compositor, compositor_bind)) + g_error ("Failed to register wayland compositor object"); + + compositor->wayland_loop = + wl_display_get_event_loop (compositor->wayland_display); + compositor->wayland_event_source = + wayland_event_source_new (compositor->wayland_display); + + /* XXX: Here we are setting the wayland event source to have a + * slightly lower priority than the X event source, because we are + * much more likely to get confused being told about surface changes + * relating to X clients when we don't know what's happened to them + * according to the X protocol. + * + * At some point we could perhaps try and get the X protocol proxied + * over the wayland protocol so that we don't have to worry about + * synchronizing the two command streams. */ + g_source_set_priority (compositor->wayland_event_source, + GDK_PRIORITY_EVENTS + 1); + g_source_attach (compositor->wayland_event_source, NULL); + + clutter_wayland_set_compositor_display (compositor->wayland_display); + + meta_clutter_init (); + + meta_monitor_manager_initialize (); + monitors = meta_monitor_manager_get (); + g_signal_connect (monitors, "monitors-changed", + G_CALLBACK (on_monitors_changed), compositor); + + compositor->outputs = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify); + compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors); + + compositor->stage = meta_wayland_stage_new (); + g_signal_connect (compositor->stage, "destroy", + G_CALLBACK (stage_destroy_cb), NULL); + + meta_wayland_data_device_manager_init (compositor->wayland_display); + + compositor->seat = meta_wayland_seat_new (compositor->wayland_display); + + meta_wayland_init_shell (compositor); + + clutter_actor_show (compositor->stage); + + /* FIXME: find the first free name instead */ + compositor->display_name = g_strdup ("wayland-0"); + if (wl_display_add_socket (compositor->wayland_display, compositor->display_name)) + g_error ("Failed to create socket"); + + /* XXX: It's important that we only try and start xwayland after we + * have initialized EGL because EGL implements the "wl_drm" + * interface which xwayland requires to determine what drm device + * name it should use. + * + * By waiting until we've shown the stage above we ensure that the + * underlying GL resources for the surface have also been allocated + * and so EGL must be initialized by this point. + */ + + if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display)) + g_error ("Failed to start X Wayland"); + + set_gnome_env ("DISPLAY", compositor->xwayland_manager.display_name); + set_gnome_env ("WAYLAND_DISPLAY", compositor->display_name); +} + +void +meta_wayland_finalize (void) +{ + MetaWaylandCompositor *compositor; + + compositor = meta_wayland_compositor_get_default (); + + meta_xwayland_stop (&compositor->xwayland_manager); +} diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h new file mode 100644 index 000000000..4f12660d9 --- /dev/null +++ b/src/wayland/meta-wayland.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef META_WAYLAND_H +#define META_WAYLAND_H + +#include "meta-wayland-types.h" + +void meta_wayland_init (void); +void meta_wayland_finalize (void); + +/* We maintain a singleton MetaWaylandCompositor which can be got at via this + * API after meta_wayland_init() has been called. */ +MetaWaylandCompositor *meta_wayland_compositor_get_default (void); + +void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor); + +void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor, + MetaWindow *window); +gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor, + const ClutterEvent *event); + +void meta_wayland_compositor_update (MetaWaylandCompositor *compositor, + const ClutterEvent *event); +void meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor); + +#endif + diff --git a/src/wayland/meta-xwayland-private.h b/src/wayland/meta-xwayland-private.h new file mode 100644 index 000000000..83b2986d3 --- /dev/null +++ b/src/wayland/meta-xwayland-private.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 Intel Corporation + * + * 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. + */ + +#ifndef META_XWAYLAND_PRIVATE_H +#define META_XWAYLAND_PRIVATE_H + +#include "meta-wayland-private.h" + +#include + +gboolean +meta_xwayland_start (MetaXWaylandManager *manager, + struct wl_display *display); + +void +meta_xwayland_complete_init (void); + +void +meta_xwayland_stop (MetaXWaylandManager *manager); + +#endif /* META_XWAYLAND_PRIVATE_H */ diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c new file mode 100644 index 000000000..a4ec03f6e --- /dev/null +++ b/src/wayland/meta-xwayland.c @@ -0,0 +1,477 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * X Wayland Support + * + * Copyright (C) 2013 Intel Corporation + * + * 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 "config.h" + +#include "meta-xwayland.h" +#include "meta-xwayland-private.h" + +#include "meta-wayland-surface-private.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +associate_window_with_surface (MetaWindow *window, + MetaWaylandSurface *surface) +{ + MetaDisplay *display = window->display; + + /* If the window has an existing surface, like if we're + * undecorating or decorating the window, then we need + * to detach the window from its old surface. + */ + if (window->surface) + window->surface->window = NULL; + + meta_wayland_surface_set_window (surface, window); + window->surface = surface; + + meta_compositor_window_surface_changed (display->compositor, window); + + /* Since the association comes in the form of a ClientMessage, + * we have no way to know when the surface was set up. Since + * commit just breaks if we don't have a window associated with + * it, we need to do a commit *again* here. */ + meta_wayland_surface_commit (surface); + + /* Now that we have a surface check if it should have focus. */ + meta_display_sync_wayland_input_focus (display); +} + +static gboolean +associate_window_with_surface_id (MetaXWaylandManager *manager, + MetaWindow *window, + guint32 surface_id) +{ + struct wl_resource *resource; + + resource = wl_client_get_object (manager->client, surface_id); + if (resource) + { + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + associate_window_with_surface (window, surface); + return TRUE; + } + else + return FALSE; +} + +typedef struct { + MetaXWaylandManager *manager; + MetaWindow *window; + guint32 surface_id; +} AssociateWindowWithSurfaceOp; + +static gboolean +associate_window_with_surface_idle (gpointer user_data) +{ + AssociateWindowWithSurfaceOp *op = user_data; + if (!associate_window_with_surface_id (op->manager, op->window, op->surface_id)) + { + /* Not here? Oh well... nothing we can do */ + g_warning ("Unknown surface ID %d (from window %s)", op->surface_id, op->window->desc); + } + g_free (op); + + return G_SOURCE_REMOVE; +} + +void +meta_xwayland_handle_wl_surface_id (MetaWindow *window, + guint32 surface_id) +{ + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + MetaXWaylandManager *manager = &compositor->xwayland_manager; + + if (!associate_window_with_surface_id (manager, window, surface_id)) + { + /* No surface ID yet... it should arrive after the next + * iteration through the loop, so queue an idle and see + * what happens. + */ + AssociateWindowWithSurfaceOp *op = g_new0 (AssociateWindowWithSurfaceOp, 1); + op->manager = manager; + op->window = window; + op->surface_id = surface_id; + g_idle_add (associate_window_with_surface_idle, op); + } +} + +static char * +create_lockfile (int display, int *display_out) +{ + char *filename; + int size; + char pid[11]; + int fd; + + do + { + char *end; + pid_t other; + + filename = g_strdup_printf ("/tmp/.X%d-lock", display); + fd = open (filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444); + + if (fd < 0 && errno == EEXIST) + { + fd = open (filename, O_CLOEXEC, O_RDONLY); + if (fd < 0 || read (fd, pid, 11) != 11) + { + const char *msg = strerror (errno); + g_warning ("can't read lock file %s: %s", filename, msg); + g_free (filename); + + /* ignore error and try the next display number */ + display++; + continue; + } + close (fd); + + other = strtol (pid, &end, 0); + if (end != pid + 10) + { + g_warning ("can't parse lock file %s", filename); + g_free (filename); + + /* ignore error and try the next display number */ + display++; + continue; + } + + if (kill (other, 0) < 0 && errno == ESRCH) + { + if (unlink (filename) < 0) + { + const char *msg = strerror (errno); + g_warning ("failed to unlink stale lock file: %s", msg); + display++; + } + g_free (filename); + continue; + } + + g_free (filename); + display++; + continue; + } + else if (fd < 0) + { + const char *msg = strerror (errno); + g_warning ("failed to create lock file %s: %s", filename , msg); + g_free (filename); + return NULL; + } + + break; + } + while (1); + + /* Subtle detail: we use the pid of the wayland compositor, not the xserver + * in the lock file. */ + size = snprintf (pid, 11, "%10d\n", getpid ()); + if (size != 11 || write (fd, pid, 11) != 11) + { + unlink (filename); + close (fd); + g_warning ("failed to write pid to lock file %s", filename); + g_free (filename); + return NULL; + } + + close (fd); + + *display_out = display; + return filename; +} + +static int +bind_to_abstract_socket (int display) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -1; + + addr.sun_family = AF_LOCAL; + name_size = snprintf (addr.sun_path, sizeof addr.sun_path, + "%c/tmp/.X11-unix/X%d", 0, display); + size = offsetof (struct sockaddr_un, sun_path) + name_size; + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { + g_warning ("failed to bind to @%s: %m", addr.sun_path + 1); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { + close (fd); + return -1; + } + + return fd; +} + +static int +bind_to_unix_socket (int display) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -1; + + addr.sun_family = AF_LOCAL; + name_size = snprintf (addr.sun_path, sizeof addr.sun_path, + "/tmp/.X11-unix/X%d", display) + 1; + size = offsetof (struct sockaddr_un, sun_path) + name_size; + unlink (addr.sun_path); + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { + g_warning ("failed to bind to %s: %m\n", addr.sun_path); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { + unlink (addr.sun_path); + close (fd); + return -1; + } + + return fd; +} + +static void +xserver_died (GPid pid, + gint status, + gpointer user_data) +{ + if (!WIFEXITED (status)) + g_error ("X Wayland crashed; aborting"); + else + { + /* For now we simply abort if we see the server exit. + * + * In the future X will only be loaded lazily for legacy X support + * but for now it's a hard requirement. */ + g_error ("Spurious exit of X Wayland server"); + } +} + +static int +x_io_error (Display *display) +{ + g_error ("Connection to xwayland lost"); + + return 0; +} + +static gboolean +choose_xdisplay (MetaXWaylandManager *manager) +{ + int display = 0; + char *lockfile = NULL; + + do + { + lockfile = create_lockfile (display, &display); + if (!lockfile) + { + g_warning ("Failed to create an X lock file"); + return FALSE; + } + + manager->abstract_fd = bind_to_abstract_socket (display); + if (manager->abstract_fd < 0) + { + unlink (lockfile); + + if (errno == EADDRINUSE) + { + display++; + continue; + } + else + return FALSE; + } + + manager->unix_fd = bind_to_unix_socket (display); + if (manager->abstract_fd < 0) + { + unlink (lockfile); + close (manager->abstract_fd); + return FALSE; + } + + break; + } + while (1); + + manager->display_index = display; + manager->display_name = g_strdup_printf (":%d", manager->display_index); + manager->lockfile = lockfile; + + return TRUE; +} + +static void +xserver_finished_init (MetaXWaylandManager *manager) +{ + /* At this point xwayland is all setup to start accepting + * connections so we can quit the transient initialization mainloop + * and unblock meta_wayland_init() to continue initializing mutter. + * */ + g_main_loop_quit (manager->init_loop); + g_clear_pointer (&manager->init_loop, g_main_loop_unref); +} + +static gboolean +got_sigusr1 (gpointer user_data) +{ + MetaXWaylandManager *manager = user_data; + + xserver_finished_init (manager); + + return G_SOURCE_REMOVE; +} + +gboolean +meta_xwayland_start (MetaXWaylandManager *manager, + struct wl_display *wl_display) +{ + int sp[2]; + int fd; + + if (!choose_xdisplay (manager)) + return FALSE; + + /* We want xwayland to be a wayland client so we make a socketpair to setup a + * wayland protocol connection. */ + if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sp) < 0) + { + g_warning ("socketpair failed\n"); + unlink (manager->lockfile); + return 1; + } + + manager->pid = fork (); + if (manager->pid == 0) + { + char socket_fd[8], unix_fd[8], abstract_fd[8]; + + /* We passed SOCK_CLOEXEC, so dup the FD so it isn't + * closed on exec.. */ + fd = dup (sp[1]); + snprintf (socket_fd, sizeof (socket_fd), "%d", fd); + setenv ("WAYLAND_SOCKET", socket_fd, TRUE); + + fd = dup (manager->abstract_fd); + snprintf (abstract_fd, sizeof (abstract_fd), "%d", fd); + + fd = dup (manager->unix_fd); + snprintf (unix_fd, sizeof (unix_fd), "%d", fd); + + /* xwayland, please. */ + if (getenv ("XWAYLAND_STFU")) + { + int dev_null; + dev_null = open ("/dev/null", O_WRONLY); + + dup2 (dev_null, STDOUT_FILENO); + dup2 (dev_null, STDERR_FILENO); + } + + /* We have to ignore SIGUSR1 in the child to make sure + * that the server will send it to mutter-wayland. */ + signal(SIGUSR1, SIG_IGN); + + if (execl (XWAYLAND_PATH, XWAYLAND_PATH, + manager->display_name, + "-rootless", + "-noreset", + "-listen", abstract_fd, + "-listen", unix_fd, + NULL) < 0) + { + g_error ("Failed to spawn XWayland: %m"); + } + } + else if (manager->pid == -1) + { + g_error ("Failed to fork: %m"); + } + + g_child_watch_add (manager->pid, xserver_died, NULL); + g_unix_signal_add (SIGUSR1, got_sigusr1, manager); + manager->client = wl_client_create (wl_display, sp[0]); + + /* We need to run a mainloop until we know xwayland has a binding + * for our xserver interface at which point we can assume it's + * ready to start accepting connections. */ + manager->init_loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (manager->init_loop); + + return TRUE; +} + +/* To be called right after connecting */ +void +meta_xwayland_complete_init (void) +{ + /* We install an X IO error handler in addition to the child watch, + because after Xlib connects our child watch may not be called soon + enough, and therefore we won't crash when X exits (and most important + we won't reset the tty). + */ + XSetIOErrorHandler (x_io_error); +} + +void +meta_xwayland_stop (MetaXWaylandManager *manager) +{ + char path[256]; + + snprintf (path, sizeof path, "/tmp/.X%d-lock", manager->display_index); + unlink (path); + snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index); + unlink (path); + + unlink (manager->lockfile); +} diff --git a/src/wayland/meta-xwayland.h b/src/wayland/meta-xwayland.h new file mode 100644 index 000000000..5308f2957 --- /dev/null +++ b/src/wayland/meta-xwayland.h @@ -0,0 +1,35 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef META_XWAYLAND_H +#define META_XWAYLAND_H + +#include +#include + +void +meta_xwayland_handle_wl_surface_id (MetaWindow *window, + guint32 surface_id); + +#endif /* META_XWAYLAND_H */ diff --git a/src/wayland/protocol/gtk-shell.xml b/src/wayland/protocol/gtk-shell.xml new file mode 100644 index 000000000..e2cc4f455 --- /dev/null +++ b/src/wayland/protocol/gtk-shell.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wayland/protocol/xdg-shell.xml b/src/wayland/protocol/xdg-shell.xml new file mode 100644 index 000000000..a2913c4c0 --- /dev/null +++ b/src/wayland/protocol/xdg-shell.xml @@ -0,0 +1,444 @@ + + + + + Copyright © 2008-2013 Kristian Høgsberg + Copyright © 2013 Rafael Antognolli + Copyright © 2013 Jasper St. Pierre + Copyright © 2010-2013 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + This interface is implemented by servers that provide + desktop-style user interfaces. + + It allows clients to associate a xdg_surface with + a basic surface. + + + + + The 'current' member of this enum gives the version of the + protocol. Implementations can compare this to the version + they implement using static_assert to ensure the protocol and + implementation versions match. + + + + + + + + Negotiate the unstable version of the interface. This + mechanism is in place to ensure client and server agree on the + unstable versions of the protocol that they speak or exit + cleanly if they don't agree. This request will go away once + the xdg-shell protocol is stable. + + + + + + + Create a shell surface for an existing surface. + + Only one shell or popup surface can be associated with a given + surface. + + + + + + + + Create a popup surface for an existing surface. + + Only one shell or popup surface can be associated with a given + surface. + + + + + + + + + + + + + + The ping event asks the client if it's still alive. Pass the + serial specified in the event back to the compositor by sending + a "pong" request back with the specified serial. + + Compositors can use this to determine if the client is still + alive. It's unspecified what will happen if the client doesn't + respond to the ping request, or in what timeframe. Clients should + try to respond in a reasonable amount of time. + + + + + + + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. + + + + + + + + + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style user interface. + + It provides requests to treat surfaces like windows, allowing to set + properties like maximized, fullscreen, minimized, and to move and resize + them, and associate metadata like title and app id. + + On the server side the object is automatically destroyed when + the related wl_surface is destroyed. On client side, + xdg_surface.destroy() must be called before destroying + the wl_surface object. + + + + + The xdg_surface interface is removed from the wl_surface object + that was turned into a xdg_surface with + xdg_shell.get_xdg_surface request. The xdg_surface properties, + like maximized and fullscreen, are lost. The wl_surface loses + its role as a xdg_surface. The wl_surface is unmapped. + + + + + + Setting a surface as transient of another means that it is child + of another surface. + + Child surfaces are stacked above their parents, and will be + unmapped if the parent is unmapped too. They should not appear + on task bars and alt+tab. + + + + + + + This tells the compositor what the visible size of the window + should be, so it can use it to determine what borders to use for + constrainment and alignment. + + CSD often has invisible areas for decoration purposes, like drop + shadows. These "shadow" drawings need to be subtracted out of the + normal boundaries of the window when computing where to place + windows (e.g. to set this window so it's centered on top of another, + or to put it to the left or right of the screen.) + + This value should change as little as possible at runtime, to + prevent flicker. + + This value is also ignored when the window is maximized or + fullscreen, and assumed to be 0. + + If never called, this value is assumed to be 0. + + + + + + + + + + Set a short title for the surface. + + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. + + The string must be encoded in UTF-8. + + + + + + + Set an id for the surface. + + The app id identifies the general class of applications to which + the surface belongs. + + It should be the ID that appears in the new desktop entry + specification, the interface name. + + + + + + + Start a pointer-driven move of the surface. + + This request must be used in response to a button press event. + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized). + + + + + + + + These values are used to indicate which edge of a surface + is being dragged in a resize operation. The server may + use this information to adapt its behavior, e.g. choose + an appropriate cursor image. + + + + + + + + + + + + + + + Start a pointer-driven resizing of the surface. + + This request must be used in response to a button press event. + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). + + + + + + + + + The configure event asks the client to resize its surface. + + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). + + The client is free to dismiss all but the last configure + event it received. + + The width and height arguments specify the size of the window + in surface local coordinates. + + + + + + + + + Set the default output used by this surface when it is first mapped. + + If this value is NULL (default), it's up to the compositor to choose + which display will be used to map this surface. + + When fullscreen or maximized state are set on this surface, and it + wasn't mapped yet, the output set with this method will be used. + Otherwise, the output where the surface is currently mapped will be + used. + + + + + + + The different state values used on the surface. This is designed for + state values like maximized, fullscreen. It is paired with the + request_change_state event to ensure that both the client and the + compositor setting the state can be synchronized. + + States set in this way are double-buffered. They will get applied on + the next commit. + + Desktop environments may extend this enum by taking up a range of + values and documenting the range they chose in this description. + They are not required to document the values for the range that they + chose. Ideally, any good extensions from a desktop environment should + make its way into standardization into this enum. + + The current reserved ranges are: + + 0x0000 - 0x0FFF: xdg-shell core values, documented below. + 0x1000 - 0x1FFF: GNOME + + + A non-zero value indicates the surface is maximized. Otherwise, + the surface is unmaximized. + + + A non-zero value indicates the surface is fullscreen. Otherwise, + the surface is not fullscreen. + + + + + + This asks the compositor to change the state. If the compositor wants + to change the state, it will send a change_state event with the same + state_type, value, and serial, and the event flow continues as if it + it was initiated by the compositor. + + If the compositor does not want to change the state, it will send a + change_state to the client with the old value of the state. + + + + + This serial is so the client can know which change_state event corresponds + to which request_change_state request it sent out. + + + + + + This event tells the client to change a surface's state. The client + should respond with an ack_change_state request to the compositor to + guarantee that the compositor knows that the client has seen it. + + + + + + + + + + When a change_state event is received, a client should then ack it + using the ack_change_state request to ensure that the compositor + knows the client has seen the event. + + By this point, the state is confirmed, and the next attach should + contain the buffer drawn for the new state value. + + The values here need to be the same as the values in the cooresponding + change_state event. + + + + + + + + + Minimize the surface. + + + + + + The activated_set event is sent when this surface has been + activated, which means that the surface has user attention. + Window decorations should be updated accordingly. You should + not use this event for anything but the style of decorations + you display, use wl_keyboard.enter and wl_keyboard.leave for + determining keyboard focus. + + + + + + The deactivate event is sent when this surface has been + deactivated, which means that the surface lost user attention. + Window decorations should be updated accordingly. You should + not use this event for anything but the style of decorations + you display, use wl_keyboard.enter and wl_keyboard.leave for + determining keyboard focus. + + + + + + The delete event is sent by the compositor when the user + wants the surface to be closed. This should be equivalent to + the user clicking the close button in client-side decorations, + if your application has any... + + This is only a request that the user intends to close your + window. The client may choose to ignore this request, or show + a dialog to ask the user to save their data... + + + + + + + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style popups/menus. A popup + surface is a transient surface with an added pointer grab. + + An existing implicit grab will be changed to owner-events mode, + and the popup grab will continue after the implicit grab ends + (i.e. releasing the mouse button does not cause the popup to be + unmapped). + + The popup grab continues until the window is destroyed or a mouse + button is pressed in any other clients window. A click in any of + the clients surfaces is reported as normal, however, clicks in + other clients surfaces will be discarded and trigger the callback. + + The x and y arguments specify the locations of the upper left + corner of the surface relative to the upper left corner of the + parent surface, in surface local coordinates. + + xdg_popup surfaces are always transient for another surface. + + + + + The xdg_surface interface is removed from the wl_surface object + that was turned into a xdg_surface with + xdg_shell.get_xdg_surface request. The xdg_surface properties, + like maximized and fullscreen, are lost. The wl_surface loses + its role as a xdg_surface. The wl_surface is unmapped. + + + + + + The popup_done event is sent out when a popup grab is broken, + that is, when the users clicks a surface that doesn't belong + to the client owning the popup surface. + + + + + + diff --git a/src/wayland/window-wayland.c b/src/wayland/window-wayland.c new file mode 100644 index 000000000..e52c1435e --- /dev/null +++ b/src/wayland/window-wayland.c @@ -0,0 +1,220 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "window-wayland.h" + +#include "window-private.h" +#include "boxes-private.h" +#include "stack-tracker.h" +#include "meta-wayland-surface.h" + +struct _MetaWindowWayland +{ + MetaWindow parent; +}; + +struct _MetaWindowWaylandClass +{ + MetaWindowClass parent_class; +}; + +G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW) + +static void +meta_window_wayland_manage (MetaWindow *window) +{ + MetaDisplay *display = window->display; + + meta_display_register_wayland_window (display, window); + + { + MetaStackWindow stack_window; + stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND; + stack_window.wayland.meta_window = window; + meta_stack_tracker_record_add (window->screen->stack_tracker, + &stack_window, + 0); + } +} + +static void +meta_window_wayland_unmanage (MetaWindow *window) +{ + { + MetaStackWindow stack_window; + stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND; + stack_window.wayland.meta_window = window; + meta_stack_tracker_record_remove (window->screen->stack_tracker, + &stack_window, + 0); + } + + meta_display_unregister_wayland_window (window->display, window); +} + +static void +meta_window_wayland_ping (MetaWindow *window, + guint32 serial) +{ + meta_wayland_surface_ping (window->surface, serial); +} + +static void +meta_window_wayland_delete (MetaWindow *window, + guint32 timestamp) +{ + meta_wayland_surface_delete (window->surface); +} + +static void +meta_window_wayland_kill (MetaWindow *window) +{ + MetaWaylandSurface *surface = window->surface; + struct wl_resource *resource = surface->resource; + + /* Send the client an unrecoverable error to kill the client. */ + wl_resource_post_error (resource, + WL_DISPLAY_ERROR_NO_MEMORY, + "User requested that we kill you. Sorry. Don't take it too personally."); +} + +static void +meta_window_wayland_focus (MetaWindow *window, + guint32 timestamp) +{ + meta_display_set_input_focus_window (window->display, + window, + FALSE, + timestamp); +} + +static void +meta_window_wayland_move_resize_internal (MetaWindow *window, + int gravity, + MetaRectangle requested_rect, + MetaRectangle constrained_rect, + MetaMoveResizeFlags flags, + MetaMoveResizeResultFlags *result) +{ + g_assert (window->frame == NULL); + + /* For wayland clients, the size is completely determined by the client, + * and while this allows to avoid some trickery with frames and the resulting + * lagging, we also need to insist a bit when the constraints would apply + * a different size than the client decides. + * + * Note that this is not generally a problem for normal toplevel windows (the + * constraints don't see the size hints, or just change the position), but + * it can be for maximized or fullscreen. + */ + + /* First, save where we would like the client to be. This is used by the next + * attach to determine if the client is really moving/resizing or not. + */ + window->expected_rect = constrained_rect; + + if (flags & META_IS_WAYLAND_RESIZE) + { + /* This is a call to wl_surface_commit(), ignore the constrained_rect and + * update the real client size to match the buffer size. + */ + + window->rect.width = requested_rect.width; + window->rect.height = requested_rect.height; + } + + if (constrained_rect.width != window->rect.width || + constrained_rect.height != window->rect.height) + { + /* We need to resize the client. Resizing is in two parts: + * some of the movement happens immediately, and some happens as part + * of the resizing (through dx/dy in wl_surface_attach). + * + * To do so, we need to compute the resize from the point of the view + * of the client, and then adjust the immediate resize to match. + * + * dx/dy are the values we expect from the new attach(), while deltax/ + * deltay reflect the overall movement. + */ + MetaRectangle old_rect; + MetaRectangle client_rect; + int dx, dy; + int deltax, deltay; + + meta_window_get_client_root_coords (window, &old_rect); + + meta_rectangle_resize_with_gravity (&old_rect, + &client_rect, + gravity, + constrained_rect.width, + constrained_rect.height); + + deltax = constrained_rect.x - old_rect.x; + deltay = constrained_rect.y - old_rect.y; + dx = client_rect.x - constrained_rect.x; + dy = client_rect.y - constrained_rect.y; + + if (deltax != dx || deltay != dy) + *result |= META_MOVE_RESIZE_RESULT_MOVED; + + window->rect.x += (deltax - dx); + window->rect.y += (deltay - dy); + + *result |= META_MOVE_RESIZE_RESULT_RESIZED; + meta_wayland_surface_configure_notify (window->surface, + constrained_rect.width, + constrained_rect.height); + } + else + { + /* No resize happening, we can just move the window and live with it. */ + if (window->rect.x != constrained_rect.x || + window->rect.y != constrained_rect.y) + *result |= META_MOVE_RESIZE_RESULT_MOVED; + + window->rect.x = constrained_rect.x; + window->rect.y = constrained_rect.y; + } +} + +static void +meta_window_wayland_init (MetaWindowWayland *window_wayland) +{ +} + +static void +meta_window_wayland_class_init (MetaWindowWaylandClass *klass) +{ + MetaWindowClass *window_class = META_WINDOW_CLASS (klass); + + window_class->manage = meta_window_wayland_manage; + window_class->unmanage = meta_window_wayland_unmanage; + window_class->ping = meta_window_wayland_ping; + window_class->delete = meta_window_wayland_delete; + window_class->kill = meta_window_wayland_kill; + window_class->focus = meta_window_wayland_focus; + window_class->move_resize_internal = meta_window_wayland_move_resize_internal; +} diff --git a/src/wayland/window-wayland.h b/src/wayland/window-wayland.h new file mode 100644 index 000000000..c1c667468 --- /dev/null +++ b/src/wayland/window-wayland.h @@ -0,0 +1,44 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2014 Red Hat + * + * 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. + * + * Written by: + * Jasper St. Pierre + */ + +#ifndef META_WINDOW_WAYLAND_H +#define META_WINDOW_WAYLAND_H + +#include + +G_BEGIN_DECLS + +#define META_TYPE_WINDOW_WAYLAND (meta_window_wayland_get_type()) +#define META_WINDOW_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_WAYLAND, MetaWindowWayland)) +#define META_WINDOW_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_WAYLAND, MetaWindowWaylandClass)) +#define META_IS_WINDOW_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_WAYLAND)) +#define META_IS_WINDOW_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_WAYLAND)) +#define META_WINDOW_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_WAYLAND, MetaWindowWaylandClass)) + +GType meta_window_wayland_get_type (void); + +typedef struct _MetaWindowWayland MetaWindowWayland; +typedef struct _MetaWindowWaylandClass MetaWindowWaylandClass; + +#endif diff --git a/src/core/async-getprop.c b/src/x11/async-getprop.c similarity index 100% rename from src/core/async-getprop.c rename to src/x11/async-getprop.c diff --git a/src/core/async-getprop.h b/src/x11/async-getprop.h similarity index 100% rename from src/core/async-getprop.h rename to src/x11/async-getprop.h diff --git a/src/core/group-private.h b/src/x11/group-private.h similarity index 100% rename from src/core/group-private.h rename to src/x11/group-private.h diff --git a/src/core/group-props.c b/src/x11/group-props.c similarity index 100% rename from src/core/group-props.c rename to src/x11/group-props.c diff --git a/src/core/group-props.h b/src/x11/group-props.h similarity index 100% rename from src/core/group-props.h rename to src/x11/group-props.h diff --git a/src/core/group.c b/src/x11/group.c similarity index 100% rename from src/core/group.c rename to src/x11/group.c diff --git a/src/core/iconcache.c b/src/x11/iconcache.c similarity index 99% rename from src/core/iconcache.c rename to src/x11/iconcache.c index 30018d22e..ac09190f3 100644 --- a/src/core/iconcache.c +++ b/src/x11/iconcache.c @@ -230,7 +230,7 @@ read_rgb_icon (MetaDisplay *display, int mini_w, mini_h; gulong *data_as_long; - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); type = None; data = NULL; result = XGetWindowProperty (display->xdisplay, @@ -504,7 +504,7 @@ get_kwm_win_icon (MetaDisplay *display, *pixmap = None; *mask = None; - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); icons = NULL; result = XGetWindowProperty (display->xdisplay, xwindow, display->atom__KWM_WIN_ICON, diff --git a/src/core/iconcache.h b/src/x11/iconcache.h similarity index 100% rename from src/core/iconcache.h rename to src/x11/iconcache.h diff --git a/src/core/mutter-Xatomtype.h b/src/x11/mutter-Xatomtype.h similarity index 100% rename from src/core/mutter-Xatomtype.h rename to src/x11/mutter-Xatomtype.h diff --git a/src/core/session.c b/src/x11/session.c similarity index 97% rename from src/core/session.c rename to src/x11/session.c index 2a76619d7..48678ab61 100644 --- a/src/core/session.c +++ b/src/x11/session.c @@ -24,6 +24,7 @@ #include #include "util-private.h" +#include #include "session.h" #include @@ -530,6 +531,12 @@ die_callback (SmcConn smc_conn, SmPointer client_data) * Anything that wants us to go away outside of session management * can use kill(). */ + + /* All of that is true - unless we're a wayland compositor. In which + * case the X server won't go down until we do, so we must die first. + */ + if (meta_is_wayland_compositor ()) + meta_quit (0); } static void @@ -839,14 +846,14 @@ save_state (void) if (mkdir (mutter_dir, 0700) < 0 && errno != EEXIST) { - meta_warning (_("Could not create directory '%s': %s\n"), + meta_warning ("Could not create directory '%s': %s\n", mutter_dir, g_strerror (errno)); } if (mkdir (session_dir, 0700) < 0 && errno != EEXIST) { - meta_warning (_("Could not create directory '%s': %s\n"), + meta_warning ("Could not create directory '%s': %s\n", session_dir, g_strerror (errno)); } @@ -856,7 +863,7 @@ save_state (void) if (outfile == NULL) { - meta_warning (_("Could not open session file '%s' for writing: %s\n"), + meta_warning ("Could not open session file '%s' for writing: %s\n", full_save_file (), g_strerror (errno)); goto out; } @@ -997,12 +1004,12 @@ save_state (void) /* FIXME need a dialog for this */ if (ferror (outfile)) { - meta_warning (_("Error writing session file '%s': %s\n"), + meta_warning ("Error writing session file '%s': %s\n", full_save_file (), g_strerror (errno)); } if (fclose (outfile)) { - meta_warning (_("Error closing session file '%s': %s\n"), + meta_warning ("Error closing session file '%s': %s\n", full_save_file (), g_strerror (errno)); } } @@ -1132,7 +1139,7 @@ load_state (const char *previous_save_file) error: - meta_warning (_("Failed to parse saved session file: %s\n"), + meta_warning ("Failed to parse saved session file: %s\n", error->message); g_error_free (error); @@ -1181,7 +1188,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _(" attribute seen but we already have the session ID")); + " attribute seen but we already have the session ID"); return; } @@ -1194,7 +1201,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "mutter_session"); return; } @@ -1211,7 +1218,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("nested tag")); + "nested tag"); return; } @@ -1269,7 +1276,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "window"); session_info_free (pd->info); pd->info = NULL; @@ -1301,7 +1308,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "window"); session_info_free (pd->info); pd->info = NULL; @@ -1373,7 +1380,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "maximized"); return; } @@ -1433,7 +1440,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute %s on <%s> element"), + "Unknown attribute %s on <%s> element", name, "geometry"); return; } @@ -1453,7 +1460,7 @@ start_element_handler (GMarkupParseContext *context, g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, - _("Unknown element %s"), + "Unknown element %s", element_name); return; } @@ -1809,7 +1816,7 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown) "and will have to be restarted manually next time " "you log in."), "240", - meta_get_display()->active_screen->screen_name, + meta_get_display()->screen->screen_name, NULL, NULL, NULL, None, columns, diff --git a/src/core/session.h b/src/x11/session.h similarity index 100% rename from src/core/session.h rename to src/x11/session.h diff --git a/src/core/testasyncgetprop.c b/src/x11/testasyncgetprop.c similarity index 100% rename from src/core/testasyncgetprop.c rename to src/x11/testasyncgetprop.c diff --git a/src/core/window-props.c b/src/x11/window-props.c similarity index 89% rename from src/core/window-props.c rename to src/x11/window-props.c index 94b12aeba..755225122 100644 --- a/src/core/window-props.c +++ b/src/x11/window-props.c @@ -39,6 +39,8 @@ #include #include "window-props.h" +#include "window-x11.h" +#include "window-x11-private.h" #include #include "xprops.h" #include "frame.h" @@ -229,7 +231,7 @@ reload_net_wm_window_type (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_net_wm_type (window); + meta_window_x11_update_net_wm_type (window); } static void @@ -302,18 +304,17 @@ reload_gtk_frame_extents (MetaWindow *window, } else { - GtkBorder *extents = &window->custom_frame_extents; - - window->has_custom_frame_extents = TRUE; - extents->left = (int)value->v.cardinal_list.cardinals[0]; - extents->right = (int)value->v.cardinal_list.cardinals[1]; - extents->top = (int)value->v.cardinal_list.cardinals[2]; - extents->bottom = (int)value->v.cardinal_list.cardinals[3]; + GtkBorder extents; + extents.left = (int)value->v.cardinal_list.cardinals[0]; + extents.right = (int)value->v.cardinal_list.cardinals[1]; + extents.top = (int)value->v.cardinal_list.cardinals[2]; + extents.bottom = (int)value->v.cardinal_list.cardinals[3]; + meta_window_set_custom_frame_extents (window, &extents); } } else { - window->has_custom_frame_extents = FALSE; + meta_window_set_custom_frame_extents (window, NULL); } if (!initial) @@ -333,7 +334,7 @@ reload_wm_window_role (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_role (window); + meta_window_x11_update_role (window); } static void @@ -346,7 +347,7 @@ reload_net_wm_pid (MetaWindow *window, gulong cardinal = (int) value->v.cardinal; if (cardinal <= 0) - meta_warning (_("Application set a bogus _NET_WM_PID %lu\n"), + meta_warning ("Application set a bogus _NET_WM_PID %lu\n", cardinal); else { @@ -431,9 +432,8 @@ reload_net_wm_user_time_window (MetaWindow *window, /** * set_title_text: * - * Called by set_window_title() and set_icon_title() to set the value of - * @target to @title. It required and @atom is set, it will update the - * appropriate property. + * Called by set_window_title() to set the value of @target to @title. + * If required and @atom is set, it will update the appropriate property. * * Returns: %TRUE if a new title was set. */ @@ -491,28 +491,22 @@ static void set_window_title (MetaWindow *window, const char *title) { - char *str; - + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + + char *new_title = NULL; + gboolean modified = set_title_text (window, - window->using_net_wm_visible_name, + priv->using_net_wm_visible_name, title, window->display->atom__NET_WM_VISIBLE_NAME, - &window->title); - window->using_net_wm_visible_name = modified; + &new_title); + priv->using_net_wm_visible_name = modified; - /* strndup is a hack since GNU libc has broken %.10s */ - str = g_strndup (window->title, 10); - g_free (window->desc); - window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str); - g_free (str); + meta_window_set_title (window, new_title); - if (window->frame) - meta_ui_set_frame_title (window->screen->ui, - window->frame->xwindow, - window->title); - - g_object_notify (G_OBJECT (window), "title"); + g_free (new_title); } static void @@ -520,10 +514,13 @@ reload_net_wm_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + if (value->type != META_PROP_VALUE_INVALID) { set_window_title (window, value->v.str); - window->using_net_wm_name = TRUE; + priv->using_net_wm_name = TRUE; meta_verbose ("Using _NET_WM_NAME for new title of %s: \"%s\"\n", window->desc, window->title); @@ -531,7 +528,7 @@ reload_net_wm_name (MetaWindow *window, else { set_window_title (window, NULL); - window->using_net_wm_name = FALSE; + priv->using_net_wm_name = FALSE; if (!initial) meta_window_reload_property (window, XA_WM_NAME, FALSE); } @@ -542,7 +539,10 @@ reload_wm_name (MetaWindow *window, MetaPropValue *value, gboolean initial) { - if (window->using_net_wm_name) + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + + if (priv->using_net_wm_name) { meta_verbose ("Ignoring WM_NAME \"%s\" as _NET_WM_NAME is set\n", value->v.str); @@ -567,7 +567,7 @@ reload_opaque_region (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_opaque_region_x11 (window); + meta_window_x11_update_opaque_region (window); } static void @@ -613,71 +613,14 @@ reload_mutter_hints (MetaWindow *window, } } -static void -set_icon_title (MetaWindow *window, - const char *title) -{ - gboolean modified = - set_title_text (window, - window->using_net_wm_visible_icon_name, - title, - window->display->atom__NET_WM_VISIBLE_ICON_NAME, - &window->icon_name); - window->using_net_wm_visible_icon_name = modified; -} - -static void -reload_net_wm_icon_name (MetaWindow *window, - MetaPropValue *value, - gboolean initial) -{ - if (value->type != META_PROP_VALUE_INVALID) - { - set_icon_title (window, value->v.str); - window->using_net_wm_icon_name = TRUE; - - meta_verbose ("Using _NET_WM_ICON_NAME for new title of %s: \"%s\"\n", - window->desc, window->title); - } - else - { - set_icon_title (window, NULL); - window->using_net_wm_icon_name = FALSE; - if (!initial) - meta_window_reload_property (window, XA_WM_ICON_NAME, FALSE); - } -} - -static void -reload_wm_icon_name (MetaWindow *window, - MetaPropValue *value, - gboolean initial) -{ - if (window->using_net_wm_icon_name) - { - meta_verbose ("Ignoring WM_ICON_NAME \"%s\" as _NET_WM_ICON_NAME is set\n", - value->v.str); - return; - } - - if (value->type != META_PROP_VALUE_INVALID) - { - set_icon_title (window, value->v.str); - - meta_verbose ("Using WM_ICON_NAME for new title of %s: \"%s\"\n", - window->desc, window->title); - } - else - { - set_icon_title (window, NULL); - } -} - static void reload_net_wm_state (MetaWindow *window, MetaPropValue *value, gboolean initial) { + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = window_x11->priv; + int i; /* We know this is only an initial window creation, @@ -695,9 +638,9 @@ reload_net_wm_state (MetaWindow *window, window->maximized_horizontally = FALSE; window->maximized_vertically = FALSE; window->fullscreen = FALSE; - window->wm_state_modal = FALSE; - window->wm_state_skip_taskbar = FALSE; - window->wm_state_skip_pager = FALSE; + priv->wm_state_modal = FALSE; + priv->wm_state_skip_taskbar = FALSE; + priv->wm_state_skip_pager = FALSE; window->wm_state_above = FALSE; window->wm_state_below = FALSE; window->wm_state_demands_attention = FALSE; @@ -717,11 +660,11 @@ reload_net_wm_state (MetaWindow *window, else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_HIDDEN) window->minimize_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MODAL) - window->wm_state_modal = TRUE; + priv->wm_state_modal = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_TASKBAR) - window->wm_state_skip_taskbar = TRUE; + priv->wm_state_skip_taskbar = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER) - window->wm_state_skip_pager = TRUE; + priv->wm_state_skip_pager = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN) window->fullscreen_after_placement = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE) @@ -739,7 +682,7 @@ reload_net_wm_state (MetaWindow *window, meta_verbose ("Reloaded _NET_WM_STATE for %s\n", window->desc); - meta_window_recalc_window_type (window); + meta_window_x11_recalc_window_type (window); meta_window_recalc_features (window); } @@ -854,7 +797,7 @@ reload_mwm_hints (MetaWindow *window, meta_window_recalc_features (window); - /* We do all this anyhow at the end of meta_window_new() */ + /* We do all this anyhow at the end of meta_window_x11_new() */ if (!window->constructing) { if (window->decorated) @@ -877,23 +820,15 @@ reload_wm_class (MetaWindow *window, MetaPropValue *value, gboolean initial) { - if (window->res_class) - g_free (window->res_class); - if (window->res_name) - g_free (window->res_name); - - window->res_class = NULL; - window->res_name = NULL; - if (value->type != META_PROP_VALUE_INVALID) - { - if (value->v.class_hint.res_name) - window->res_name = g_strdup (value->v.class_hint.res_name); - - if (value->v.class_hint.res_class) - window->res_class = g_strdup (value->v.class_hint.res_class); - - g_object_notify (G_OBJECT (window), "wm-class"); + { + meta_window_set_wm_class (window, + value->v.class_hint.res_class, + value->v.class_hint.res_name); + } + else + { + meta_window_set_wm_class (window, NULL, NULL); } meta_verbose ("Window %s class: '%s' name: '%s'\n", @@ -1427,7 +1362,7 @@ reload_wm_protocols (MetaWindow *window, window->take_focus = FALSE; window->delete_window = FALSE; - window->net_wm_ping = FALSE; + window->can_ping = FALSE; if (value->type == META_PROP_VALUE_INVALID) return; @@ -1443,7 +1378,7 @@ reload_wm_protocols (MetaWindow *window, window->delete_window = TRUE; else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_PING) - window->net_wm_ping = TRUE; + window->can_ping = TRUE; ++i; } @@ -1458,10 +1393,9 @@ reload_wm_hints (MetaWindow *window, gboolean initial) { Window old_group_leader; - gboolean old_urgent; + gboolean urgent; old_group_leader = window->xgroup_leader; - old_urgent = window->wm_hints_urgent; /* Fill in defaults */ window->input = TRUE; @@ -1469,7 +1403,7 @@ reload_wm_hints (MetaWindow *window, window->xgroup_leader = None; window->wm_hints_pixmap = None; window->wm_hints_mask = None; - window->wm_hints_urgent = FALSE; + urgent = FALSE; if (value->type != META_PROP_VALUE_INVALID) { @@ -1491,7 +1425,7 @@ reload_wm_hints (MetaWindow *window, window->wm_hints_mask = hints->icon_mask; if (hints->flags & XUrgencyHint) - window->wm_hints_urgent = TRUE; + urgent = TRUE; meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%lx pixmap: 0x%lx mask: 0x%lx\n", window->input, window->initially_iconic, @@ -1508,20 +1442,7 @@ reload_wm_hints (MetaWindow *window, meta_window_group_leader_changed (window); } - /* - * Do not emit urgency notification on the inital property load - */ - if (!initial && (window->wm_hints_urgent != old_urgent)) - g_object_notify (G_OBJECT (window), "urgent"); - - /* - * Do not emit signal for the initial property load, let the constructor to - * take care of it once the MetaWindow is fully constructed. - * - * Only emit if the property is both changed and set. - */ - if (!initial && window->wm_hints_urgent && !old_urgent) - g_signal_emit_by_name (window->display, "window-marked-urgent", window); + meta_window_set_urgent (window, urgent); meta_icon_cache_property_changed (&window->icon_cache, window->display, @@ -1536,7 +1457,7 @@ reload_transient_for (MetaWindow *window, gboolean initial) { MetaWindow *parent = NULL; - Window transient_for, old_transient_for; + Window transient_for; if (value->type != META_PROP_VALUE_INVALID) { @@ -1545,8 +1466,7 @@ reload_transient_for (MetaWindow *window, parent = meta_display_lookup_x_window (window->display, transient_for); if (!parent) { - meta_warning (_("Invalid WM_TRANSIENT_FOR window 0x%lx specified " - "for %s.\n"), + meta_warning ("Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n", transient_for, window->desc); transient_for = None; } @@ -1556,8 +1476,7 @@ reload_transient_for (MetaWindow *window, { if (parent == window) { - meta_warning (_("WM_TRANSIENT_FOR window 0x%lx for %s " - "would create loop.\n"), + meta_warning ("WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n", transient_for, window->desc); transient_for = None; break; @@ -1573,10 +1492,6 @@ reload_transient_for (MetaWindow *window, if (transient_for == window->xtransient_for) return; - if (meta_window_appears_focused (window) && window->xtransient_for != None) - meta_window_propagate_focus_appearance (window, FALSE); - - old_transient_for = window->xtransient_for; window->xtransient_for = transient_for; window->transient_parent_is_root_window = @@ -1588,46 +1503,14 @@ reload_transient_for (MetaWindow *window, else meta_verbose ("Window %s is not transient\n", window->desc); - /* may now be a dialog */ - meta_window_recalc_window_type (window); - - if (!window->constructing) + if (window->transient_parent_is_root_window || window->xtransient_for == None) + meta_window_set_transient_for (window, NULL); + else { - /* If the window attaches, detaches, or changes attached - * parents, we need to destroy the MetaWindow and let a new one - * be created (which happens as a side effect of - * meta_window_unmanage()). The condition below is correct - * because we know window->xtransient_for has changed. - */ - if (window->attached || meta_window_should_attach_to_parent (window)) - { - guint32 timestamp; - - window->xtransient_for = old_transient_for; - timestamp = meta_display_get_current_time_roundtrip (window->display); - meta_window_unmanage (window, timestamp); - return; - } + parent = meta_display_lookup_x_window (window->display, + window->xtransient_for); + meta_window_set_transient_for (window, parent); } - - /* update stacking constraints */ - if (!window->override_redirect) - meta_stack_update_transient (window->screen->stack, window); - - /* possibly change its group. We treat being a window's transient as - * equivalent to making it your group leader, to work around shortcomings - * in programs such as xmms-- see #328211. - */ - if (window->xtransient_for != None && - window->xgroup_leader != None && - window->xtransient_for != window->xgroup_leader) - meta_window_group_leader_changed (window); - - if (!window->constructing && !window->override_redirect) - meta_window_queue (window, META_QUEUE_MOVE_RESIZE); - - if (meta_window_appears_focused (window) && window->xtransient_for != None) - meta_window_propagate_focus_appearance (window, TRUE); } static void @@ -1791,8 +1674,6 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { XA_WM_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name, TRUE, TRUE }, { display->atom__MUTTER_HINTS, META_PROP_VALUE_TEXT_PROPERTY, reload_mutter_hints, TRUE, TRUE }, { display->atom__NET_WM_OPAQUE_REGION, META_PROP_VALUE_CARDINAL_LIST, reload_opaque_region, TRUE, TRUE }, - { display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8, reload_net_wm_icon_name, TRUE, FALSE }, - { XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE }, { display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE }, { display->atom__NET_STARTUP_ID, META_PROP_VALUE_UTF8, reload_net_startup_id, TRUE, FALSE }, { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER_LIST, reload_update_counter, TRUE, TRUE }, @@ -1819,8 +1700,8 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { display->atom__NET_WM_ICON_GEOMETRY, META_PROP_VALUE_CARDINAL_LIST, reload_icon_geometry, FALSE, FALSE }, { display->atom_WM_CLIENT_LEADER, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE }, { display->atom_SM_CLIENT_ID, META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE }, - { display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, FALSE, FALSE }, - { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, FALSE, TRUE }, + { display->atom_WM_WINDOW_ROLE, META_PROP_VALUE_INVALID, reload_wm_window_role, TRUE, FALSE }, + { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type, TRUE, TRUE }, { display->atom__NET_WM_STRUT, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE }, { display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts, FALSE, FALSE }, { display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL, reload_bypass_compositor, FALSE, FALSE }, diff --git a/src/core/window-props.h b/src/x11/window-props.h similarity index 100% rename from src/core/window-props.h rename to src/x11/window-props.h diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h new file mode 100644 index 000000000..e288439bb --- /dev/null +++ b/src/x11/window-x11-private.h @@ -0,0 +1,57 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington, Anders Carlsson + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * 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, see . + */ + +#include "window-private.h" + +#ifndef META_WINDOW_X11_PRIVATE_H +#define META_WINDOW_X11_PRIVATE_H + +G_BEGIN_DECLS + +typedef struct _MetaWindowX11Private MetaWindowX11Private; + +struct _MetaWindowX11 +{ + MetaWindow parent; + + MetaWindowX11Private *priv; +}; + +struct _MetaWindowX11Private +{ + /* TRUE if the client forced these on */ + guint wm_state_skip_taskbar : 1; + guint wm_state_skip_pager : 1; + + /* Weird "_NET_WM_STATE_MODAL" flag */ + guint wm_state_modal : 1; + + /* Info on which props we got our attributes from */ + guint using_net_wm_name : 1; /* vs. plain wm_name */ + guint using_net_wm_visible_name : 1; /* tracked so we can clear it */ + + Atom type_atom; +}; + +G_END_DECLS + +#endif diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c new file mode 100644 index 000000000..099a55dbd --- /dev/null +++ b/src/x11/window-x11.c @@ -0,0 +1,2528 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington, Anders Carlsson + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * 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, see . + */ + +#include "config.h" + +#include "window-x11.h" +#include "window-x11-private.h" + +#include +#include +#include /* For display->resource_mask */ + +#ifdef HAVE_SHAPE +#include +#endif + +#include +#include "core.h" + +#include +#include +#include +#include + +#include "frame.h" +#include "window-private.h" +#include "window-props.h" +#include "xprops.h" + +struct _MetaWindowX11Class +{ + MetaWindowClass parent_class; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW) + +static void +meta_window_x11_init (MetaWindowX11 *window_x11) +{ + window_x11->priv = meta_window_x11_get_instance_private (window_x11); +} + +static void +send_icccm_message (MetaWindow *window, + Atom atom, + guint32 timestamp) +{ + /* This comment and code are from twm, copyright + * Open Group, Evans & Sutherland, etc. + */ + + /* + * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all + * client messages will have the following form: + * + * event type ClientMessage + * message type _XA_WM_PROTOCOLS + * window tmp->w + * format 32 + * data[0] message atom + * data[1] time stamp + */ + + XClientMessageEvent ev; + + ev.type = ClientMessage; + ev.window = window->xwindow; + ev.message_type = window->display->atom_WM_PROTOCOLS; + ev.format = 32; + ev.data.l[0] = atom; + ev.data.l[1] = timestamp; + + meta_error_trap_push (window->display); + XSendEvent (window->display->xdisplay, + window->xwindow, False, 0, (XEvent*) &ev); + meta_error_trap_pop (window->display); +} + +static Window +read_client_leader (MetaDisplay *display, + Window xwindow) +{ + Window retval = None; + + meta_prop_get_window (display, xwindow, + display->atom_WM_CLIENT_LEADER, + &retval); + + return retval; +} + +typedef struct +{ + Window leader; +} ClientLeaderData; + +static gboolean +find_client_leader_func (MetaWindow *ancestor, + void *data) +{ + ClientLeaderData *d; + + d = data; + + d->leader = read_client_leader (ancestor->display, + ancestor->xwindow); + + /* keep going if no client leader found */ + return d->leader == None; +} + +static void +update_sm_hints (MetaWindow *window) +{ + Window leader; + + window->xclient_leader = None; + window->sm_client_id = NULL; + + /* If not on the current window, we can get the client + * leader from transient parents. If we find a client + * leader, we read the SM_CLIENT_ID from it. + */ + leader = read_client_leader (window->display, window->xwindow); + if (leader == None) + { + ClientLeaderData d; + d.leader = None; + meta_window_foreach_ancestor (window, find_client_leader_func, + &d); + leader = d.leader; + } + + if (leader != None) + { + char *str; + + window->xclient_leader = leader; + + if (meta_prop_get_latin1_string (window->display, leader, + window->display->atom_SM_CLIENT_ID, + &str)) + { + window->sm_client_id = g_strdup (str); + meta_XFree (str); + } + } + else + { + meta_verbose ("Didn't find a client leader for %s\n", window->desc); + + if (!meta_prefs_get_disable_workarounds ()) + { + /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app + * instead of the client leader + */ + char *str; + + str = NULL; + if (meta_prop_get_latin1_string (window->display, window->xwindow, + window->display->atom_SM_CLIENT_ID, + &str)) + { + if (window->sm_client_id == NULL) /* first time through */ + meta_warning ("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n", + window->desc); + + window->sm_client_id = g_strdup (str); + meta_XFree (str); + } + } + } + + meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n", + window->desc, window->xclient_leader, + window->sm_client_id ? window->sm_client_id : "none"); +} + +static void +send_configure_notify (MetaWindow *window) +{ + XEvent event; + + /* from twm */ + + event.type = ConfigureNotify; + event.xconfigure.display = window->display->xdisplay; + event.xconfigure.event = window->xwindow; + event.xconfigure.window = window->xwindow; + event.xconfigure.x = window->rect.x - window->border_width; + event.xconfigure.y = window->rect.y - window->border_width; + if (window->frame) + { + if (window->withdrawn) + { + MetaFrameBorders borders; + /* We reparent the client window and put it to the position + * where the visible top-left of the frame window currently is. + */ + + meta_frame_calc_borders (window->frame, &borders); + + event.xconfigure.x = window->frame->rect.x + borders.invisible.left; + event.xconfigure.y = window->frame->rect.y + borders.invisible.top; + } + else + { + /* Need to be in root window coordinates */ + event.xconfigure.x += window->frame->rect.x; + event.xconfigure.y += window->frame->rect.y; + } + } + event.xconfigure.width = window->rect.width; + event.xconfigure.height = window->rect.height; + event.xconfigure.border_width = window->border_width; /* requested not actual */ + event.xconfigure.above = None; /* FIXME */ + event.xconfigure.override_redirect = False; + + meta_topic (META_DEBUG_GEOMETRY, + "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n", + window->desc, + event.xconfigure.x, event.xconfigure.y, + event.xconfigure.width, event.xconfigure.height); + + meta_error_trap_push (window->display); + XSendEvent (window->display->xdisplay, + window->xwindow, + False, StructureNotifyMask, &event); + meta_error_trap_pop (window->display); +} + +static void +meta_window_x11_manage (MetaWindow *window) +{ + MetaDisplay *display = window->display; + + meta_display_register_x_window (display, &window->xwindow, window); + meta_window_x11_update_shape_region (window); + meta_window_x11_update_input_region (window); + + /* assign the window to its group, or create a new group if needed */ + window->group = NULL; + window->xgroup_leader = None; + meta_window_compute_group (window); + + meta_window_load_initial_properties (window); + + if (!window->override_redirect) + update_sm_hints (window); /* must come after transient_for */ + + meta_window_x11_update_net_wm_type (window); +} + +static void +meta_window_x11_unmanage (MetaWindow *window) +{ + meta_error_trap_push (window->display); + + if (window->withdrawn) + { + /* We need to clean off the window's state so it + * won't be restored if the app maps it again. + */ + meta_verbose ("Cleaning state from window %s\n", window->desc); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_DESKTOP); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_STATE); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS); + meta_window_x11_set_wm_state (window); + } + else + { + /* We need to put WM_STATE so that others will understand it on + * restart. + */ + if (!window->minimized) + meta_window_x11_set_wm_state (window); + + /* If we're unmanaging a window that is not withdrawn, then + * either (a) mutter is exiting, in which case we need to map + * the window so the next WM will know that it's not Withdrawn, + * or (b) we want to create a new MetaWindow to replace the + * current one, which will happen automatically if we re-map + * the X Window. + */ + XMapWindow (window->display->xdisplay, + window->xwindow); + } + + meta_display_unregister_x_window (window->display, window->xwindow); + + /* Put back anything we messed up */ + if (window->border_width != 0) + XSetWindowBorderWidth (window->display->xdisplay, + window->xwindow, + window->border_width); + + /* No save set */ + XRemoveFromSaveSet (window->display->xdisplay, + window->xwindow); + + /* Even though the window is now unmanaged, we can't unselect events. This + * window might be a window from this process, like a GdkMenu, in + * which case it will have pointer events and so forth selected + * for it by GDK. There's no way to disentangle those events from the events + * we've selected. Even for a window from a different X client, + * GDK could also have selected events for it for IPC purposes, so we + * can't unselect in that case either. + * + * Similarly, we can't unselected for events on window->user_time_window. + * It might be our own GDK focus window, or it might be a window that a + * different client is using for multiple different things: + * _NET_WM_USER_TIME_WINDOW and IPC, perhaps. + */ + + if (window->user_time_window != None) + { + meta_display_unregister_x_window (window->display, + window->user_time_window); + window->user_time_window = None; + } + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask); +#endif + + /* The XReparentWindow call in meta_window_destroy_frame() moves the + * window so we need to send a configure notify; see bug 399552. (We + * also do this just in case a window got unmaximized.) + */ + send_configure_notify (window); + + meta_error_trap_pop (window->display); +} + +static void +meta_window_x11_ping (MetaWindow *window, + guint32 serial) +{ + MetaDisplay *display = window->display; + + send_icccm_message (window, display->atom__NET_WM_PING, serial); +} + +static void +meta_window_x11_delete (MetaWindow *window, + guint32 timestamp) +{ + meta_error_trap_push (window->display); + if (window->delete_window) + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Deleting %s with delete_window request\n", + window->desc); + send_icccm_message (window, window->display->atom_WM_DELETE_WINDOW, timestamp); + } + else + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Deleting %s with explicit kill\n", + window->desc); + XKillClient (window->display->xdisplay, window->xwindow); + } + meta_error_trap_pop (window->display); +} + +static void +meta_window_x11_kill (MetaWindow *window) +{ + meta_topic (META_DEBUG_WINDOW_OPS, + "Killing %s brutally\n", + window->desc); + + if (!meta_window_is_remote (window) && + window->net_wm_pid > 0) + { + meta_topic (META_DEBUG_WINDOW_OPS, + "Killing %s with kill()\n", + window->desc); + + if (kill (window->net_wm_pid, 9) < 0) + meta_topic (META_DEBUG_WINDOW_OPS, + "Failed to signal %s: %s\n", + window->desc, strerror (errno)); + } + + meta_topic (META_DEBUG_WINDOW_OPS, + "Disconnecting %s with XKillClient()\n", + window->desc); + + meta_error_trap_push (window->display); + XKillClient (window->display->xdisplay, window->xwindow); + meta_error_trap_pop (window->display); +} + +static void +request_take_focus (MetaWindow *window, + guint32 timestamp) +{ + MetaDisplay *display = window->display; + + meta_topic (META_DEBUG_FOCUS, "WM_TAKE_FOCUS(%s, %u)\n", + window->desc, timestamp); + + send_icccm_message (window, display->atom_WM_TAKE_FOCUS, timestamp); +} + +static void +meta_window_x11_focus (MetaWindow *window, + guint32 timestamp) +{ + /* For output-only or shaded windows, focus the frame. + * This seems to result in the client window getting key events + * though, so I don't know if it's icccm-compliant. + * + * Still, we have to do this or keynav breaks for these windows. + */ + if (window->frame && + (window->shaded || + !(window->input || window->take_focus))) + { + if (window->frame) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing frame of %s\n", window->desc); + meta_display_set_input_focus_window (window->display, + window, + TRUE, + timestamp); + } + } + else + { + if (window->input) + { + meta_topic (META_DEBUG_FOCUS, + "Setting input focus on %s since input = true\n", + window->desc); + meta_display_set_input_focus_window (window->display, + window, + FALSE, + timestamp); + } + + if (window->take_focus) + { + meta_topic (META_DEBUG_FOCUS, + "Sending WM_TAKE_FOCUS to %s since take_focus = true\n", + window->desc); + + if (!window->input) + { + /* The "Globally Active Input" window case, where the window + * doesn't want us to call XSetInputFocus on it, but does + * want us to send a WM_TAKE_FOCUS. + * + * Normally, we want to just leave the focus undisturbed until + * the window respnds to WM_TAKE_FOCUS, but if we're unmanaging + * the current focus window we *need* to move the focus away, so + * we focus the no_focus_window now (and set + * display->focus_window to that) before sending WM_TAKE_FOCUS. + */ + if (window->display->focus_window != NULL && + window->display->focus_window->unmanaging) + meta_display_focus_the_no_focus_window (window->display, + window->screen, + timestamp); + } + + request_take_focus (window, timestamp); + } + } +} + +static void +update_net_frame_extents (MetaWindow *window) +{ + unsigned long data[4]; + MetaFrameBorders borders; + + meta_frame_calc_borders (window->frame, &borders); + /* Left */ + data[0] = borders.visible.left; + /* Right */ + data[1] = borders.visible.right; + /* Top */ + data[2] = borders.visible.top; + /* Bottom */ + data[3] = borders.visible.bottom; + + meta_topic (META_DEBUG_GEOMETRY, + "Setting _NET_FRAME_EXTENTS on managed window 0x%lx " + "to left = %lu, right = %lu, top = %lu, bottom = %lu\n", + window->xwindow, data[0], data[1], data[2], data[3]); + + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, window->xwindow, + window->display->atom__NET_FRAME_EXTENTS, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 4); + meta_error_trap_pop (window->display); +} + +#ifdef HAVE_XSYNC +static gboolean +sync_request_timeout (gpointer data) +{ + MetaWindow *window = data; + + window->sync_request_timeout_id = 0; + + /* We have now waited for more than a second for the + * application to respond to the sync request + */ + window->disable_sync = TRUE; + + /* Reset the wait serial, so we don't continue freezing + * window updates + */ + window->sync_request_wait_serial = 0; + meta_compositor_set_updates_frozen (window->display->compositor, window, + meta_window_updates_are_frozen (window)); + + if (window == window->display->grab_window && + meta_grab_op_is_resizing (window->display->grab_op)) + { + meta_window_update_resize (window, + window->display->grab_last_user_action_was_snap, + window->display->grab_latest_motion_x, + window->display->grab_latest_motion_y, + TRUE); + } + + return FALSE; +} + +static void +send_sync_request (MetaWindow *window) +{ + XClientMessageEvent ev; + gint64 wait_serial; + + /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to + * increase the value, but for the new "extended" style we need to + * pick an even (unfrozen) value sufficiently ahead of the last serial + * that we received from the client; the same code still works + * for the old style. The increment of 240 is specified by the EWMH + * and is (1 second) * (60fps) * (an increment of 4 per frame). + */ + wait_serial = window->sync_request_serial + 240; + + window->sync_request_wait_serial = wait_serial; + + ev.type = ClientMessage; + ev.window = window->xwindow; + ev.message_type = window->display->atom_WM_PROTOCOLS; + ev.format = 32; + ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST; + /* FIXME: meta_display_get_current_time() is bad, but since calls + * come from meta_window_move_resize_internal (which in turn come + * from all over), I'm not sure what we can do to fix it. Do we + * want to use _roundtrip, though? + */ + ev.data.l[1] = meta_display_get_current_time (window->display); + ev.data.l[2] = wait_serial & G_GUINT64_CONSTANT(0xffffffff); + ev.data.l[3] = wait_serial >> 32; + ev.data.l[4] = window->extended_sync_request_counter ? 1 : 0; + + /* We don't need to trap errors here as we are already + * inside an error_trap_push()/pop() pair. + */ + XSendEvent (window->display->xdisplay, + window->xwindow, False, 0, (XEvent*) &ev); + + /* We give the window 1 sec to respond to _NET_WM_SYNC_REQUEST; + * if this time expires, we consider the window unresponsive + * and resize it unsynchonized. + */ + window->sync_request_timeout_id = g_timeout_add (1000, + sync_request_timeout, + window); + + meta_compositor_set_updates_frozen (window->display->compositor, window, + meta_window_updates_are_frozen (window)); +} +#endif + +static void +meta_window_x11_move_resize_internal (MetaWindow *window, + int gravity, + MetaRectangle requested_rect, + MetaRectangle constrained_rect, + MetaMoveResizeFlags flags, + MetaMoveResizeResultFlags *result) +{ + int root_x_nw, root_y_nw; + int w, h; + int client_move_x, client_move_y; + int size_dx, size_dy; + XWindowChanges values; + unsigned int mask; + gboolean need_configure_notify; + MetaFrameBorders borders; + gboolean need_move_client = FALSE; + gboolean need_move_frame = FALSE; + gboolean need_resize_client = FALSE; + gboolean need_resize_frame = FALSE; + gboolean frame_shape_changed = FALSE; + gboolean configure_frame_first; + + gboolean is_configure_request; + + is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0; + + /* meta_window_constrain() might have maximized the window after placement, + * changing the borders. + */ + meta_frame_calc_borders (window->frame, &borders); + + root_x_nw = constrained_rect.x; + root_y_nw = constrained_rect.y; + w = constrained_rect.width; + h = constrained_rect.height; + + if (w != window->rect.width || + h != window->rect.height) + need_resize_client = TRUE; + + window->rect.width = w; + window->rect.height = h; + + if (window->frame) + { + int frame_size_dx, frame_size_dy; + int new_w, new_h; + + new_w = window->rect.width + borders.total.left + borders.total.right; + + if (window->shaded) + new_h = borders.total.top; + else + new_h = window->rect.height + borders.total.top + borders.total.bottom; + + frame_size_dx = new_w - window->frame->rect.width; + frame_size_dy = new_h - window->frame->rect.height; + + need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0); + + window->frame->rect.width = new_w; + window->frame->rect.height = new_h; + + meta_topic (META_DEBUG_GEOMETRY, + "Calculated frame size %dx%d\n", + window->frame->rect.width, + window->frame->rect.height); + } + + /* For nice effect, when growing the window we want to move/resize + * the frame first, when shrinking the window we want to move/resize + * the client first. If we grow one way and shrink the other, + * see which way we're moving "more" + * + * Mail from Owen subject "Suggestion: Gravity and resizing from the left" + * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html + * + * An annoying fact you need to know in this code is that StaticGravity + * does nothing if you _only_ resize or _only_ move the frame; + * it must move _and_ resize, otherwise you get NorthWestGravity + * behavior. The move and resize must actually occur, it is not + * enough to set CWX | CWWidth but pass in the current size/pos. + */ + + if (window->frame) + { + int new_x, new_y; + int frame_pos_dx, frame_pos_dy; + + /* Compute new frame coords */ + new_x = root_x_nw - borders.total.left; + new_y = root_y_nw - borders.total.top; + + frame_pos_dx = new_x - window->frame->rect.x; + frame_pos_dy = new_y - window->frame->rect.y; + + need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0); + + window->frame->rect.x = new_x; + window->frame->rect.y = new_y; + + /* If frame will both move and resize, then StaticGravity + * on the child window will kick in and implicitly move + * the child with respect to the frame. The implicit + * move will keep the child in the same place with + * respect to the root window. If frame only moves + * or only resizes, then the child will just move along + * with the frame. + */ + + /* window->rect.x, window->rect.y are relative to frame, + * remember they are the server coords + */ + + new_x = borders.total.left; + new_y = borders.total.top; + client_move_x = new_x; + client_move_y = new_y; + + if (client_move_x != window->rect.x || + client_move_y != window->rect.y) + need_move_client = TRUE; + + /* This is the final target position, but not necessarily what + * we pass to XConfigureWindow, due to StaticGravity implicit + * movement. + */ + window->rect.x = new_x; + window->rect.y = new_y; + } + else + { + if (root_x_nw != window->rect.x || + root_y_nw != window->rect.y) + need_move_client = TRUE; + + window->rect.x = root_x_nw; + window->rect.y = root_y_nw; + + client_move_x = window->rect.x; + client_move_y = window->rect.y; + } + + /* If frame extents have changed, fill in other frame fields and + change frame's extents property. */ + if (window->frame && + (window->frame->child_x != borders.total.left || + window->frame->child_y != borders.total.top || + window->frame->right_width != borders.total.right || + window->frame->bottom_height != borders.total.bottom)) + { + window->frame->child_x = borders.total.left; + window->frame->child_y = borders.total.top; + window->frame->right_width = borders.total.right; + window->frame->bottom_height = borders.total.bottom; + + update_net_frame_extents (window); + } + + /* See ICCCM 4.1.5 for when to send ConfigureNotify */ + + need_configure_notify = FALSE; + + /* If this is a configure request and we change nothing, then we + * must send configure notify. + */ + if (is_configure_request && + !(need_move_client || need_move_frame || + need_resize_client || need_resize_frame || + window->border_width != 0)) + need_configure_notify = TRUE; + + /* We must send configure notify if we move but don't resize, since + * the client window may not get a real event + */ + if ((need_move_client || need_move_frame) && + !(need_resize_client || need_resize_frame)) + need_configure_notify = TRUE; + + /* MapRequest events with a PPosition or UPosition hint with a frame + * are moved by mutter without resizing; send a configure notify + * in such cases. See #322840. (Note that window->constructing is + * only true iff this call is due to a MapRequest, and when + * PPosition/UPosition hints aren't set, mutter seems to send a + * ConfigureNotify anyway due to the above code.) + */ + if (window->constructing && window->frame && + ((window->size_hints.flags & PPosition) || + (window->size_hints.flags & USPosition))) + need_configure_notify = TRUE; + + /* The rest of this function syncs our new size/pos with X as + * efficiently as possible + */ + + /* Normally, we configure the frame first depending on whether + * we grow the frame more than we shrink. The idea is to avoid + * messing up the window contents by having a temporary situation + * where the frame is smaller than the window. However, if we're + * cooperating with the client to create an atomic frame upate, + * and the window is redirected, then we should always update + * the frame first, since updating the frame will force a new + * backing pixmap to be allocated, and the old backing pixmap + * will be left undisturbed for us to paint to the screen until + * the client finishes redrawing. + */ + if (window->extended_sync_request_counter) + { + configure_frame_first = TRUE; + } + else + { + size_dx = w - window->rect.width; + size_dy = h - window->rect.height; + + configure_frame_first = size_dx + size_dy >= 0; + } + + if (configure_frame_first && window->frame) + frame_shape_changed = meta_frame_sync_to_window (window->frame, + gravity, + need_move_frame, need_resize_frame); + + values.border_width = 0; + values.x = client_move_x; + values.y = client_move_y; + values.width = window->rect.width; + values.height = window->rect.height; + + mask = 0; + if (is_configure_request && window->border_width != 0) + mask |= CWBorderWidth; /* must force to 0 */ + if (need_move_client) + mask |= (CWX | CWY); + if (need_resize_client) + mask |= (CWWidth | CWHeight); + + if (mask != 0) + { + { + int newx, newy; + meta_window_get_position (window, &newx, &newy); + meta_topic (META_DEBUG_GEOMETRY, + "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n", + newx, newy, + window->rect.width, window->rect.height, + mask & CWBorderWidth ? "true" : "false", + need_move_client ? "true" : "false", + need_resize_client ? "true" : "false"); + } + + meta_error_trap_push (window->display); + +#ifdef HAVE_XSYNC + if (window == window->display->grab_window && + meta_grab_op_is_resizing (window->display->grab_op) && + !window->disable_sync && + window->sync_request_counter != None && + window->sync_request_alarm != None && + window->sync_request_timeout_id == 0) + { + send_sync_request (window); + } +#endif + + XConfigureWindow (window->display->xdisplay, + window->xwindow, + mask, + &values); + + meta_error_trap_pop (window->display); + } + + if (!configure_frame_first && window->frame) + frame_shape_changed = meta_frame_sync_to_window (window->frame, + gravity, + need_move_frame, need_resize_frame); + + if (need_configure_notify) + send_configure_notify (window); + + if (frame_shape_changed) + *result |= META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED; + if (need_move_client || need_move_frame) + *result |= META_MOVE_RESIZE_RESULT_MOVED; + if (need_resize_client || need_resize_frame) + *result |= META_MOVE_RESIZE_RESULT_RESIZED; +} + +static void +meta_window_x11_get_default_skip_hints (MetaWindow *window, + gboolean *skip_taskbar_out, + gboolean *skip_pager_out) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + + *skip_taskbar_out = priv->wm_state_skip_taskbar; + *skip_pager_out = priv->wm_state_skip_pager; +} + +static void +meta_window_x11_class_init (MetaWindowX11Class *klass) +{ + MetaWindowClass *window_class = META_WINDOW_CLASS (klass); + + window_class->manage = meta_window_x11_manage; + window_class->unmanage = meta_window_x11_unmanage; + window_class->ping = meta_window_x11_ping; + window_class->delete = meta_window_x11_delete; + window_class->kill = meta_window_x11_kill; + window_class->focus = meta_window_x11_focus; + window_class->move_resize_internal = meta_window_x11_move_resize_internal; + window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints; +} + +void +meta_window_x11_set_net_wm_state (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + int i; + unsigned long data[13]; + + i = 0; + if (window->shaded) + { + data[i] = window->display->atom__NET_WM_STATE_SHADED; + ++i; + } + if (priv->wm_state_modal) + { + data[i] = window->display->atom__NET_WM_STATE_MODAL; + ++i; + } + if (window->skip_pager) + { + data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER; + ++i; + } + if (window->skip_taskbar) + { + data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR; + ++i; + } + if (window->maximized_horizontally) + { + data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ; + ++i; + } + if (window->maximized_vertically) + { + data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT; + ++i; + } + if (window->fullscreen) + { + data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN; + ++i; + } + if (!meta_window_showing_on_its_workspace (window) || window->shaded) + { + data[i] = window->display->atom__NET_WM_STATE_HIDDEN; + ++i; + } + if (window->wm_state_above) + { + data[i] = window->display->atom__NET_WM_STATE_ABOVE; + ++i; + } + if (window->wm_state_below) + { + data[i] = window->display->atom__NET_WM_STATE_BELOW; + ++i; + } + if (window->wm_state_demands_attention) + { + data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION; + ++i; + } + if (window->on_all_workspaces_requested) + { + data[i] = window->display->atom__NET_WM_STATE_STICKY; + ++i; + } + if (meta_window_appears_focused (window)) + { + data[i] = window->display->atom__NET_WM_STATE_FOCUSED; + ++i; + } + + meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); + + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, window->xwindow, + window->display->atom__NET_WM_STATE, + XA_ATOM, + 32, PropModeReplace, (guchar*) data, i); + meta_error_trap_pop (window->display); + + if (window->fullscreen) + { + if (window->fullscreen_monitors[0] >= 0) + { + data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[0]); + data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[1]); + data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[2]); + data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[3]); + + meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS, + XA_CARDINAL, 32, PropModeReplace, + (guchar*) data, 4); + meta_error_trap_pop (window->display); + } + else + { + meta_verbose ("Clearing _NET_WM_FULLSCREEN_MONITORS\n"); + meta_error_trap_push (window->display); + XDeleteProperty (window->display->xdisplay, + window->xwindow, + window->display->atom__NET_WM_FULLSCREEN_MONITORS); + meta_error_trap_pop (window->display); + } + } +} + +void +meta_window_x11_update_net_wm_type (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + int n_atoms; + Atom *atoms; + int i; + + priv->type_atom = None; + n_atoms = 0; + atoms = NULL; + + meta_prop_get_atom_list (window->display, window->xwindow, + window->display->atom__NET_WM_WINDOW_TYPE, + &atoms, &n_atoms); + + i = 0; + while (i < n_atoms) + { + /* We break as soon as we find one we recognize, + * supposed to prefer those near the front of the list + */ + if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG || + atoms[i] == + window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP || + atoms[i] == + window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_COMBO || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DND || + atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) + { + priv->type_atom = atoms[i]; + break; + } + + ++i; + } + + meta_XFree (atoms); + + if (meta_is_verbose ()) + { + char *str; + + str = NULL; + if (priv->type_atom != None) + { + meta_error_trap_push (window->display); + str = XGetAtomName (window->display->xdisplay, priv->type_atom); + meta_error_trap_pop (window->display); + } + + meta_verbose ("Window %s type atom %s\n", window->desc, + str ? str : "(none)"); + + if (str) + meta_XFree (str); + } + + meta_window_x11_recalc_window_type (window); +} + +void +meta_window_x11_update_role (MetaWindow *window) +{ + char *str; + + g_return_if_fail (!window->override_redirect); + + if (window->role) + g_free (window->role); + window->role = NULL; + + if (meta_prop_get_latin1_string (window->display, window->xwindow, + window->display->atom_WM_WINDOW_ROLE, + &str)) + { + window->role = g_strdup (str); + meta_XFree (str); + } + + meta_verbose ("Updated role of %s to '%s'\n", + window->desc, window->role ? window->role : "null"); +} + +static void +meta_window_set_opaque_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->opaque_region, cairo_region_destroy); + + if (region != NULL) + window->opaque_region = cairo_region_reference (region); + + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_x11_update_opaque_region (MetaWindow *window) +{ + cairo_region_t *opaque_region = NULL; + gulong *region = NULL; + int nitems; + + if (meta_prop_get_cardinal_list (window->display, + window->xwindow, + window->display->atom__NET_WM_OPAQUE_REGION, + ®ion, &nitems)) + { + cairo_rectangle_int_t *rects; + int i, rect_index, nrects; + + if (nitems % 4 != 0) + { + meta_verbose ("_NET_WM_OPAQUE_REGION does not have a list of 4-tuples."); + goto out; + } + + /* empty region */ + if (nitems == 0) + goto out; + + nrects = nitems / 4; + + rects = g_new (cairo_rectangle_int_t, nrects); + + rect_index = 0; + i = 0; + while (i < nitems) + { + cairo_rectangle_int_t *rect = &rects[rect_index]; + + rect->x = region[i++]; + rect->y = region[i++]; + rect->width = region[i++]; + rect->height = region[i++]; + + rect_index++; + } + + opaque_region = cairo_region_create_rectangles (rects, nrects); + + g_free (rects); + } + + out: + meta_XFree (region); + + meta_window_set_opaque_region (window, opaque_region); + cairo_region_destroy (opaque_region); +} + +static cairo_region_t * +region_create_from_x_rectangles (const XRectangle *rects, + int n_rects) +{ + int i; + cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects); + + for (i = 0; i < n_rects; i ++) + { + cairo_rects[i].x = rects[i].x; + cairo_rects[i].y = rects[i].y; + cairo_rects[i].width = rects[i].width; + cairo_rects[i].height = rects[i].height; + } + + return cairo_region_create_rectangles (cairo_rects, n_rects); +} + +static void +meta_window_set_input_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->input_region, cairo_region_destroy); + + if (region != NULL) + window->input_region = cairo_region_reference (region); + + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +#if 0 +/* Print out a region; useful for debugging */ +static void +print_region (cairo_region_t *region) +{ + int n_rects; + int i; + + n_rects = cairo_region_num_rectangles (region); + g_print ("["); + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + g_print ("+%d+%dx%dx%d ", + rect.x, rect.y, rect.width, rect.height); + } + g_print ("]\n"); +} +#endif + +void +meta_window_x11_update_input_region (MetaWindow *window) +{ + cairo_region_t *region = NULL; + + /* Decorated windows don't have an input region, because + we don't shape the frame to match the client windows + (so the events are blocked by the frame anyway) + */ + if (window->decorated) + { + if (window->input_region) + meta_window_set_input_region (window, NULL); + return; + } + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + { + /* Translate the set of XShape rectangles that we + * get from the X server to a cairo_region. */ + XRectangle *rects = NULL; + int n_rects, ordering; + + meta_error_trap_push (window->display); + rects = XShapeGetRectangles (window->display->xdisplay, + window->xwindow, + ShapeInput, + &n_rects, + &ordering); + meta_error_trap_pop (window->display); + + /* XXX: The x shape extension doesn't provide a way to only test if an + * input shape has been specified, so we have to query and throw away the + * rectangles. */ + if (rects) + { + if (n_rects > 1 || + (n_rects == 1 && + (rects[0].x != 0 || + rects[0].y != 0 || + rects[0].width != window->rect.width || + rects[0].height != window->rect.height))) + region = region_create_from_x_rectangles (rects, n_rects); + + XFree (rects); + } + } +#endif /* HAVE_SHAPE */ + + if (region != NULL) + { + cairo_rectangle_int_t client_area; + + client_area.x = 0; + client_area.y = 0; + client_area.width = window->rect.width; + client_area.height = window->rect.height; + + /* The shape we get back from the client may have coordinates + * outside of the frame. The X SHAPE Extension requires that + * the overall shape the client provides never exceeds the + * "bounding rectangle" of the window -- the shape that the + * window would have gotten if it was unshaped. In our case, + * this is simply the client area. + */ + cairo_region_intersect_rectangle (region, &client_area); + } + + meta_window_set_input_region (window, region); + cairo_region_destroy (region); +} + +static void +meta_window_set_shape_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->shape_region, cairo_region_destroy); + + if (region != NULL) + window->shape_region = cairo_region_reference (region); + + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_x11_update_shape_region (MetaWindow *window) +{ + cairo_region_t *region = NULL; + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + { + /* Translate the set of XShape rectangles that we + * get from the X server to a cairo_region. */ + XRectangle *rects = NULL; + int n_rects, ordering; + + int x_bounding, y_bounding, x_clip, y_clip; + unsigned w_bounding, h_bounding, w_clip, h_clip; + int bounding_shaped, clip_shaped; + + meta_error_trap_push (window->display); + XShapeQueryExtents (window->display->xdisplay, window->xwindow, + &bounding_shaped, &x_bounding, &y_bounding, + &w_bounding, &h_bounding, + &clip_shaped, &x_clip, &y_clip, + &w_clip, &h_clip); + + if (bounding_shaped) + { + rects = XShapeGetRectangles (window->display->xdisplay, + window->xwindow, + ShapeBounding, + &n_rects, + &ordering); + } + meta_error_trap_pop (window->display); + + if (rects) + { + region = region_create_from_x_rectangles (rects, n_rects); + XFree (rects); + } + } +#endif /* HAVE_SHAPE */ + + if (region != NULL) + { + cairo_rectangle_int_t client_area; + + client_area.x = 0; + client_area.y = 0; + client_area.width = window->rect.width; + client_area.height = window->rect.height; + + /* The shape we get back from the client may have coordinates + * outside of the frame. The X SHAPE Extension requires that + * the overall shape the client provides never exceeds the + * "bounding rectangle" of the window -- the shape that the + * window would have gotten if it was unshaped. In our case, + * this is simply the client area. + */ + cairo_region_intersect_rectangle (region, &client_area); + } + + meta_window_set_shape_region (window, region); + cairo_region_destroy (region); +} + +/* Generally meta_window_same_application() is a better idea + * of "sameness", since it handles the case where multiple apps + * want to look like the same app or the same app wants to look + * like multiple apps, but in the case of workarounds for legacy + * applications (which likely aren't setting the group properly + * anyways), it may be desirable to check this as well. + */ +static gboolean +meta_window_same_client (MetaWindow *window, + MetaWindow *other_window) +{ + int resource_mask = window->display->xdisplay->resource_mask; + + return ((window->xwindow & ~resource_mask) == + (other_window->xwindow & ~resource_mask)); +} + +gboolean +meta_window_x11_configure_request (MetaWindow *window, + XEvent *event) +{ + /* Note that x, y is the corner of the window border, + * and width, height is the size of the window inside + * its border, but that we always deny border requests + * and give windows a border of 0. But we save the + * requested border here. + */ + if (event->xconfigurerequest.value_mask & CWBorderWidth) + window->border_width = event->xconfigurerequest.border_width; + + meta_window_move_resize_request(window, + event->xconfigurerequest.value_mask, + window->size_hints.win_gravity, + event->xconfigurerequest.x, + event->xconfigurerequest.y, + event->xconfigurerequest.width, + event->xconfigurerequest.height); + + /* Handle stacking. We only handle raises/lowers, mostly because + * stack.c really can't deal with anything else. I guess we'll fix + * that if a client turns up that really requires it. Only a very + * few clients even require the raise/lower (and in fact all client + * attempts to deal with stacking order are essentially broken, + * since they have no idea what other clients are involved or how + * the stack looks). + * + * I'm pretty sure no interesting client uses TopIf, BottomIf, or + * Opposite anyway, so the only possible missing thing is + * Above/Below with a sibling set. For now we just pretend there's + * never a sibling set and always do the full raise/lower instead of + * the raise-just-above/below-sibling. + */ + if (event->xconfigurerequest.value_mask & CWStackMode) + { + MetaWindow *active_window; + active_window = window->display->focus_window; + if (meta_prefs_get_disable_workarounds ()) + { + meta_topic (META_DEBUG_STACK, + "%s sent an xconfigure stacking request; this is " + "broken behavior and the request is being ignored.\n", + window->desc); + } + else if (active_window && + !meta_window_same_application (window, active_window) && + !meta_window_same_client (window, active_window) && + XSERVER_TIME_IS_BEFORE (window->net_wm_user_time, + active_window->net_wm_user_time)) + { + meta_topic (META_DEBUG_STACK, + "Ignoring xconfigure stacking request from %s (with " + "user_time %u); currently active application is %s (with " + "user_time %u).\n", + window->desc, + window->net_wm_user_time, + active_window->desc, + active_window->net_wm_user_time); + if (event->xconfigurerequest.detail == Above) + meta_window_set_demands_attention(window); + } + else + { + switch (event->xconfigurerequest.detail) + { + case Above: + meta_window_raise (window); + break; + case Below: + meta_window_lower (window); + break; + case TopIf: + case BottomIf: + case Opposite: + break; + } + } + } + + return TRUE; +} + +static gboolean +process_property_notify (MetaWindow *window, + XPropertyEvent *event) +{ + Window xid = window->xwindow; + + if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */ + { + char *property_name = XGetAtomName (window->display->xdisplay, + event->atom); + + meta_verbose ("Property notify on %s for %s\n", + window->desc, property_name); + XFree (property_name); + } + + if (event->atom == window->display->atom__NET_WM_USER_TIME && + window->user_time_window) + { + xid = window->user_time_window; + } + + meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE); + + return TRUE; +} + +gboolean +meta_window_x11_property_notify (MetaWindow *window, + XEvent *event) +{ + return process_property_notify (window, &event->xproperty); +} + +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 +#define _NET_WM_MOVERESIZE_CANCEL 11 + +static int +query_pressed_buttons (MetaWindow *window) +{ + ClutterModifierType mods; + int button = 0; + + meta_cursor_tracker_get_pointer (window->screen->cursor_tracker, + NULL, NULL, &mods); + + if (mods & CLUTTER_BUTTON1_MASK) + button |= 1 << 1; + if (mods & CLUTTER_BUTTON2_MASK) + button |= 1 << 2; + if (mods & CLUTTER_BUTTON3_MASK) + button |= 1 << 3; + + return button; +} + +gboolean +meta_window_x11_client_message (MetaWindow *window, + XEvent *event) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + MetaDisplay *display; + + display = window->display; + + if (window->override_redirect) + { + /* Don't warn here: we could warn on any of the messages below, + * but we might also receive other client messages that are + * part of protocols we don't know anything about. So, silently + * ignoring is simplest. + */ + return FALSE; + } + + if (event->xclient.message_type == + display->atom__NET_CLOSE_WINDOW) + { + guint32 timestamp; + + if (event->xclient.data.l[0] != 0) + timestamp = event->xclient.data.l[0]; + else + { + meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without " + "a timestamp! This means some buggy (outdated) " + "application is on the loose!\n", + window->desc); + timestamp = meta_display_get_current_time (window->display); + } + + meta_window_delete (window, timestamp); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_DESKTOP) + { + int space; + MetaWorkspace *workspace; + + space = event->xclient.data.l[0]; + + meta_verbose ("Request to move %s to workspace %d\n", + window->desc, space); + + workspace = + meta_screen_get_workspace_by_index (window->screen, + space); + + if (workspace) + { + if (window->on_all_workspaces_requested) + meta_window_unstick (window); + meta_window_change_workspace (window, workspace); + } + else if (space == (int) 0xFFFFFFFF) + { + meta_window_stick (window); + } + else + { + meta_verbose ("No such workspace %d for screen\n", space); + } + + meta_verbose ("Window %s now on_all_workspaces = %d\n", + window->desc, window->on_all_workspaces); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_STATE) + { + gulong action; + Atom first; + Atom second; + + action = event->xclient.data.l[0]; + first = event->xclient.data.l[1]; + second = event->xclient.data.l[2]; + + if (meta_is_verbose ()) + { + char *str1; + char *str2; + + meta_error_trap_push (display); + str1 = XGetAtomName (display->xdisplay, first); + if (meta_error_trap_pop_with_return (display) != Success) + str1 = NULL; + + meta_error_trap_push (display); + str2 = XGetAtomName (display->xdisplay, second); + if (meta_error_trap_pop_with_return (display) != Success) + str2 = NULL; + + meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n", + action, + str1 ? str1 : "(unknown)", + str2 ? str2 : "(unknown)"); + + meta_XFree (str1); + meta_XFree (str2); + } + + if (first == display->atom__NET_WM_STATE_SHADED || + second == display->atom__NET_WM_STATE_SHADED) + { + gboolean shade; + guint32 timestamp; + + /* Stupid protocol has no timestamp; of course, shading + * sucks anyway so who really cares that we're forced to do + * a roundtrip here? + */ + timestamp = meta_display_get_current_time_roundtrip (window->display); + + shade = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && !window->shaded)); + if (shade && window->has_shade_func) + meta_window_shade (window, timestamp); + else + meta_window_unshade (window, timestamp); + } + + if (first == display->atom__NET_WM_STATE_FULLSCREEN || + second == display->atom__NET_WM_STATE_FULLSCREEN) + { + gboolean make_fullscreen; + + make_fullscreen = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && !window->fullscreen)); + if (make_fullscreen && window->has_fullscreen_func) + meta_window_make_fullscreen (window); + else + meta_window_unmake_fullscreen (window); + } + + if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || + second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || + first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || + second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) + { + gboolean max; + MetaMaximizeFlags directions = 0; + + max = (action == _NET_WM_STATE_ADD || + (action == _NET_WM_STATE_TOGGLE && + !window->maximized_horizontally)); + + if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ || + second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ) + directions |= META_MAXIMIZE_HORIZONTAL; + + if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT || + second == display->atom__NET_WM_STATE_MAXIMIZED_VERT) + directions |= META_MAXIMIZE_VERTICAL; + + if (max && window->has_maximize_func) + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + meta_window_maximize (window, directions); + } + else + { + if (meta_prefs_get_raise_on_click ()) + meta_window_raise (window); + meta_window_unmaximize (window, directions); + } + } + + if (first == display->atom__NET_WM_STATE_MODAL || + second == display->atom__NET_WM_STATE_MODAL) + { + priv->wm_state_modal = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !priv->wm_state_modal); + + meta_window_x11_recalc_window_type (window); + meta_window_queue(window, META_QUEUE_MOVE_RESIZE); + } + + if (first == display->atom__NET_WM_STATE_SKIP_PAGER || + second == display->atom__NET_WM_STATE_SKIP_PAGER) + { + priv->wm_state_skip_pager = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->skip_pager); + + meta_window_recalc_features (window); + meta_window_x11_set_net_wm_state (window); + } + + if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR || + second == display->atom__NET_WM_STATE_SKIP_TASKBAR) + { + priv->wm_state_skip_taskbar = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar); + + meta_window_recalc_features (window); + meta_window_x11_set_net_wm_state (window); + } + + if (first == display->atom__NET_WM_STATE_ABOVE || + second == display->atom__NET_WM_STATE_ABOVE) + { + if ((action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) + meta_window_make_above (window); + else + meta_window_unmake_above (window); + } + + if (first == display->atom__NET_WM_STATE_BELOW || + second == display->atom__NET_WM_STATE_BELOW) + { + window->wm_state_below = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below); + + meta_window_update_layer (window); + meta_window_x11_set_net_wm_state (window); + } + + if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION || + second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION) + { + if ((action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention)) + meta_window_set_demands_attention (window); + else + meta_window_unset_demands_attention (window); + } + + if (first == display->atom__NET_WM_STATE_STICKY || + second == display->atom__NET_WM_STATE_STICKY) + { + if ((action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->on_all_workspaces_requested)) + meta_window_stick (window); + else + meta_window_unstick (window); + } + + return TRUE; + } + else if (event->xclient.message_type == + display->atom_WM_CHANGE_STATE) + { + meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n", + event->xclient.data.l[0]); + if (event->xclient.data.l[0] == IconicState && + window->has_minimize_func) + meta_window_minimize (window); + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_MOVERESIZE) + { + int x_root; + int y_root; + int action; + MetaGrabOp op; + int button; + guint32 timestamp; + + /* _NET_WM_MOVERESIZE messages are almost certainly going to come from + * clients when users click on the fake "frame" that the client has, + * thus we should also treat such messages as though it were a + * "frame action". + */ + gboolean const frame_action = TRUE; + + x_root = event->xclient.data.l[0]; + y_root = event->xclient.data.l[1]; + action = event->xclient.data.l[2]; + button = event->xclient.data.l[3]; + + /* FIXME: What a braindead protocol; no timestamp?!? */ + timestamp = meta_display_get_current_time_roundtrip (display); + meta_topic (META_DEBUG_WINDOW_OPS, + "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n", + window->desc, + x_root, y_root, action, button); + + op = META_GRAB_OP_NONE; + switch (action) + { + case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: + op = META_GRAB_OP_RESIZING_NW; + break; + case _NET_WM_MOVERESIZE_SIZE_TOP: + op = META_GRAB_OP_RESIZING_N; + break; + case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT: + op = META_GRAB_OP_RESIZING_NE; + break; + case _NET_WM_MOVERESIZE_SIZE_RIGHT: + op = META_GRAB_OP_RESIZING_E; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT: + op = META_GRAB_OP_RESIZING_SE; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOM: + op = META_GRAB_OP_RESIZING_S; + break; + case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: + op = META_GRAB_OP_RESIZING_SW; + break; + case _NET_WM_MOVERESIZE_SIZE_LEFT: + op = META_GRAB_OP_RESIZING_W; + break; + case _NET_WM_MOVERESIZE_MOVE: + op = META_GRAB_OP_MOVING; + break; + case _NET_WM_MOVERESIZE_SIZE_KEYBOARD: + op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN; + break; + case _NET_WM_MOVERESIZE_MOVE_KEYBOARD: + op = META_GRAB_OP_KEYBOARD_MOVING; + break; + case _NET_WM_MOVERESIZE_CANCEL: + /* handled below */ + break; + default: + break; + } + + if (action == _NET_WM_MOVERESIZE_CANCEL) + { + meta_display_end_grab_op (window->display, timestamp); + } + else if (op != META_GRAB_OP_NONE && + ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) || + (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN))) + { + meta_window_begin_grab_op (window, op, frame_action, timestamp); + } + else if (op != META_GRAB_OP_NONE && + ((window->has_move_func && op == META_GRAB_OP_MOVING) || + (window->has_resize_func && + (op != META_GRAB_OP_MOVING && + op != META_GRAB_OP_KEYBOARD_MOVING)))) + { + int button_mask; + + meta_topic (META_DEBUG_WINDOW_OPS, + "Beginning move/resize with button = %d\n", button); + meta_display_begin_grab_op (window->display, + window->screen, + window, + op, + FALSE, + frame_action, + button, 0, + timestamp, + x_root, + y_root); + + button_mask = query_pressed_buttons (window); + + if (button == 0) + { + /* + * the button SHOULD already be included in the message + */ + if ((button_mask & (1 << 1)) != 0) + button = 1; + else if ((button_mask & (1 << 2)) != 0) + button = 2; + else if ((button_mask & (1 << 3)) != 0) + button = 3; + + if (button != 0) + window->display->grab_button = button; + else + meta_display_end_grab_op (window->display, + timestamp); + } + else + { + /* There is a potential race here. If the user presses and + * releases their mouse button very fast, it's possible for + * both the ButtonPress and ButtonRelease to be sent to the + * client before it can get a chance to send _NET_WM_MOVERESIZE + * to us. When that happens, we'll become stuck in a grab + * state, as we haven't received a ButtonRelease to cancel the + * grab. + * + * We can solve this by querying after we take the explicit + * pointer grab -- if the button isn't pressed, we cancel the + * drag immediately. + */ + + if ((button_mask & (1 << button)) == 0) + meta_display_end_grab_op (window->display, timestamp); + } + } + + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_MOVERESIZE_WINDOW) + { + int gravity; + guint value_mask; + + gravity = (event->xclient.data.l[0] & 0xff); + value_mask = (event->xclient.data.l[0] & 0xf00) >> 8; + /* source = (event->xclient.data.l[0] & 0xf000) >> 12; */ + + if (gravity == 0) + gravity = window->size_hints.win_gravity; + + meta_window_move_resize_request(window, + value_mask, + gravity, + event->xclient.data.l[1], /* x */ + event->xclient.data.l[2], /* y */ + event->xclient.data.l[3], /* width */ + event->xclient.data.l[4]); /* height */ + } + else if (event->xclient.message_type == + display->atom__NET_ACTIVE_WINDOW) + { + MetaClientType source_indication; + guint32 timestamp; + + meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating\n", + window->desc); + + source_indication = event->xclient.data.l[0]; + timestamp = event->xclient.data.l[1]; + + if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED) + source_indication = META_CLIENT_TYPE_UNKNOWN; + + if (timestamp == 0) + { + /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */ + meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a " + "timestamp of 0 for %s\n", + window->desc); + timestamp = meta_display_get_current_time (display); + } + + meta_window_activate_full (window, timestamp, source_indication, NULL); + return TRUE; + } + else if (event->xclient.message_type == + display->atom__NET_WM_FULLSCREEN_MONITORS) + { + gulong top, bottom, left, right; + + meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", + window->desc); + + top = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[0]); + bottom = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[1]); + left = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[2]); + right = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[3]); + /* source_indication = event->xclient.data.l[4]; */ + + meta_window_update_fullscreen_monitors (window, top, bottom, left, right); + } + + return FALSE; +} + +static void +set_wm_state_on_xwindow (MetaDisplay *display, + Window xwindow, + int state) +{ + unsigned long data[2]; + + /* Mutter doesn't use icon windows, so data[1] should be None + * according to the ICCCM 2.0 Section 4.1.3.1. + */ + data[0] = state; + data[1] = None; + + meta_error_trap_push (display); + XChangeProperty (display->xdisplay, xwindow, + display->atom_WM_STATE, + display->atom_WM_STATE, + 32, PropModeReplace, (guchar*) data, 2); + meta_error_trap_pop (display); +} + +void +meta_window_x11_set_wm_state (MetaWindow *window) +{ + int state; + + if (window->withdrawn) + state = WithdrawnState; + else if (window->iconic) + state = IconicState; + else + state = NormalState; + + set_wm_state_on_xwindow (window->display, window->xwindow, state); +} + +/* The MUTTER_WM_CLASS_FILTER environment variable is designed for + * performance and regression testing environments where we want to do + * tests with only a limited set of windows and ignore all other windows + * + * When it is set to a comma separated list of WM_CLASS class names, all + * windows not matching the list will be ignored. + * + * Returns TRUE if window has been filtered out and should be ignored. + */ +static gboolean +maybe_filter_xwindow (MetaDisplay *display, + Window xwindow, + gboolean must_be_viewable, + XWindowAttributes *attrs) +{ + static char **filter_wm_classes = NULL; + static gboolean initialized = FALSE; + XClassHint class_hint; + gboolean filtered; + Status success; + int i; + + if (!initialized) + { + const char *filter_string = g_getenv ("MUTTER_WM_CLASS_FILTER"); + if (filter_string) + filter_wm_classes = g_strsplit (filter_string, ",", -1); + initialized = TRUE; + } + + if (!filter_wm_classes || !filter_wm_classes[0]) + return FALSE; + + filtered = TRUE; + + meta_error_trap_push (display); + success = XGetClassHint (display->xdisplay, xwindow, &class_hint); + + if (success) + { + for (i = 0; filter_wm_classes[i]; i++) + { + if (strcmp (class_hint.res_class, filter_wm_classes[i]) == 0) + { + filtered = FALSE; + break; + } + } + + XFree (class_hint.res_name); + XFree (class_hint.res_class); + } + + if (filtered) + { + /* We want to try and get the window managed by the next WM that come along, + * so we need to make sure that windows that are requested to be mapped while + * Mutter is running (!must_be_viewable), or windows already viewable at startup + * get a non-withdrawn WM_STATE property. Previously unmapped windows are left + * with whatever WM_STATE property they had. + */ + if (!must_be_viewable || attrs->map_state == IsViewable) + { + gulong old_state; + + if (!meta_prop_get_cardinal_with_atom_type (display, xwindow, + display->atom_WM_STATE, + display->atom_WM_STATE, + &old_state)) + old_state = WithdrawnState; + + if (old_state == WithdrawnState) + set_wm_state_on_xwindow (display, xwindow, NormalState); + } + + /* Make sure filtered windows are hidden from view */ + XUnmapWindow (display->xdisplay, xwindow); + } + + meta_error_trap_pop (display); + + return filtered; +} + +static gboolean +is_our_xwindow (MetaDisplay *display, + MetaScreen *screen, + Window xwindow, + XWindowAttributes *attrs) +{ + if (xwindow == screen->no_focus_window) + return TRUE; + + if (xwindow == screen->wm_sn_selection_window) + return TRUE; + + if (xwindow == screen->wm_cm_selection_window) + return TRUE; + + if (xwindow == screen->guard_window) + return TRUE; + + if (xwindow == XCompositeGetOverlayWindow (display->xdisplay, screen->xroot)) + return TRUE; + + /* Any windows created via meta_create_offscreen_window */ + if (attrs->override_redirect && attrs->x == -100 && attrs->y == -100 && attrs->width == 1 && attrs->height == 1) + return TRUE; + + return FALSE; +} + +#ifdef WITH_VERBOSE_MODE +static const char* +wm_state_to_string (int state) +{ + switch (state) + { + case NormalState: + return "NormalState"; + case IconicState: + return "IconicState"; + case WithdrawnState: + return "WithdrawnState"; + } + + return "Unknown"; +} +#endif + +MetaWindow * +meta_window_x11_new (MetaDisplay *display, + Window xwindow, + gboolean must_be_viewable, + MetaCompEffect effect) +{ + MetaScreen *screen = display->screen; + XWindowAttributes attrs; + gulong existing_wm_state; + MetaWindow *window = NULL; + gulong event_mask; + + meta_verbose ("Attempting to manage 0x%lx\n", xwindow); + + if (meta_display_xwindow_is_a_no_focus_window (display, xwindow)) + { + meta_verbose ("Not managing no_focus_window 0x%lx\n", + xwindow); + return NULL; + } + + meta_error_trap_push (display); /* Push a trap over all of window + * creation, to reduce XSync() calls + */ + /* + * This function executes without any server grabs held. This means that + * the window could have already gone away, or could go away at any point, + * so we must be careful with X error handling. + */ + + if (!XGetWindowAttributes (display->xdisplay, xwindow, &attrs)) + { + meta_verbose ("Failed to get attributes for window 0x%lx\n", + xwindow); + goto error; + } + + if (attrs.root != screen->xroot) + { + meta_verbose ("Not on our screen\n"); + goto error; + } + + if (is_our_xwindow (display, screen, xwindow, &attrs)) + { + meta_verbose ("Not managing our own windows\n"); + goto error; + } + + if (maybe_filter_xwindow (display, xwindow, must_be_viewable, &attrs)) + { + meta_verbose ("Not managing filtered window\n"); + goto error; + } + + existing_wm_state = WithdrawnState; + if (must_be_viewable && attrs.map_state != IsViewable) + { + /* Only manage if WM_STATE is IconicState or NormalState */ + gulong state; + + /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */ + if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow, + display->atom_WM_STATE, + display->atom_WM_STATE, + &state) && + (state == IconicState || state == NormalState))) + { + meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow); + goto error; + } + + existing_wm_state = state; + meta_verbose ("WM_STATE of %lx = %s\n", xwindow, + wm_state_to_string (existing_wm_state)); + } + + meta_error_trap_push (display); + + /* + * XAddToSaveSet can only be called on windows created by a different + * client. with Mutter we want to be able to create manageable windows + * from within the process (such as a dummy desktop window). As we do not + * want this call failing to prevent the window from being managed, we + * call this before creating the return-checked error trap. + */ + XAddToSaveSet (display->xdisplay, xwindow); + + meta_error_trap_push (display); + + event_mask = PropertyChangeMask; + if (attrs.override_redirect) + event_mask |= StructureNotifyMask; + + /* If the window is from this client (a menu, say) we need to augment + * the event mask, not replace it. For windows from other clients, + * attrs.your_event_mask will be empty at this point. + */ + XSelectInput (display->xdisplay, xwindow, attrs.your_event_mask | event_mask); + + { + unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; + XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits }; + + meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask); + + XISetMask (mask.mask, XI_Enter); + XISetMask (mask.mask, XI_Leave); + XISetMask (mask.mask, XI_FocusIn); + XISetMask (mask.mask, XI_FocusOut); + + XISelectEvents (display->xdisplay, xwindow, &mask, 1); + } + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (display)) + XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); +#endif + + /* Get rid of any borders */ + if (attrs.border_width != 0) + XSetWindowBorderWidth (display->xdisplay, xwindow, 0); + + /* Get rid of weird gravities */ + if (attrs.win_gravity != NorthWestGravity) + { + XSetWindowAttributes set_attrs; + + set_attrs.win_gravity = NorthWestGravity; + + XChangeWindowAttributes (display->xdisplay, + xwindow, + CWWinGravity, + &set_attrs); + } + + if (meta_error_trap_pop_with_return (display) != Success) + { + meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", + xwindow); + goto error; + } + + window = _meta_window_shared_new (display, + screen, + META_WINDOW_CLIENT_TYPE_X11, + NULL, + xwindow, + existing_wm_state, + effect, + &attrs); + meta_window_set_surface_mapped (window, TRUE); + + meta_error_trap_pop (display); /* pop the XSync()-reducing trap */ + return window; + +error: + meta_error_trap_pop (display); + return NULL; +} + +void +meta_window_x11_recalc_window_type (MetaWindow *window) +{ + MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); + MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); + MetaWindowType type; + + if (priv->type_atom != None) + { + if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP) + type = META_WINDOW_DESKTOP; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK) + type = META_WINDOW_DOCK; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR) + type = META_WINDOW_TOOLBAR; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU) + type = META_WINDOW_MENU; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY) + type = META_WINDOW_UTILITY; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH) + type = META_WINDOW_SPLASHSCREEN; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG) + type = META_WINDOW_DIALOG; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL) + type = META_WINDOW_NORMAL; + /* The below are *typically* override-redirect windows, but the spec does + * not disallow using them for managed windows. + */ + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU) + type = META_WINDOW_DROPDOWN_MENU; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU) + type = META_WINDOW_POPUP_MENU; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP) + type = META_WINDOW_TOOLTIP; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION) + type = META_WINDOW_NOTIFICATION; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO) + type = META_WINDOW_COMBO; + else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND) + type = META_WINDOW_DND; + else + { + char *atom_name; + + /* + * Fallback on a normal type, and print warning. Don't abort. + */ + type = META_WINDOW_NORMAL; + + meta_error_trap_push (window->display); + atom_name = XGetAtomName (window->display->xdisplay, + priv->type_atom); + meta_error_trap_pop (window->display); + + meta_warning ("Unrecognized type atom [%s] set for %s \n", + atom_name ? atom_name : "unknown", + window->desc); + + if (atom_name) + XFree (atom_name); + } + } + else if (window->transient_for != NULL) + { + type = META_WINDOW_DIALOG; + } + else + { + type = META_WINDOW_NORMAL; + } + + if (type == META_WINDOW_DIALOG && priv->wm_state_modal) + type = META_WINDOW_MODAL_DIALOG; + + /* We don't want to allow override-redirect windows to have decorated-window + * types since that's just confusing. + */ + if (window->override_redirect) + { + switch (window->type) + { + /* Decorated types */ + case META_WINDOW_NORMAL: + case META_WINDOW_DIALOG: + case META_WINDOW_MODAL_DIALOG: + case META_WINDOW_MENU: + case META_WINDOW_UTILITY: + type = META_WINDOW_OVERRIDE_OTHER; + break; + /* Undecorated types, normally not override-redirect */ + case META_WINDOW_DESKTOP: + case META_WINDOW_DOCK: + case META_WINDOW_TOOLBAR: + case META_WINDOW_SPLASHSCREEN: + /* Undecorated types, normally override-redirect types */ + case META_WINDOW_DROPDOWN_MENU: + case META_WINDOW_POPUP_MENU: + case META_WINDOW_TOOLTIP: + case META_WINDOW_NOTIFICATION: + case META_WINDOW_COMBO: + case META_WINDOW_DND: + /* To complete enum */ + case META_WINDOW_OVERRIDE_OTHER: + break; + } + } + + meta_verbose ("Calculated type %u for %s, old type %u\n", + type, window->desc, type); + meta_window_set_type (window, type); +} + +/** + * meta_window_x11_configure_notify: (skip) + * @window: a #MetaWindow + * @event: a #XConfigureEvent + * + * This is used to notify us of an unrequested configuration + * (only applicable to override redirect windows) + */ +void +meta_window_x11_configure_notify (MetaWindow *window, + XConfigureEvent *event) +{ + g_assert (window->override_redirect); + g_assert (window->frame == NULL); + + window->rect.x = event->x; + window->rect.y = event->y; + window->rect.width = event->width; + window->rect.height = event->height; + meta_window_update_monitor (window); + + /* Whether an override-redirect window is considered fullscreen depends + * on its geometry. + */ + if (window->override_redirect) + meta_screen_queue_check_fullscreen (window->screen); + + if (!event->override_redirect && !event->send_event) + meta_warning ("Unhandled change of windows override redirect status\n"); + + meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE); +} diff --git a/src/x11/window-x11.h b/src/x11/window-x11.h new file mode 100644 index 000000000..29d95b0f5 --- /dev/null +++ b/src/x11/window-x11.h @@ -0,0 +1,64 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2002 Red Hat, Inc. + * Copyright (C) 2003, 2004 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * + * 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, see . + */ + +#ifndef META_WINDOW_X11_H +#define META_WINDOW_X11_H + +#include +#include + +G_BEGIN_DECLS + +#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type()) +#define META_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_X11, MetaWindowX11)) +#define META_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_X11, MetaWindowX11Class)) +#define META_IS_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_X11)) +#define META_IS_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_X11)) +#define META_WINDOW_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_X11, MetaWindowX11Class)) + +GType meta_window_x11_get_type (void); + +typedef struct _MetaWindowX11 MetaWindowX11; +typedef struct _MetaWindowX11Class MetaWindowX11Class; + +void meta_window_x11_set_net_wm_state (MetaWindow *window); +void meta_window_x11_set_wm_state (MetaWindow *window); + +void meta_window_x11_update_role (MetaWindow *window); +void meta_window_x11_update_net_wm_type (MetaWindow *window); +void meta_window_x11_update_opaque_region (MetaWindow *window); +void meta_window_x11_update_input_region (MetaWindow *window); +void meta_window_x11_update_shape_region (MetaWindow *window); + +void meta_window_x11_recalc_window_type (MetaWindow *window); + +gboolean meta_window_x11_configure_request (MetaWindow *window, + XEvent *event); +gboolean meta_window_x11_property_notify (MetaWindow *window, + XEvent *event); +gboolean meta_window_x11_client_message (MetaWindow *window, + XEvent *event); + +void meta_window_x11_configure_notify (MetaWindow *window, + XConfigureEvent *event); + +#endif diff --git a/src/core/xprops.c b/src/x11/xprops.c similarity index 93% rename from src/core/xprops.c rename to src/x11/xprops.c index 5c96319da..44c1113ca 100644 --- a/src/core/xprops.c +++ b/src/x11/xprops.c @@ -150,7 +150,7 @@ validate_or_free_results (GetPropertyResults *results, if (res_name == NULL) res_name = "unknown"; - meta_warning (_("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n"), + meta_warning ("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n", results->xwindow, prop_name ? prop_name : "(bad atom)", expected_name ? expected_name : "(bad atom)", @@ -191,7 +191,7 @@ get_property (MetaDisplay *display, results->bytes_after = 0; results->format = 0; - meta_error_trap_push_with_return (display); + meta_error_trap_push (display); if (XGetWindowProperty (display->xdisplay, xwindow, xatom, 0, G_MAXLONG, False, req_type, &results->type, &results->format, @@ -406,7 +406,7 @@ utf8_string_from_results (GetPropertyResults *results, char *name; name = XGetAtomName (results->display->xdisplay, results->xatom); - meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8\n"), + meta_warning ("Property %s on window 0x%lx contained invalid UTF-8\n", name, results->xwindow); meta_XFree (name); XFree (results->prop); @@ -489,7 +489,7 @@ utf8_list_from_results (GetPropertyResults *results, meta_error_trap_push (results->display); name = XGetAtomName (results->display->xdisplay, results->xatom); meta_error_trap_pop (results->display); - meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n"), + meta_warning ("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n", name, results->xwindow, i); meta_XFree (name); meta_XFree (results->prop); @@ -534,6 +534,81 @@ meta_prop_get_utf8_list (MetaDisplay *display, return utf8_list_from_results (&results, str_p, n_str_p); } +/* this one freakishly returns g_malloc memory */ +static gboolean +latin1_list_from_results (GetPropertyResults *results, + char ***str_p, + int *n_str_p) +{ + int i; + int n_strings; + char **retval; + const char *p; + + *str_p = NULL; + *n_str_p = 0; + + if (!validate_or_free_results (results, 8, XA_STRING, FALSE)) + return FALSE; + + /* I'm not sure this is right, but I'm guessing the + * property is nul-separated + */ + i = 0; + n_strings = 0; + while (i < (int) results->n_items) + { + if (results->prop[i] == '\0') + ++n_strings; + ++i; + } + + if (results->prop[results->n_items - 1] != '\0') + ++n_strings; + + /* we're guaranteed that results->prop has a nul on the end + * by XGetWindowProperty + */ + + retval = g_new0 (char*, n_strings + 1); + + p = (char *)results->prop; + i = 0; + while (i < n_strings) + { + retval[i] = g_strdup (p); + + p = p + strlen (p) + 1; + ++i; + } + + *str_p = retval; + *n_str_p = i; + + meta_XFree (results->prop); + results->prop = NULL; + + return TRUE; +} + +gboolean +meta_prop_get_latin1_list (MetaDisplay *display, + Window xwindow, + Atom xatom, + char ***str_p, + int *n_str_p) +{ + GetPropertyResults results; + + *str_p = NULL; + + if (!get_property (display, xwindow, xatom, + XA_STRING, &results)) + return FALSE; + + return latin1_list_from_results (&results, str_p, n_str_p); +} + void meta_prop_set_utf8_string_hint (MetaDisplay *display, Window xwindow, @@ -661,6 +736,29 @@ meta_prop_get_cardinal_with_atom_type (MetaDisplay *display, return cardinal_with_atom_type_from_results (&results, prop_type, cardinal_p); } +static char * +text_property_to_utf8 (Display *xdisplay, + const XTextProperty *prop) +{ + char *ret = NULL; + char **local_list = NULL; + int count = 0; + int res; + + res = XmbTextPropertyToTextList (xdisplay, prop, &local_list, &count); + if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound) + goto out; + + if (count == 0) + goto out; + + ret = g_strdup (local_list[0]); + + out: + meta_XFree (local_list); + return ret; +} + static gboolean text_property_from_results (GetPropertyResults *results, char **utf8_str_p) @@ -668,15 +766,14 @@ text_property_from_results (GetPropertyResults *results, XTextProperty tp; *utf8_str_p = NULL; - + tp.value = results->prop; results->prop = NULL; tp.encoding = results->type; tp.format = results->format; tp.nitems = results->n_items; - *utf8_str_p = meta_text_property_to_utf8 (results->display->xdisplay, - &tp); + *utf8_str_p = text_property_to_utf8 (results->display->xdisplay, &tp); if (tp.value != NULL) XFree (tp.value); diff --git a/src/core/xprops.h b/src/x11/xprops.h similarity index 96% rename from src/core/xprops.h rename to src/x11/xprops.h index cad7a1f4a..241557ff7 100644 --- a/src/core/xprops.h +++ b/src/x11/xprops.h @@ -100,6 +100,11 @@ gboolean meta_prop_get_utf8_list (MetaDisplay *display, Atom xatom, char ***str_p, int *n_str_p); +gboolean meta_prop_get_latin1_list (MetaDisplay *display, + Window xwindow, + Atom xatom, + char ***str_p, + int *n_str_p); void meta_prop_set_utf8_string_hint (MetaDisplay *display, Window xwindow, diff --git a/stamp.h.in b/stamp.h.in deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/tokentest/Makefile b/test/tokentest/Makefile deleted file mode 100644 index 010fd604d..000000000 --- a/test/tokentest/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# completely hacked-up makefile, proceed at your own risk, etc - -default: - @echo "Try 'make tp' or 'make glib'" - -tp: tokentest.c - gcc `pkg-config --cflags --libs glib-2.0 gdk-2.0 atk` -DMUTTER_DATADIR=\"/usr/share/mutter\" -I../.. -I../../src -I../../src/include tokentest.c ../../src/ui/theme.c ../../src/ui/gradient.c -o tp diff --git a/test/tokentest/README b/test/tokentest/README deleted file mode 100644 index c98dbe4ad..000000000 --- a/test/tokentest/README +++ /dev/null @@ -1,19 +0,0 @@ -Tokeniser test -============== -This directory contains a set of tools for checking the behaviour -of the tokeniser for Metacity theme files. - -tokentest.ini contains a list of all expressions retrieved from -all theme files on art.gnome.org, and mappings to what the tokenising -should be, in a separate representation. get-tokens.py produces the -template version of this; it will produce a file with no expected -values. - -tokentest.c will either check that a tokeniser behaves according to -tokentest.ini, or, if it finds a file, is empty it will print the -values that the tokeniser it's using is producing. - -The makefile is a hacky attempt at letting you compile either against -Metacity's existing tokeniser or one which uses GLib's "scanner". - -This code may or may not eventually end up in the automated test suite. \ No newline at end of file diff --git a/test/tokentest/get-tokens.py b/test/tokentest/get-tokens.py deleted file mode 100644 index 42a8844e6..000000000 --- a/test/tokentest/get-tokens.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/python -# Copyright (C) 2008 Thomas Thurman -# -# 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, see . - - -import os -import xml.sax - -standard = ['x', 'y', 'width', 'height'] - -expressions = { - 'line': ['x1', 'x2', 'y1', 'y2'], - 'rectangle': standard, - 'arc': standard, - 'clip': standard, - 'gradient': standard, - 'image': standard, - 'gtk_arrow': standard, - 'gtk_box': standard, - 'gtk_vline': standard, - 'icon': standard, - 'title': standard, - 'include': standard, - 'tile': ['x', 'y', 'width', 'height', - 'tile_xoffset', 'tile_yoffset', - 'tile_width', 'tile_height'], -} - -all_themes = '../../../all-themes/' - -result = {} - -class themeparser: - def __init__(self, name): - self.filename = name - - def processingInstruction(self): - pass - - def characters(self, what): - pass - - def setDocumentLocator(self, where): - pass - - def startDocument(self): - pass - - def startElement(self, name, attrs): - if expressions.has_key(name): - for attr in expressions[name]: - if attrs.has_key(attr): - expression = attrs[attr] - if not result.has_key(expression): result[expression] = {} - result[expression][self.filename] = 1 - - def endElement(self, name): - pass # print "end element" - - def endDocument(self): - pass - -def maybe_parse(themename, filename): - if os.access(all_themes+filename, os.F_OK): - parser = themeparser(themename) - xml.sax.parse(all_themes+filename, parser) - -for theme in os.listdir(all_themes): - maybe_parse(theme, theme+'/metacity-1/metacity-theme-1.xml') - maybe_parse(theme, theme+'/metacity-theme-1.xml') - -print '[tokentest0]' - -for expr in sorted(result.keys()): - print "# %s" % (', '.join(sorted(result[expr]))) - print "%s=REQ" % (expr) - print diff --git a/test/tokentest/tokentest.c b/test/tokentest/tokentest.c deleted file mode 100644 index 107d9ee4a..000000000 --- a/test/tokentest/tokentest.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * tokentest.c - test for Metacity's tokeniser - * - * Copyright (C) 2008 Thomas Thurman - * - * 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, see . - */ - -/* Still under heavy development. */ -/* Especially: FIXME: GErrors need checking! */ - -#include -#include -#include -#include -#include -#include - -#define TOKENTEST_GROUP "tokentest0" - -/************************/ -/* Dummy functions which are just here to keep the linker happy */ - -MetaTheme* meta_theme_load (const char *theme_name, - GError **err) { - /* dummy */ - return NULL; -} - -void -meta_bug(const char *format, ...) -{ - /* dummy */ -} - -void -meta_warning(const char *format, ...) -{ - /* dummy */ -} - -GType -gtk_widget_get_type (void) -{ - /* dummy */ -} - -GType -gtk_object_get_type (void) -{ - /* dummy */ -} - -void gtk_paint_arrow (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - GtkArrowType arrow_type, - gboolean fill, - gint x, - gint y, - gint width, - gint height) -{ - /* dummy */ -} - -void gtk_paint_vline (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint y1_, - gint y2_, - gint x) -{ - /* dummy */ -} -void gtk_paint_box (GtkStyle *style, - GdkWindow *window, - GtkStateType state_type, - GtkShadowType shadow_type, - GdkRectangle *area, - GtkWidget *widget, - const gchar *detail, - gint x, - gint y, - gint width, - gint height) -{ - /* dummy */ -} - -GtkIconTheme *gtk_icon_theme_get_default (void) -{ - /* dummy */ -} - -GdkPixbuf * gtk_icon_theme_load_icon (GtkIconTheme *icon_theme, - const gchar *icon_name, - gint size, - GtkIconLookupFlags flags, - GError **error) -{ - /* dummy */ -} - -MetaRectangle meta_rect (int x, int y, int width, int height) -{ - /* dummy */ -} - -void -meta_topic_real (MetaDebugTopic topic, - const char *format, - ...) -{ - /* dummy */ -} - - -/*********************************/ - -GString *draw_spec_to_string(MetaDrawSpec *spec) -{ - GString *result; - int i; - - if (spec == NULL) - return g_string_new ("NONE"); - - result = g_string_new (""); - - if (spec->constant) - { - g_string_append_printf (result, "{%d==}", spec->value); - } - - for (i=0; in_tokens; i++) - { - PosToken t = spec->tokens[i]; - - switch (t.type) - { - case POS_TOKEN_INT: - g_string_append_printf (result, "(int %d)", t.d.i.val); - break; - - case POS_TOKEN_DOUBLE: - g_string_append_printf (result, "(double %g)", t.d.d.val); - break; - - case POS_TOKEN_OPERATOR: - - switch (t.d.o.op) { - case POS_OP_NONE: - g_string_append (result, "(no-op)"); - break; - - case POS_OP_ADD: - g_string_append (result, "(add)"); - break; - - case POS_OP_SUBTRACT: - g_string_append (result, "(subtract)"); - break; - - case POS_OP_MULTIPLY: - g_string_append (result, "(multiply)"); - break; - - case POS_OP_DIVIDE: - g_string_append (result, "(divide)"); - break; - - case POS_OP_MOD: - g_string_append (result, "(mod)"); - break; - - case POS_OP_MAX: - g_string_append (result, "(max)"); - break; - - case POS_OP_MIN: - g_string_append (result, "(min)"); - break; - - default: - g_string_append_printf (result, "(op %d)", t.d.o.op); - } - - break; - - case POS_TOKEN_VARIABLE: - g_string_append_printf (result, "(str %s)", t.d.v.name); - break; - - case POS_TOKEN_OPEN_PAREN: - g_string_append (result, "( "); - break; - - case POS_TOKEN_CLOSE_PAREN: - g_string_append (result, " )"); - break; - - default: - g_string_append_printf (result, "(strange %d)", t.type); - } - - } - - return result; -} - -GKeyFile *keys; - -void -load_keys () -{ - GError* err = NULL; - gchar** keys_of_file; - gchar** cursor; - gboolean ever_printed_header = FALSE; - gint passes = 0, fails = 0; - - keys = g_key_file_new (); - - g_key_file_load_from_file (keys, - "tokentest.ini", - G_KEY_FILE_KEEP_COMMENTS, - &err); - - keys_of_file = g_key_file_get_keys (keys, - TOKENTEST_GROUP, - NULL, - &err); - - cursor = keys_of_file; - - while (*cursor) - { - gchar *desideratum = g_key_file_get_value (keys, - TOKENTEST_GROUP, - *cursor, - &err); - MetaTheme *dummy = meta_theme_new (); - MetaDrawSpec *spec; - GString *str; - - spec = meta_draw_spec_new (dummy, *cursor, &err); - - str = draw_spec_to_string (spec); - - if (strcmp ("REQ", desideratum)==0) { - gchar *comment = g_key_file_get_comment (keys, TOKENTEST_GROUP, *cursor, &err); - - if (!ever_printed_header) { - g_print ("[%s]\n", TOKENTEST_GROUP); - ever_printed_header = TRUE; - } - - g_print ("\n#%s%s=%s\n", comment? comment: "", *cursor, str->str); - g_free (comment); - } else if (strcmp (str->str, desideratum)==0) { - g_print("PASS: %s\n", *cursor); - passes++; - } else { - g_warning ("FAIL: %s, wanted %s, got %s\n", - *cursor, desideratum, str->str); - fails++; - } - - meta_theme_free (dummy); - g_string_free (str, TRUE); - g_free (desideratum); - - cursor++; - } - - g_strfreev (keys_of_file); - - g_print("\n# Passes: %d. Fails: %d.\n", passes, fails); -} - -int -main () -{ - load_keys (); -} diff --git a/test/tokentest/tokentest.ini b/test/tokentest/tokentest.ini deleted file mode 100644 index edfc58764..000000000 --- a/test/tokentest/tokentest.ini +++ /dev/null @@ -1,1873 +0,0 @@ -# Copyright (C) 2008 Thomas Thurman and others -# Generated using the "get-tokens.py" script from all themes on -# art.gnome.org, which are all released under DFSG-compatible -# licences. -# -# 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, see . - -########################### - -[tokentest0] - -########################### - -# Some very simple examples -width+height=(str width)(add)(str height) -width*height=(str width)(multiply)(str height) -width `min` height=(str width)(min)(str height) - -########################### - -# Strings which can't possibly be well-formed -~~~=NONE - -########################### - -# Strings auto-generated by the original tokeniser -# from art.gnome.org themes (the theme name is given -# in a comment) - -# Amiga, AmigaRelief, pOS -(((height - title_height) / 2) `max` 0)=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) ) - -# Amiga, AmigaRelief, pOS -(((height - title_height) / 2) `max` 0)=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) ) - -# Aquarius, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -(((height - title_height) / 2) `max` 0) + 1=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(add)(int 1) - -# Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, River, SmoothGNOME, TangoDance, c2 -(((height - title_height) / 2) `max` 0) + 2=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(add)(int 2) - -# Clearlooks-RedExit -(((height - title_height) / 2) `max` 0) - 1=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(subtract)(int 1) - -# Gilouche, GiloucheIM -(((height - title_height) / 2) `max` 0)-1=( ( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) )(subtract)(int 1) - -# Gilouche, GiloucheIM -((3 `max` (width-title_width)) / 2)=( ( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) ) - -# Gilouche, GiloucheIM -((3 `max` (width-title_width)) / 2)+1=( ( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) )(add)(int 1) - -# Gilouche, GiloucheIM -((3 `max` (width-title_width)) / 2)-1=( ( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) )(subtract)(int 1) - -# Esco -((height - (ButtonIPad + 1) * 2) * 0.4) * 0.67=( ( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) )(multiply)(double 0.67) - -# Atlanta, Bright, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Gilouche, GiloucheIM, Metabox, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Sandwish, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -((height - title_height) / 2) `max` 0=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) - -# Simple, Tetelestai-Modern -((height - title_height) / 2) `max` 0 + 1=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0)(add)(int 1) - -# Outcrop -((height - title_height) / 2) `max` 0 +2=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0)(add)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2)=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2) + 1=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2) + 2=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((height-(Bmin`max`height-Bpad*2))/2) - 1=( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Clearbox-in, Clearbox-out, Simplebox -((height-title_height)/2) `max` 0=( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(max)(int 0) - -# Crux -((left_width + ButtonWidth + IconTitleSpacing + title_width + CenterTitlePieceWidth * height / 22) `min` (width - 3 * ButtonWidth - right_width)) + 1=( ( (str left_width)(add)(str ButtonWidth)(add)(str IconTitleSpacing)(add)(str title_width)(add)(str CenterTitlePieceWidth)(multiply)(str height)(divide)(int 22) )(min)( (str width)(subtract)(int 3)(multiply)(str ButtonWidth)(subtract)(str right_width) ) )(add)(int 1) - -# Crux -((left_width + ButtonWidth + IconTitleSpacing + title_width) `min` (width - object_width * height / 22 - right_width - 3 * ButtonWidth)) + 1=( ( (str left_width)(add)(str ButtonWidth)(add)(str IconTitleSpacing)(add)(str title_width) )(min)( (str width)(subtract)(str object_width)(multiply)(str height)(divide)(int 22)(subtract)(str right_width)(subtract)(int 3)(multiply)(str ButtonWidth) ) )(add)(int 1) - -# Crux, Sandwish -((title_width + height / 2 + 32)) + 1=( ( (str title_width)(add)(str height)(divide)(int 2)(add)(int 32) ) )(add)(int 1) - -# Crux, Sandwish -((title_width + height / 2 - 4) `min` (width - object_width - 26))=( ( (str title_width)(add)(str height)(divide)(int 2)(subtract)(int 4) )(min)( (str width)(subtract)(str object_width)(subtract)(int 26) ) ) - -# Crux, Sandwish -((title_width + height / 2) `min` (width - object_width - 6)) + 1=( ( (str title_width)(add)(str height)(divide)(int 2) )(min)( (str width)(subtract)(str object_width)(subtract)(int 6) ) )(add)(int 1) - -# Sandwish -((title_width - 4) `min` (title_width/2-10))=( ( (str title_width)(subtract)(int 4) )(min)( (str title_width)(divide)(int 2)(subtract)(int 10) ) ) - -# Sandwish -((title_width) `min` (title_width/2-10))=( ( (str title_width) )(min)( (str title_width)(divide)(int 2)(subtract)(int 10) ) ) - -# Sandwish -((title_width) `min` (width)) + 1=( ( (str title_width) )(min)( (str width) ) )(add)(int 1) - -# Sandwish -((title_width)) + 1=( ( (str title_width) ) )(add)(int 1) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -((width - title_width) / 2)=( ( (str width)(subtract)(str title_width) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((width-(Bmin`max`height-Bpad*2))/2)=( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((width-(Bmin`max`height-Bpad*2))/2) + 1=( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -((width-(Bmin`max`height-Bpad*2))/2) + 2=( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(add)(int 2) - -# Sloth -((width-title_width)/2) `max` 40=( ( (str width)(subtract)(str title_width) )(divide)(int 2) )(max)(int 40) - -# Atlanta, EasyListening, Metabox, Outcrop -(0 `max` (width-title_width)) / 2=( (int 0)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) - -# Outcrop -(0 `max` (width-title_width)) / 2 +1=( (int 0)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 1) - -# EasyListening -(0 `max` (width-title_width)) / 2 - 1=( (int 0)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(subtract)(int 1) - -# Atlanta, Bright, Metabox, Outcrop -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2) - -# Atlanta, Metabox, Outcrop, Simple -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2 + mini_icon_width + IconTitleSpacing=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2)(add)(str mini_icon_width)(add)(str IconTitleSpacing) - -# Simple -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2 + mini_icon_width + IconTitleSpacing + 1=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2)(add)(str mini_icon_width)(add)(str IconTitleSpacing)(add)(int 1) - -# Outcrop -(0 `max` (width-title_width-mini_icon_width-IconTitleSpacing)) / 2 + mini_icon_width + IconTitleSpacing +1=( (int 0)(max)( (str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) ) )(divide)(int 2)(add)(str mini_icon_width)(add)(str IconTitleSpacing)(add)(int 1) - -# Aquarius, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -(3 `max` (width-title_width)) / 2=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2) - -# Aquarius, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, River, SmoothGNOME, TangoDance, c2 -(3 `max` (width-title_width)) / 2 + 1=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 1) - -# Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks2-Squared, Clearlooks2-Squared-Berries, River, SmoothGNOME, TangoDance, c2 -(3 `max` (width-title_width)) / 2 + 2=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 2) - -# Bright -(3 `max` (width-title_width)) / 2+2=( (int 3)(max)( (str width)(subtract)(str title_width) ) )(divide)(int 2)(add)(int 2) - -# Sandwish -(4+title_width+20) `min` (title_width-30)=( (int 4)(add)(str title_width)(add)(int 20) )(min)( (str title_width)(subtract)(int 30) ) - -# Sandwish -(4+title_width+291-34) `min` (width-4)=( (int 4)(add)(str title_width)(add)(int 291)(subtract)(int 34) )(min)( (str width)(subtract)(int 4) ) - -# Chiro, c2 -(ButtonIPad+1) + 1=( (str ButtonIPad)(add)(int 1) )(add)(int 1) - -# Esco -(height - (ButtonIPad + 1) * 2) * 0.4=( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) - -# Esco -(height - (ButtonIPad + 1) * 2) * 0.4 + 1=( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4)(add)(int 1) - -# Esco -(height - (ButtonIPad + 1) * 2) * 0.67=( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.67) - -# AgingGorilla, Crux, Gorilla, Sandwish, Soft Squares, Tactile, ThinMC -(height - object_height) / 2=( (str height)(subtract)(str object_height) )(divide)(int 2) - -# Graphite -(height - title_height + 2) / 2=( (str height)(subtract)(str title_height)(add)(int 2) )(divide)(int 2) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Firey 1.0, Firey Dark, Graphite, Maemo, Redmond, Silverado, Soft Squares, Tactile, ThinMC -(height - title_height) / 2=( (str height)(subtract)(str title_height) )(divide)(int 2) - -# Agata, Black, Firey 1.0, Firey Dark -(height - title_height) / 2 + 1=( (str height)(subtract)(str title_height) )(divide)(int 2)(add)(int 1) - -# Agata -(height - title_height) / 2 - 1=( (str height)(subtract)(str title_height) )(divide)(int 2)(subtract)(int 1) - -# Maemo -(height - title_height) / 2+1=( (str height)(subtract)(str title_height) )(divide)(int 2)(add)(int 1) - -# sky, sky-blue -(height - title_height) / 5=( (str height)(subtract)(str title_height) )(divide)(int 5) - -# Esco -(height / 2) - (mini_icon_height / 2)=( (str height)(divide)(int 2) )(subtract)( (str mini_icon_height)(divide)(int 2) ) - -# Esco -(height / 2) - (mini_icon_height / 2) - 2=( (str height)(divide)(int 2) )(subtract)( (str mini_icon_height)(divide)(int 2) )(subtract)(int 2) - -# Esco -(height / 2) - (title_height / 2)=( (str height)(divide)(int 2) )(subtract)( (str title_height)(divide)(int 2) ) - -# Esco -(height / 2) - (title_height / 2) - 1=( (str height)(divide)(int 2) )(subtract)( (str title_height)(divide)(int 2) )(subtract)(int 1) - -# Esco -(height / 2) - (title_height / 2) - 2=( (str height)(divide)(int 2) )(subtract)( (str title_height)(divide)(int 2) )(subtract)(int 2) - -# Atlanta -(height-(ArrowSpacer*2)) `max` MinArrowSize=( (str height)(subtract)( (str ArrowSpacer)(multiply)(int 2) ) )(max)(str MinArrowSize) - -# Outcrop -(height-1)-(title_height /1.5)=( (str height)(subtract)(int 1) )(subtract)( (str title_height)(divide)(double 1.5) ) - -# Clearlooks-2.0-blend, Gilouche, GiloucheIM, TangoDance -(height-10)/2=( (str height)(subtract)(int 10) )(divide)(int 2) - -# Atlanta, Bright, Metabox, Outcrop -(height-mini_icon_height) / 2=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2) - -# Aquarius, Clearlooks-RedExit, Firey 1.0, Firey Dark, Gilouche, GiloucheIM -(height-mini_icon_height)/2=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2) - -# Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance -(height-mini_icon_height)/2+1=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2)(add)(int 1) - -# Vista Basic -(height-mini_icon_height)/2-1=( (str height)(subtract)(str mini_icon_height) )(divide)(int 2)(subtract)(int 1) - -# boxx -(height-object_height)/2=( (str height)(subtract)(str object_height) )(divide)(int 2) - -# boxx -(height-object_height)/2+1=( (str height)(subtract)(str object_height) )(divide)(int 2)(add)(int 1) - -# 4DWM, MWM -(height-title_height)/2=( (str height)(subtract)(str title_height) )(divide)(int 2) - -# Tetelestai-Modern -(height/2)-3=( (str height)(divide)(int 2) )(subtract)(int 3) - -# Tetelestai-Modern -(height/2)-4=( (str height)(divide)(int 2) )(subtract)(int 4) - -# Sloth -(height/2)-5=( (str height)(divide)(int 2) )(subtract)(int 5) - -# Crux -(left_width + ButtonWidth + IconTitleSpacing + title_width) `min` (width - right_width - 3 * ButtonWidth - CenterTitlePieceWidth * height / 22 - 3)=( (str left_width)(add)(str ButtonWidth)(add)(str IconTitleSpacing)(add)(str title_width) )(min)( (str width)(subtract)(str right_width)(subtract)(int 3)(multiply)(str ButtonWidth)(subtract)(str CenterTitlePieceWidth)(multiply)(str height)(divide)(int 22)(subtract)(int 3) ) - -# Chiro, c2 -(title_height + 6)/2=( (str title_height)(add)(int 6) )(divide)(int 2) - -# Chiro, c2 -(title_height + 6)/2+1=( (str title_height)(add)(int 6) )(divide)(int 2)(add)(int 1) - -# Esco -(width - (ButtonIPad + 1) * 2) * 0.67=( (str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.67) - -# AgingGorilla, Crux, Gorilla, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Sandwish, Soft Squares, Tactile, ThinMC -(width - object_width) / 2=( (str width)(subtract)(str object_width) )(divide)(int 2) - -# Crux, Sandwish -(width - title_width - height / 2 - 32 - 7) `max` 0=( (str width)(subtract)(str title_width)(subtract)(str height)(divide)(int 2)(subtract)(int 32)(subtract)(int 7) )(max)(int 0) - -# Crux -(width - title_width - left_width - ButtonWidth - IconTitleSpacing - CenterTitlePieceWidth * height / 22 - right_width) `max` (3 * ButtonWidth)=( (str width)(subtract)(str title_width)(subtract)(str left_width)(subtract)(str ButtonWidth)(subtract)(str IconTitleSpacing)(subtract)(str CenterTitlePieceWidth)(multiply)(str height)(divide)(int 22)(subtract)(str right_width) )(max)( (int 3)(multiply)(str ButtonWidth) ) - -# Sandwish -(width - title_width - left_width - ButtonWidth - IconTitleSpacing - right_width) `max` (3 * ButtonWidth)=( (str width)(subtract)(str title_width)(subtract)(str left_width)(subtract)(str ButtonWidth)(subtract)(str IconTitleSpacing)(subtract)(str right_width) )(max)( (int 3)(multiply)(str ButtonWidth) ) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Firey 1.0, Firey Dark, Soft Squares, Tactile -(width - title_width) / 2=( (str width)(subtract)(str title_width) )(divide)(int 2) - -# Agata, Black -(width - title_width) / 2 +1=( (str width)(subtract)(str title_width) )(divide)(int 2)(add)(int 1) - -# Agata -(width - title_width) / 2 -1=( (str width)(subtract)(str title_width) )(divide)(int 2)(subtract)(int 1) - -# Sandwish -(width -183) `max` 0=( (str width)(subtract)(int 183) )(max)(int 0) - -# Graphite -(width -title_width + 2) / 2=( (str width)(subtract)(str title_width)(add)(int 2) )(divide)(int 2) - -# Graphite -(width -title_width) / 2=( (str width)(subtract)(str title_width) )(divide)(int 2) - -# Carved2 -(width / 2) + 3=( (str width)(divide)(int 2) )(add)(int 3) - -# Carved2 -(width / 2) - 3=( (str width)(divide)(int 2) )(subtract)(int 3) - -# Atlanta -(width-(ArrowSpacer*2)) `max` MinArrowSize=( (str width)(subtract)( (str ArrowSpacer)(multiply)(int 2) ) )(max)(str MinArrowSize) - -# Clearlooks-2.0-blend, Gilouche, GiloucheIM, TangoDance -(width-10)/2=( (str width)(subtract)(int 10) )(divide)(int 2) - -# boxx -(width-18-title_width-18)/18*18+9=( (str width)(subtract)(int 18)(subtract)(str title_width)(subtract)(int 18) )(divide)(int 18)(multiply)(int 18)(add)(int 9) - -# Metabox -(width-ButtonIPad)/2+1=( (str width)(subtract)(str ButtonIPad) )(divide)(int 2)(add)(int 1) - -# Clearlooks-RedExit, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Mista -(width-mini_icon_width)/2=( (str width)(subtract)(str mini_icon_width) )(divide)(int 2) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance, Vista Basic -(width-mini_icon_width)/2-2=( (str width)(subtract)(str mini_icon_width) )(divide)(int 2)(subtract)(int 2) - -# MWM -(width-title_width)/2 `max` 10=( (str width)(subtract)(str title_width) )(divide)(int 2)(max)(int 10) - -# 4DWM, Agata, AgingGorilla, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Black, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Correcamins, Crux, EasyListening, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, Graphite, MWM, Maemo, MetaGrip, Metabox, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, Sloth , SmoothGNOME, Soft Squares, Tactile, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, W2k, boxx, c2, pOS, sky, sky-blue -0={0==}(int 0) - -# Esco -0 - 25={-25==}(int 0)(subtract)(int 25) - -# Clearbox-look-2 -0 `max` ((height-title_height)/2)=(int 0)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) ) - -# Bentham -0 `max` ((width-title_width)) / 2 - height=(int 0)(max)( ( (str width)(subtract)(str title_width) ) )(divide)(int 2)(subtract)(str height) - -# Vista Basic -0+1={1==}(int 0)(add)(int 1) - -# Vista Basic -0+2={2==}(int 0)(add)(int 2) - -# Amiga -0.125 * height=(double 0.125)(multiply)(str height) - -# Amiga -0.125 * width=(double 0.125)(multiply)(str width) - -# Amiga, AmigaRelief -0.25 * height=(double 0.25)(multiply)(str height) - -# Amiga, AmigaRelief -0.25 * width=(double 0.25)(multiply)(str width) - -# AmigaRelief -0.3 * height=(double 0.3)(multiply)(str height) - -# AmigaRelief -0.3 * width=(double 0.3)(multiply)(str width) - -# Amiga, AmigaRelief -0.35 * height=(double 0.35)(multiply)(str height) - -# Amiga, AmigaRelief -0.35 * width=(double 0.35)(multiply)(str width) - -# Amiga, AmigaRelief -0.375 * height=(double 0.375)(multiply)(str height) - -# Amiga, AmigaRelief -0.375 * width=(double 0.375)(multiply)(str width) - -# Amiga, AmigaRelief -0.4 * height=(double 0.4)(multiply)(str height) - -# Amiga, AmigaRelief -0.4 * width=(double 0.4)(multiply)(str width) - -# Amiga, AmigaRelief -0.5 * height=(double 0.5)(multiply)(str height) - -# Amiga, AmigaRelief -0.5 * width=(double 0.5)(multiply)(str width) - -# Amiga, AmigaRelief -0.525 * height=(double 0.525)(multiply)(str height) - -# AmigaRelief -0.525 * width=(double 0.525)(multiply)(str width) - -# AmigaRelief -0.6 * height=(double 0.6)(multiply)(str height) - -# AmigaRelief -0.6 * width=(double 0.6)(multiply)(str width) - -# AmigaRelief -0.625 * height=(double 0.625)(multiply)(str height) - -# AmigaRelief -0.625 * width=(double 0.625)(multiply)(str width) - -# AmigaRelief -0.65 * height=(double 0.65)(multiply)(str height) - -# AmigaRelief -0.7 * height=(double 0.7)(multiply)(str height) - -# AmigaRelief -0.7 * width=(double 0.7)(multiply)(str width) - -# AmigaRelief -0.75 * height=(double 0.75)(multiply)(str height) - -# AmigaRelief -0.75 * width=(double 0.75)(multiply)(str width) - -# 4DWM, AgingGorilla, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, MWM, Maemo, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, SmoothGNOME, Soft Squares, Tactile, TangoDance, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -1={1==}(int 1) - -# Clearbox-look-2 -1 `max` ((height-title_height)/2)+1=(int 1)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(add)(int 1) - -# Almond, MetaGrip, Shiny, Shiny-Tango -1 `max` ((height-title_height)/2)-1=(int 1)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) )(subtract)(int 1) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, AmigaRelief, Black, Clearlooks-2.0-blend, Gilouche, GiloucheIM, Maemo, Outcrop, Shiny, Shiny-Tango, Sloth , TangoDance, pOS, sky, sky-blue -10={10==}(int 10) - -# MetaGrip -1024={1024==}(int 1024) - -# MetaGrip, Shiny, Shiny-Tango -11={11==}(int 11) - -# Almond, Shiny, Shiny-Tango -12={12==}(int 12) - -# Shiny -13={13==}(int 13) - -# Almond, Sloth -14={14==}(int 14) - -# sky, sky-blue -15={15==}(int 15) - -# Almond, Graphite, Maemo, MetaGrip, Shiny, Shiny-Tango, sky, sky-blue -16={16==}(int 16) - -# boxx -1600={1600==}(int 1600) - -# Agata, Maemo, boxx -17={17==}(int 17) - -# EasyListening, MetaGrip, Shiny, Shiny-Tango, boxx -19={19==}(int 19) - -# 4DWM, AgingGorilla, Almond, Amiga, AmigaRelief, Aquarius, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, EasyListening, Esco, Gilouche, GiloucheIM, Gorilla, MWM, Maemo, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, Sloth , SmoothGNOME, Tactile, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, boxx, c2, pOS -2={2==}(int 2) - -# Redmond -2 + ButtonIPad=(int 2)(add)(str ButtonIPad) - -# Shiny, Shiny-Tango -2 `max` ((height-title_height)/2)=(int 2)(max)( ( (str height)(subtract)(str title_height) )(divide)(int 2) ) - -# Firey 1.0, Firey Dark, Maemo, MetaGrip, Shiny, Shiny-Tango -20={20==}(int 20) - -# Shiny, Shiny-Tango -21={21==}(int 21) - -# Soft Squares -22={22==}(int 22) - -# Graphite, MetaGrip, Shiny, Shiny-Tango, sky, sky-blue -23={23==}(int 23) - -# Almond, Maemo, Shiny, Shiny-Tango -24={24==}(int 24) - -# Agata -25={25==}(int 25) - -# 4DWM, AgingGorilla, Amiga, AmigaRelief, Aquarius, Bright, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, EasyListening, Esco, Gilouche, GiloucheIM, Gorilla, Maemo, MetaGrip, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Sandwish, Shiny, Shiny-Tango, Sloth , SmoothGNOME, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -3={3==}(int 3) - -# Atlanta, Bright, Metabox, Redmond, Simple, SmoothGNOME, Tetelestai-Modern -3 + ButtonIPad=(int 3)(add)(str ButtonIPad) - -# SmoothGNOME -3 + ButtonIPad+1=(int 3)(add)(str ButtonIPad)(add)(int 1) - -# Chiro, Maemo, SmoothGNOME -32={32==}(int 32) - -# Outcrop -36={36==}(int 36) - -# Graphite -39={39==}(int 39) - -# 4DWM, Agata, AgingGorilla, Almond, Amiga, AmigaRelief, Aquarius, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, EasyListening, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, MWM, Maemo, MetaGrip, Redmond, River, Sandwish, Silverado, Simplebox, Sloth , SmoothGNOME, W2k, boxx, c2, pOS -4={4==}(int 4) - -# Clearbox-look-2 -4 `max` (width-title_width)/2=(int 4)(max)( (str width)(subtract)(str title_width) )(divide)(int 2) - -# sky, sky-blue -40={40==}(int 40) - -# TangoDance -48={48==}(int 48) - -# 4DWM, AgingGorilla, Almond, AmigaRelief, Aquarius, Black, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Correcamins, Crux, Gorilla, MWM, MetaGrip, Outcrop, Redmond, Sandwish, Shiny, Shiny-Tango, Simplebox, Sloth , Tactile, ThinMC, Vista Basic, pOS -5={5==}(int 5) - -# Almond, Clearbox-look-2, MetaGrip, Shiny, Shiny-Tango -5 `max` (width-title_width)/2+1=(int 5)(max)( (str width)(subtract)(str title_width) )(divide)(int 2)(add)(int 1) - -# 4DWM, AgingGorilla, Clearbox-in, Clearbox-out, Clearlooks-RedExit, Firey 1.0, Firey Dark, Gorilla, Graphite, MWM, Maemo, Outcrop, Simplebox, Soft Squares, Vista Basic, pOS -6={6==}(int 6) - -# Shiny, Shiny-Tango -6 `max` (width-title_width)/2+2=(int 6)(max)( (str width)(subtract)(str title_width) )(divide)(int 2)(add)(int 2) - -# 4DWM, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Clearbox-in, Clearbox-out, MWM, MetaGrip, Outcrop, Shiny, Shiny-Tango, Simplebox, pOS -7={7==}(int 7) - -# 4DWM, AgingGorilla, Almond, Clearlooks-RedExit, Gorilla, Maemo, Outcrop, Shiny, Sloth , Tactile, pOS -8={8==}(int 8) - -# Clearlooks-RedExit -8 + top_height - 16=(int 8)(add)(str top_height)(subtract)(int 16) - -# Vista Basic -87={87==}(int 87) - -# Clearbox-in, Clearbox-out, Outcrop, Shiny, Shiny-Tango, Simplebox, Vista Basic, pOS, sky, sky-blue -9={9==}(int 9) - -# Atlanta -ArrowSpacer `min` (height-MinArrowSize)/2=(str ArrowSpacer)(min)( (str height)(subtract)(str MinArrowSize) )(divide)(int 2) - -# Atlanta -ArrowSpacer `min` (width-MinArrowSize)/2=(str ArrowSpacer)(min)( (str width)(subtract)(str MinArrowSize) )(divide)(int 2) - -# Atlanta, Bright, Carved2, Chiro, Esco, Metabox, Redmond, River, Simple, SmoothGNOME, Tetelestai-Modern, c2 -ButtonIPad=(str ButtonIPad) - -# Esco -ButtonIPad + (height - (ButtonIPad + 1) * 2) * 0.33=(str ButtonIPad)(add)( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33) - -# Esco -ButtonIPad + (height - (ButtonIPad + 1) * 2) * 0.33 + 1=(str ButtonIPad)(add)( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33)(add)(int 1) - -# Esco -ButtonIPad + (width - (ButtonIPad + 1) * 2) * 0.33=(str ButtonIPad)(add)( (str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33) - -# Esco -ButtonIPad + (width - (ButtonIPad + 1) * 2) * 0.33 + 1=(str ButtonIPad)(add)( (str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.33)(add)(int 1) - -# Carved2, Chiro, Esco, River, c2 -ButtonIPad + 1=(str ButtonIPad)(add)(int 1) - -# Esco -ButtonIPad + 1 + 1=(str ButtonIPad)(add)(int 1)(add)(int 1) - -# Chiro, River, c2 -ButtonIPad + 2=(str ButtonIPad)(add)(int 2) - -# Chiro, River, c2 -ButtonIPad + 3=(str ButtonIPad)(add)(int 3) - -# Carved2, Chiro, Esco, Metabox, Redmond, River, Simple, Tetelestai-Modern, c2 -ButtonIPad - 1=(str ButtonIPad)(subtract)(int 1) - -# Esco -ButtonIPad - 1 + 1=(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Atlanta, Bright, Chiro, Metabox, Redmond, Simple, SmoothGNOME, Tetelestai-Modern, c2 -ButtonIPad+1=(str ButtonIPad)(add)(int 1) - -# Simple -ButtonIPad+2=(str ButtonIPad)(add)(int 2) - -# Redmond, SmoothGNOME -ButtonIPad-1=(str ButtonIPad)(subtract)(int 1) - -# Clearbox-look-2 -ButtonPad=(str ButtonPad) - -# Clearbox-look-2 -ButtonPad+(height-ButtonPad)/6=(str ButtonPad)(add)( (str height)(subtract)(str ButtonPad) )(divide)(int 6) - -# Clearbox-look-2 -ButtonPad+(height-ButtonPad)/6-1=(str ButtonPad)(add)( (str height)(subtract)(str ButtonPad) )(divide)(int 6)(subtract)(int 1) - -# Clearbox-look-2 -ButtonPad+1=(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -ButtonPad+2=(str ButtonPad)(add)(int 2) - -# Clearbox-look-2 -ButtonPad+3=(str ButtonPad)(add)(int 3) - -# Clearbox-look-2 -ButtonPad-1=(str ButtonPad)(subtract)(int 1) - -# Clearbox-look-2 -ButtonPad-2=(str ButtonPad)(subtract)(int 2) - -# Mista -CaptionStart=(str CaptionStart) - -# AgingGorilla, Crux, Gorilla, Sandwish -IconTitleSpacing=(str IconTitleSpacing) - -# Clearbox-look-2 -PrelightPad=(str PrelightPad) - -# Clearbox-look-2 -PrelightPad+(height-PrelightPad)/6=(str PrelightPad)(add)( (str height)(subtract)(str PrelightPad) )(divide)(int 6) - -# Clearbox-look-2 -PrelightPad+(height-PrelightPad)/6-1=(str PrelightPad)(add)( (str height)(subtract)(str PrelightPad) )(divide)(int 6)(subtract)(int 1) - -# Clearbox-look-2 -PrelightPad+1=(str PrelightPad)(add)(int 1) - -# Clearbox-look-2 -PrelightPad+2=(str PrelightPad)(add)(int 2) - -# Clearbox-look-2 -PrelightPad+3=(str PrelightPad)(add)(int 3) - -# Clearbox-look-2 -PrelightPad-1=(str PrelightPad)(subtract)(int 1) - -# Clearbox-look-2 -PrelightPad-2=(str PrelightPad)(subtract)(int 2) - -# Carved2 -ResizerWidth=(str ResizerWidth) - -# Carved2 -ResizerWidth + 1=(str ResizerWidth)(add)(int 1) - -# Mista -TitlebarPad=(str TitlebarPad) - -# Silverado -bottom_height=(str bottom_height) - -# Carved2 -bottom_height - 3=(str bottom_height)(subtract)(int 3) - -# Carved2 -bottom_height - 4=(str bottom_height)(subtract)(int 4) - -# MWM, Tetelestai-Modern -bottom_height-1=(str bottom_height)(subtract)(int 1) - -# 4DWM -bottom_height-2=(str bottom_height)(subtract)(int 2) - -# 4DWM -bottom_height-4=(str bottom_height)(subtract)(int 4) - -# 4DWM, Agata, AgingGorilla, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, Atlanta, Black, Bright, Carved2, Chiro, Clearbox-in, Clearbox-out, Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Correcamins, Crux, EasyListening, Esco, Firey 1.0, Firey Dark, Gorilla, Graphite, MWM, Maemo, MetaGrip, Metabox, Mista, Outcrop, Redmond, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, SmoothGNOME, Soft Squares, Tactile, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, W2k, boxx, c2, sky, sky-blue -height=(str height) - -# Esco -height + 25=(str height)(add)(int 25) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2)=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2) - 1=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2) - 2=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height - ((height-(Bmin`max`height-Bpad*2))/2)-1=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Esco -height - (ButtonIPad + 1) * 2=(str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) - -# AgingGorilla, Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gilouche, GiloucheIM, Gorilla, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME, TangoDance -height - 1=(str height)(subtract)(int 1) - -# Esco -height - 1 - ButtonIPad - 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -height - 1 - ButtonIPad - 1 + 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Esco -height - 1 - ButtonIPad - 1 - 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1) - -# Esco -height - 1 - ButtonIPad - 1 - 1 + 1=(str height)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1)(add)(int 1) - -# AgingGorilla, Gorilla -height - 10=(str height)(subtract)(int 10) - -# AgingGorilla, Gorilla -height - 12=(str height)(subtract)(int 12) - -# AgingGorilla, Gorilla -height - 14=(str height)(subtract)(int 14) - -# AgingGorilla, Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gorilla, Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME -height - 2=(str height)(subtract)(int 2) - -# Esco, Gilouche, GiloucheIM, SmoothGNOME, TangoDance -height - 3=(str height)(subtract)(int 3) - -# Crux, Sandwish, SmoothGNOME -height - 4=(str height)(subtract)(int 4) - -# Atlanta, Bright, Simple -height - 5 - ButtonIPad=(str height)(subtract)(int 5)(subtract)(str ButtonIPad) - -# AgingGorilla, Esco, Gorilla -height - 7=(str height)(subtract)(int 7) - -# Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -height - 7 - ButtonIPad=(str height)(subtract)(int 7)(subtract)(str ButtonIPad) - -# AgingGorilla, Gorilla -height - 8=(str height)(subtract)(int 8) - -# Carved2, Chiro, Metabox, Redmond, River, Simple, SmoothGNOME, Tetelestai-Modern, c2 -height - ButtonIPad=(str height)(subtract)(str ButtonIPad) - -# Carved2, Simple -height - ButtonIPad + 1=(str height)(subtract)(str ButtonIPad)(add)(int 1) - -# Esco -height - ButtonIPad - ((height - (ButtonIPad + 1) * 2) * 0.4)=(str height)(subtract)(str ButtonIPad)(subtract)( ( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) ) - -# Esco -height - ButtonIPad - ((height - (ButtonIPad + 1) * 2) * 0.4) - 1=(str height)(subtract)(str ButtonIPad)(subtract)( ( (str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) )(multiply)(double 0.4) )(subtract)(int 1) - -# Atlanta, Carved2, Esco, Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -height - ButtonIPad - 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -height - ButtonIPad - 1 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Esco -height - ButtonIPad - 1 - 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1) - -# Esco -height - ButtonIPad - 1 - 1 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1)(add)(int 1) - -# Bright, Chiro, Esco, Redmond, River, SmoothGNOME, c2 -height - ButtonIPad - 2=(str height)(subtract)(str ButtonIPad)(subtract)(int 2) - -# Esco -height - ButtonIPad - 2 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 2)(add)(int 1) - -# Esco -height - ButtonIPad - 3=(str height)(subtract)(str ButtonIPad)(subtract)(int 3) - -# Esco -height - ButtonIPad - 3 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(add)(int 1) - -# Esco -height - ButtonIPad - 3 - 4=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 4) - -# Esco -height - ButtonIPad - 3 - 4 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 4)(add)(int 1) - -# Esco -height - ButtonIPad - 3 - 5=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 5) - -# Esco -height - ButtonIPad - 3 - 5 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 3)(subtract)(int 5)(add)(int 1) - -# Metabox, Tetelestai-Modern -height - ButtonIPad - 4=(str height)(subtract)(str ButtonIPad)(subtract)(int 4) - -# Esco -height - ButtonIPad - 5=(str height)(subtract)(str ButtonIPad)(subtract)(int 5) - -# Esco -height - ButtonIPad - 5 + 1=(str height)(subtract)(str ButtonIPad)(subtract)(int 5)(add)(int 1) - -# Atlanta, Bright, Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -height - ButtonIPad - ThickLineWidth + 1=(str height)(subtract)(str ButtonIPad)(subtract)(str ThickLineWidth)(add)(int 1) - -# Simple -height - ButtonIPad - ThickLineWidth + 3=(str height)(subtract)(str ButtonIPad)(subtract)(str ThickLineWidth)(add)(int 3) - -# Chiro, River, c2 -height - ButtonIPad-1=(str height)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Quiet-Environment, Quiet-Graphite, Quiet-Human, Quiet-Purple-2K6 -height - height / 4=(str height)(subtract)(str height)(divide)(int 4) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -height - height / 4 + 2=(str height)(subtract)(str height)(divide)(int 4)(add)(int 2) - -# Crux, Maemo, Sandwish -height - object_height=(str height)(subtract)(str object_height) - -# Esco -height - top_height - bottom_height + 1=(str height)(subtract)(str top_height)(subtract)(str bottom_height)(add)(int 1) - -# Esco -height - top_height - bottom_height - 1=(str height)(subtract)(str top_height)(subtract)(str bottom_height)(subtract)(int 1) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance -height / 2=(str height)(divide)(int 2) - -# TangoDance -height / 2 - 1=(str height)(divide)(int 2)(subtract)(int 1) - -# TangoDance -height / 2 - 2=(str height)(divide)(int 2)(subtract)(int 2) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, TangoDance -height / 2 - 3=(str height)(divide)(int 2)(subtract)(int 3) - -# Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height / 2 - 4=(str height)(divide)(int 2)(subtract)(int 4) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -height / 3=(str height)(divide)(int 3) - -# Quiet-Environment, Quiet-Graphite, Quiet-Human, Quiet-Purple-2K6 -height / 4=(str height)(divide)(int 4) - -# Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2 -height / 4 + 2=(str height)(divide)(int 4)(add)(int 2) - -# Outcrop -height /2=(str height)(divide)(int 2) - -# Outcrop -height /2 +1=(str height)(divide)(int 2)(add)(int 1) - -# Outcrop -height /2 +2=(str height)(divide)(int 2)(add)(int 2) - -# Outcrop -height /2 -1=(str height)(divide)(int 2)(subtract)(int 1) - -# Bentham -height `max` ((width-title_width)) / 2=(str height)(max)( ( (str width)(subtract)(str title_width) ) )(divide)(int 2) - -# Mista -height `min` object_height=(str height)(min)(str object_height) - -# Sloth -height+1=(str height)(add)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height-((height-(Bmin`max`height-Bpad*2))/2)*2-1=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -height-((height-(Bmin`max`height-Bpad*2))/2)*2-3=(str height)(subtract)( ( (str height)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 3) - -# 4DWM -height-(2 * right_width - 1)=(str height)(subtract)( (int 2)(multiply)(str right_width)(subtract)(int 1) ) - -# Chiro, c2 -height-(ButtonIPad+1)*2-1=(str height)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2)(subtract)(int 1) - -# 4DWM -height-(right_width-1)=(str height)(subtract)( (str right_width)(subtract)(int 1) ) - -# 4DWM -height-(right_width-2)=(str height)(subtract)( (str right_width)(subtract)(int 2) ) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Simple, Simplebox, Sloth , SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -height-1=(str height)(subtract)(int 1) - -# pOS -height-11=(str height)(subtract)(int 11) - -# 4DWM, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, Gilouche, GiloucheIM, MWM, Metabox, Outcrop, River, Shiny, Shiny-Tango, Silverado, Simple, SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -height-2=(str height)(subtract)(int 2) - -# Shiny, Shiny-Tango -height-21=(str height)(subtract)(int 21) - -# Soft Squares, Tactile -height-23=(str height)(subtract)(int 23) - -# Maemo -height-25=(str height)(subtract)(int 25) - -# Maemo -height-26=(str height)(subtract)(int 26) - -# Maemo, Shiny, Shiny-Tango -height-29=(str height)(subtract)(int 29) - -# 4DWM, Aquarius, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, MWM, Outcrop, River, Simple, Simplebox, SmoothGNOME, Tactile, Tetelestai-Modern, W2k, c2 -height-3=(str height)(subtract)(int 3) - -# 4DWM, Amiga, AmigaRelief, Aquarius, Bright, Carved2, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Maemo, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Sandwish, SmoothGNOME, Tetelestai-Modern, W2k, c2, pOS -height-4=(str height)(subtract)(int 4) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Carved2, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, MWM, River, SmoothGNOME, Tetelestai-Modern, W2k, c2, pOS -height-5=(str height)(subtract)(int 5) - -# 4DWM, AmigaRelief, Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, EasyListening, MWM, pOS -height-6=(str height)(subtract)(int 6) - -# 4DWM, MWM, Shiny, Shiny-Tango, pOS -height-7=(str height)(subtract)(int 7) - -# 4DWM, pOS -height-8=(str height)(subtract)(int 8) - -# Almond, Outcrop, pOS -height-9=(str height)(subtract)(int 9) - -# Carved2 -height-ButtonIPad*2=(str height)(subtract)(str ButtonIPad)(multiply)(int 2) - -# Simple -height-ButtonIPad*2 + 1=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(add)(int 1) - -# Atlanta, Chiro, Metabox, Redmond, River, SmoothGNOME, Tetelestai-Modern, c2 -height-ButtonIPad*2-1=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 1) - -# Bright -height-ButtonIPad*2-2=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 2) - -# Chiro, River, c2 -height-ButtonIPad*2-5=(str height)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 5) - -# Clearbox-look-2 -height-ButtonPad=(str height)(subtract)(str ButtonPad) - -# Clearbox-look-2 -height-ButtonPad*2+1=(str height)(subtract)(str ButtonPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -height-ButtonPad*2-2=(str height)(subtract)(str ButtonPad)(multiply)(int 2)(subtract)(int 2) - -# Clearbox-look-2 -height-ButtonPad+1=(str height)(subtract)(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -height-ButtonPad-1=(str height)(subtract)(str ButtonPad)(subtract)(int 1) - -# Clearbox-look-2 -height-ButtonPad-2=(str height)(subtract)(str ButtonPad)(subtract)(int 2) - -# Clearbox-look-2 -height-PrelightPad=(str height)(subtract)(str PrelightPad) - -# Clearbox-look-2 -height-PrelightPad*2+1=(str height)(subtract)(str PrelightPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -height-PrelightPad*2-2=(str height)(subtract)(str PrelightPad)(multiply)(int 2)(subtract)(int 2) - -# Clearbox-look-2 -height-PrelightPad+1=(str height)(subtract)(str PrelightPad)(add)(int 1) - -# Clearbox-look-2 -height-PrelightPad-1=(str height)(subtract)(str PrelightPad)(subtract)(int 1) - -# Clearbox-look-2 -height-PrelightPad-2=(str height)(subtract)(str PrelightPad)(subtract)(int 2) - -# Chiro, Gilouche, GiloucheIM, SmoothGNOME, Tetelestai-Modern -height-bottom_height=(str height)(subtract)(str bottom_height) - -# Carved2 -height-bottom_height + 1=(str height)(subtract)(str bottom_height)(add)(int 1) - -# Carved2 -height-bottom_height + 2=(str height)(subtract)(str bottom_height)(add)(int 2) - -# 4DWM, MWM -height-bottom_height+1=(str height)(subtract)(str bottom_height)(add)(int 1) - -# Gilouche, GiloucheIM -height-bottom_height-top_height=(str height)(subtract)(str bottom_height)(subtract)(str top_height) - -# 4DWM -height-bottom_height/2=(str height)(subtract)(str bottom_height)(divide)(int 2) - -# Mista -height-object_height=(str height)(subtract)(str object_height) - -# 4DWM, MWM -height-right_width=(str height)(subtract)(str right_width) - -# MWM -height-right_width-1=(str height)(subtract)(str right_width)(subtract)(int 1) - -# c2 -height-title_height=(str height)(subtract)(str title_height) - -# Chiro, SmoothGNOME -height-title_height-38=(str height)(subtract)(str title_height)(subtract)(int 38) - -# Amiga, AmigaRelief, c2, pOS -height-title_height-6=(str height)(subtract)(str title_height)(subtract)(int 6) - -# 4DWM, MWM -height-top_height=(str height)(subtract)(str top_height) - -# 4DWM -height-top_height+1=(str height)(subtract)(str top_height)(add)(int 1) - -# 4DWM, MWM, Tactile -height-top_height-1=(str height)(subtract)(str top_height)(subtract)(int 1) - -# 4DWM -height-top_height-2=(str height)(subtract)(str top_height)(subtract)(int 2) - -# Atlanta, Bright, Metabox, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -height-top_height-bottom_height+1=(str height)(subtract)(str top_height)(subtract)(str bottom_height)(add)(int 1) - -# Sloth -height/1.5=(str height)(divide)(double 1.5) - -# 4DWM, Aquarius, Bentham, Clearbox-in, Clearbox-out, MWM, Simplebox, Sloth , Tetelestai-Modern -height/2=(str height)(divide)(int 2) - -# Bentham -height/2 + height/4 - 1=(str height)(divide)(int 2)(add)(str height)(divide)(int 4)(subtract)(int 1) - -# Bentham -height/2 + height/4 - 2=(str height)(divide)(int 2)(add)(str height)(divide)(int 4)(subtract)(int 2) - -# Bentham -height/2 - height/4=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4) - -# Bentham -height/2 - height/4 + 1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 1) - -# Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2 -height/2 - width/2=(str height)(divide)(int 2)(subtract)(str width)(divide)(int 2) - -# Amiga, AmigaRelief -height/2 - width/2 + 2=(str height)(divide)(int 2)(subtract)(str width)(divide)(int 2)(add)(int 2) - -# Clearbox-look-2 -height/2+(height-ButtonPad)/6+1=(str height)(divide)(int 2)(add)( (str height)(subtract)(str ButtonPad) )(divide)(int 6)(add)(int 1) - -# Clearbox-look-2 -height/2+(height-PrelightPad)/6+1=(str height)(divide)(int 2)(add)( (str height)(subtract)(str PrelightPad) )(divide)(int 6)(add)(int 1) - -# 4DWM, Aquarius, Clearbox-in, Clearbox-out, Simplebox -height/2+1=(str height)(divide)(int 2)(add)(int 1) - -# 4DWM, Clearbox-in, Clearbox-out, MWM, Simplebox -height/2+2=(str height)(divide)(int 2)(add)(int 2) - -# 4DWM, Clearbox-in, Clearbox-out, Simplebox -height/2+3=(str height)(divide)(int 2)(add)(int 3) - -# Clearbox-in, Clearbox-out, Simplebox -height/2+4=(str height)(divide)(int 2)(add)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -height/2+5=(str height)(divide)(int 2)(add)(int 5) - -# Clearbox-in, Clearbox-out, Simplebox -height/2+6=(str height)(divide)(int 2)(add)(int 6) - -# Aquarius -height/2+height/4=(str height)(divide)(int 2)(add)(str height)(divide)(int 4) - -# Aquarius -height/2+height/4-1=(str height)(divide)(int 2)(add)(str height)(divide)(int 4)(subtract)(int 1) - -# Clearbox-in, Clearbox-out, MWM, Simplebox -height/2-1=(str height)(divide)(int 2)(subtract)(int 1) - -# 4DWM, Aquarius, Clearbox-in, Clearbox-out, Simplebox -height/2-2=(str height)(divide)(int 2)(subtract)(int 2) - -# Clearbox-in, Clearbox-out, Outcrop, Simplebox -height/2-3=(str height)(divide)(int 2)(subtract)(int 3) - -# Clearbox-in, Clearbox-out, Outcrop, Simplebox -height/2-4=(str height)(divide)(int 2)(subtract)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -height/2-5=(str height)(divide)(int 2)(subtract)(int 5) - -# Aquarius -height/2-5+(2`max`height/8)=(str height)(divide)(int 2)(subtract)(int 5)(add)( (int 2)(max)(str height)(divide)(int 8) ) - -# Aquarius -height/2-height/4=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4) - -# Aquarius -height/2-height/4+1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 1) - -# Aquarius -height/2-height/4+2=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 2) - -# Aquarius -height/2-height/6+1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 6)(add)(int 1) - -# Aquarius -height/2-height/6+2=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 6)(add)(int 2) - -# Bentham -height/2-height/8-1=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 8)(subtract)(int 1) - -# Bentham -height/2-height/8-2=(str height)(divide)(int 2)(subtract)(str height)(divide)(int 8)(subtract)(int 2) - -# Aquarius -height/3+1=(str height)(divide)(int 3)(add)(int 1) - -# Aquarius -height/3-1=(str height)(divide)(int 3)(subtract)(int 1) - -# Aquarius -height/3-3=(str height)(divide)(int 3)(subtract)(int 3) - -# Bentham -height/4=(str height)(divide)(int 4) - -# Bentham -height/4+2=(str height)(divide)(int 4)(add)(int 2) - -# 4DWM, Esco, Gilouche, GiloucheIM, MWM, Silverado -left_width=(str left_width) - -# Esco -left_width - 1=(str left_width)(subtract)(int 1) - -# 4DWM, Atlanta, Bright, Chiro, Gilouche, GiloucheIM, MWM, Metabox, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -left_width-1=(str left_width)(subtract)(int 1) - -# 4DWM, Tetelestai-Modern -left_width-2=(str left_width)(subtract)(int 2) - -# 4DWM -left_width-3=(str left_width)(subtract)(int 3) - -# Aquarius, Atlanta, Clearlooks-2.0-blend, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Metabox, Mista, Outcrop, Silverado, TangoDance, Vista Basic, W2k -mini_icon_height=(str mini_icon_height) - -# Bright -mini_icon_height-1=(str mini_icon_height)(subtract)(int 1) - -# Aquarius, Atlanta, Clearlooks-2.0-blend, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Metabox, Mista, Outcrop, Silverado, Sloth , TangoDance, Vista Basic, W2k -mini_icon_width=(str mini_icon_width) - -# Esco -mini_icon_width + IconTitleSpacing=(str mini_icon_width)(add)(str IconTitleSpacing) - -# Bright -mini_icon_width-1=(str mini_icon_width)(subtract)(int 1) - -# Agata, AgingGorilla, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Crux, Firey 1.0, Firey Dark, Gorilla, Graphite, Maemo, Mista, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Sandwish, Soft Squares, Tactile, ThinMC, Vista Basic, boxx, sky, sky-blue -object_height=(str object_height) - -# Maemo -object_height+2=(str object_height)(add)(int 2) - -# Agata, AgingGorilla, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Crux, Firey 1.0, Firey Dark, Gorilla, Graphite, Maemo, Mista, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Sandwish, Silverado, Soft Squares, Tactile, ThinMC, Vista Basic, W2k, sky, sky-blue -object_width=(str object_width) - -# Crux -object_width * height / 22=(str object_width)(multiply)(str height)(divide)(int 22) - -# Maemo -object_width+2=(str object_width)(add)(int 2) - -# 4DWM, MWM, Silverado -right_width=(str right_width) - -# 4DWM, MWM -right_width-1=(str right_width)(subtract)(int 1) - -# 4DWM, Tetelestai-Modern -right_width-2=(str right_width)(subtract)(int 2) - -# 4DWM -right_width-3=(str right_width)(subtract)(int 3) - -# 4DWM -right_width-4=(str right_width)(subtract)(int 4) - -# Gilouche, GiloucheIM -title_height + 10=(str title_height)(add)(int 10) - -# TangoDance -title_height + 12=(str title_height)(add)(int 12) - -# Clearlooks, Clearlooks-Pinstripe, River -title_height + 3=(str title_height)(add)(int 3) - -# Chiro, SmoothGNOME -title_height + 38=(str title_height)(add)(int 38) - -# Chiro, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -title_height + 4=(str title_height)(add)(int 4) - -# Chiro, Clearlooks, Clearlooks-Pinstripe, Gilouche, GiloucheIM, River, SmoothGNOME, TangoDance, c2 -title_height + 5=(str title_height)(add)(int 5) - -# Clearlooks, Clearlooks-Pinstripe, SmoothGNOME, c2 -title_height + 6=(str title_height)(add)(int 6) - -# TangoDance -title_height + 9=(str title_height)(add)(int 9) - -# Outcrop -title_height +8=(str title_height)(add)(int 8) - -# Outcrop -title_height -7=(str title_height)(subtract)(int 7) - -# TangoDance -title_height / 2 - 5=(str title_height)(divide)(int 2)(subtract)(int 5) - -# Outcrop -title_height /1.5=(str title_height)(divide)(double 1.5) - -# Outcrop -title_height /2=(str title_height)(divide)(int 2) - -# Outcrop -title_height /4=(str title_height)(divide)(int 4) - -# 4DWM -title_height*2/3=(str title_height)(multiply)(int 2)(divide)(int 3) - -# AmigaRelief, pOS -title_height+3=(str title_height)(add)(int 3) - -# Amiga, AmigaRelief, Clearbox-look-2, pOS -title_height+4=(str title_height)(add)(int 4) - -# Amiga, AmigaRelief, pOS -title_height+5=(str title_height)(add)(int 5) - -# Chiro, Outcrop, SmoothGNOME, c2 -title_height+6=(str title_height)(add)(int 6) - -# Outcrop -title_height+7=(str title_height)(add)(int 7) - -# Outcrop -title_height+8=(str title_height)(add)(int 8) - -# sky, sky-blue -title_width + 16 `min` width - 14=(str title_width)(add)(int 16)(min)(str width)(subtract)(int 14) - -# sky, sky-blue -title_width + 21 `min` width - object_width=(str title_width)(add)(int 21)(min)(str width)(subtract)(str object_width) - -# sky, sky-blue -title_width + 6=(str title_width)(add)(int 6) - -# Esco -title_width + mini_icon_width + IconTitleSpacing * 3 - 1=(str title_width)(add)(str mini_icon_width)(add)(str IconTitleSpacing)(multiply)(int 3)(subtract)(int 1) - -# boxx -title_width+15=(str title_width)(add)(int 15) - -# Maemo -title_width+181=(str title_width)(add)(int 181) - -# Sandwish -title_width+20=(str title_width)(add)(int 20) - -# Maemo -title_width+32=(str title_width)(add)(int 32) - -# Maemo -title_width+32+149=(str title_width)(add)(int 32)(add)(int 149) - -# boxx -title_width-2=(str title_width)(subtract)(int 2) - -# Sandwish -title_width/2+150=(str title_width)(divide)(int 2)(add)(int 150) - -# 4DWM, Chiro, Clearbox-in, Clearbox-out, Esco, MWM, Simplebox -top_height=(str top_height) - -# Clearlooks-RedExit, Esco -top_height - 1=(str top_height)(subtract)(int 1) - -# Clearlooks-RedExit -top_height - 16=(str top_height)(subtract)(int 16) - -# Clearlooks-RedExit -top_height - 2=(str top_height)(subtract)(int 2) - -# Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -top_height / 2=(str top_height)(divide)(int 2) - -# Aquarius -top_height*2/5=(str top_height)(multiply)(int 2)(divide)(int 5) - -# Aquarius -top_height*3/10=(str top_height)(multiply)(int 3)(divide)(int 10) - -# Aquarius -top_height*3/5=(str top_height)(multiply)(int 3)(divide)(int 5) - -# Aquarius -top_height*4/5=(str top_height)(multiply)(int 4)(divide)(int 5) - -# Aquarius -top_height*7/10=(str top_height)(multiply)(int 7)(divide)(int 10) - -# Aquarius -top_height*9/10=(str top_height)(multiply)(int 9)(divide)(int 10) - -# 4DWM -top_height+1=(str top_height)(add)(int 1) - -# 4DWM, Aquarius, Atlanta, Bright, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, MWM, Metabox, Simple, SmoothGNOME, Tactile, TangoDance, Tetelestai-Modern -top_height-1=(str top_height)(subtract)(int 1) - -# 4DWM, Aquarius, Clearlooks-2.0-blend, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -top_height-2=(str top_height)(subtract)(int 2) - -# 4DWM -top_height-3=(str top_height)(subtract)(int 3) - -# Aquarius -top_height/10=(str top_height)(divide)(int 10) - -# Aquarius -top_height/10+1=(str top_height)(divide)(int 10)(add)(int 1) - -# Aquarius -top_height/2=(str top_height)(divide)(int 2) - -# Aquarius -top_height/5=(str top_height)(divide)(int 5) - -# 4DWM, Agata, AgingGorilla, Almond, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Black, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Correcamins, Crux, EasyListening, Esco, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Gorilla, Graphite, MWM, MetaGrip, Metabox, Mista, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Sandwish, Shiny, Shiny-Tango, Silverado, Simple, Simplebox, SmoothGNOME, TangoDance, Tetelestai-Modern, ThinMC, Vista Basic, W2k, boxx, c2, pOS, sky, sky-blue -width=(str width) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width - ((width-(Bmin`max`height-Bpad*2))/2)=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width - ((width-(Bmin`max`height-Bpad*2))/2) - 1=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Esco -width - (ButtonIPad + 1) * 2=(str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2) - -# sky, sky-blue -width - 0=(str width)(subtract)(int 0) - -# AgingGorilla, Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gilouche, GiloucheIM, Gorilla, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME, Soft Squares, TangoDance -width - 1=(str width)(subtract)(int 1) - -# Esco -width - 1 - ButtonIPad=(str width)(subtract)(int 1)(subtract)(str ButtonIPad) - -# Esco -width - 1 - ButtonIPad + 1=(str width)(subtract)(int 1)(subtract)(str ButtonIPad)(add)(int 1) - -# Esco -width - 1 - ButtonIPad - 1=(str width)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -width - 1 - ButtonIPad - 1 + 1=(str width)(subtract)(int 1)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Agata, Black, Correcamins -width - 10=(str width)(subtract)(int 10) - -# AgingGorilla, Gorilla -width - 11=(str width)(subtract)(int 11) - -# AgingGorilla, Almond, Gorilla, Graphite, sky, sky-blue -width - 12=(str width)(subtract)(int 12) - -# AgingGorilla, Gorilla -width - 13=(str width)(subtract)(int 13) - -# AgingGorilla, Gorilla -width - 16=(str width)(subtract)(int 16) - -# AgingGorilla, Aquarius, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Esco, Gilouche, GiloucheIM, Gorilla, Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2, Redmond, River, Simple, SmoothGNOME, Soft Squares, TangoDance, ThinMC -width - 2=(str width)(subtract)(int 2) - -# Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple -width - 20=(str width)(subtract)(int 20) - -# Almond -width - 24=(str width)(subtract)(int 24) - -# Graphite, sky, sky-blue -width - 27=(str width)(subtract)(int 27) - -# Carved2, Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Gilouche, GiloucheIM, SmoothGNOME, TangoDance -width - 3=(str width)(subtract)(int 3) - -# Aquarius, Carved2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Firey 1.0, Firey Dark, Gilouche, GiloucheIM, Quiet-Environment-v2, Quiet-Graphite-v2, Quiet-Purple-2K6-v2, River, Sandwish, SmoothGNOME, Tactile, TangoDance -width - 4=(str width)(subtract)(int 4) - -# Gilouche, GiloucheIM -width - 5=(str width)(subtract)(int 5) - -# Atlanta, Bright, Simple -width - 5 - ButtonIPad=(str width)(subtract)(int 5)(subtract)(str ButtonIPad) - -# Firey 1.0, Firey Dark, Tactile -width - 6=(str width)(subtract)(int 6) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Esco -width - 7=(str width)(subtract)(int 7) - -# Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -width - 7 - ButtonIPad=(str width)(subtract)(int 7)(subtract)(str ButtonIPad) - -# AgingGorilla, Gorilla -width - 8=(str width)(subtract)(int 8) - -# AgingGorilla, Gorilla -width - 9=(str width)(subtract)(int 9) - -# Atlanta, Metabox, Redmond, SmoothGNOME, Tetelestai-Modern -width - ButtonIPad=(str width)(subtract)(str ButtonIPad) - -# Simple -width - ButtonIPad + 1=(str width)(subtract)(str ButtonIPad)(add)(int 1) - -# Atlanta, Esco, Redmond, SmoothGNOME, Tetelestai-Modern -width - ButtonIPad - 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Esco -width - ButtonIPad - 1 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1)(add)(int 1) - -# Esco -width - ButtonIPad - 1 - 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1) - -# Esco -width - ButtonIPad - 1 - 1 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1)(subtract)(int 1)(add)(int 1) - -# Bright, Esco -width - ButtonIPad - 2=(str width)(subtract)(str ButtonIPad)(subtract)(int 2) - -# Esco -width - ButtonIPad - 2 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 2)(add)(int 1) - -# Esco, Metabox, Tetelestai-Modern -width - ButtonIPad - 4=(str width)(subtract)(str ButtonIPad)(subtract)(int 4) - -# Esco -width - ButtonIPad - 4 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 4)(add)(int 1) - -# Esco -width - ButtonIPad - 5=(str width)(subtract)(str ButtonIPad)(subtract)(int 5) - -# Esco -width - ButtonIPad - 5 + 1=(str width)(subtract)(str ButtonIPad)(subtract)(int 5)(add)(int 1) - -# Tetelestai-Modern -width - ButtonIPad -2=(str width)(subtract)(str ButtonIPad)(subtract)(int 2) - -# Bright -width - ButtonIPad-1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Carved2 -width - ResizerWidth - 1=(str width)(subtract)(str ResizerWidth)(subtract)(int 1) - -# Carved2 -width - ResizerWidth - 2=(str width)(subtract)(str ResizerWidth)(subtract)(int 2) - -# Esco -width - left_width - right_width + 1=(str width)(subtract)(str left_width)(subtract)(str right_width)(add)(int 1) - -# Esco -width - left_width - right_width - 1=(str width)(subtract)(str left_width)(subtract)(str right_width)(subtract)(int 1) - -# Esco -width - mini_icon_width - IconTitleSpacing=(str width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing) - -# Agata, Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple, Black, Correcamins, Crux, Firey 1.0, Firey Dark, Graphite, Maemo, Sandwish, Silverado, Tactile, sky, sky-blue -width - object_width=(str width)(subtract)(str object_width) - -# Esco -width - title_width - IconTitleSpacing=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing) - -# Esco -width - title_width - IconTitleSpacing + 25 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(add)(int 25)(add)(int 3) - -# Esco -width - title_width - IconTitleSpacing + 25 - 1 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(add)(int 25)(subtract)(int 1)(add)(int 3) - -# Esco -width - title_width - IconTitleSpacing - height - 25 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(subtract)(str height)(subtract)(int 25)(add)(int 3) - -# Esco -width - title_width - IconTitleSpacing - height - 25 - 1 + 3=(str width)(subtract)(str title_width)(subtract)(str IconTitleSpacing)(subtract)(str height)(subtract)(int 25)(subtract)(int 1)(add)(int 3) - -# Esco -width - title_width - height - (IconTitleSpacing * 2)=(str width)(subtract)(str title_width)(subtract)(str height)(subtract)( (str IconTitleSpacing)(multiply)(int 2) ) - -# Esco -width - title_width - mini_icon_width - (IconTitleSpacing * 2)=(str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)( (str IconTitleSpacing)(multiply)(int 2) ) - -# Esco -width - title_width - mini_icon_width - IconTitleSpacing * 3=(str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing)(multiply)(int 3) - -# Esco -width - title_width - mini_icon_width - IconTitleSpacing * 3 - 18=(str width)(subtract)(str title_width)(subtract)(str mini_icon_width)(subtract)(str IconTitleSpacing)(multiply)(int 3)(subtract)(int 18) - -# Outcrop -width -(width /3.6)=(str width)(subtract)( (str width)(divide)(double 3.6) ) - -# Outcrop -width -(width /3.6) +1=(str width)(subtract)( (str width)(divide)(double 3.6) )(add)(int 1) - -# Outcrop -width -(width /3.6) +2=(str width)(subtract)( (str width)(divide)(double 3.6) )(add)(int 2) - -# Outcrop -width -(width /3.6) -1=(str width)(subtract)( (str width)(divide)(double 3.6) )(subtract)(int 1) - -# Alphacube 0.9b Metacity Color, Alphacube 0.9b Metacity Light, Alphacube 0.9b Metacity Simple -width -7=(str width)(subtract)(int 7) - -# Carved2 -width / 2=(str width)(divide)(int 2) - -# Outcrop -width / 3.4=(str width)(divide)(double 3.4) - -# Outcrop -width / 3.4 -1=(str width)(divide)(double 3.4)(subtract)(int 1) - -# Outcrop -width /2=(str width)(divide)(int 2) - -# Outcrop -width /2+1=(str width)(divide)(int 2)(add)(int 1) - -# Outcrop -width /2-1=(str width)(divide)(int 2)(subtract)(int 1) - -# Outcrop -width /2-2=(str width)(divide)(int 2)(subtract)(int 2) - -# Outcrop -width /3.4 +1=(str width)(divide)(double 3.4)(add)(int 1) - -# Outcrop -width /3.4 +2=(str width)(divide)(double 3.4)(add)(int 2) - -# Mista -width `min` object_width=(str width)(min)(str object_width) - -# Atlanta, Bright -width+1-SpacerWidth/2=(str width)(add)(int 1)(subtract)(str SpacerWidth)(divide)(int 2) - -# Vista Basic -width+2=(str width)(add)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width- ((width-(Bmin`max`height-Bpad*2))/2)=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) ) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2) - 2=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)*2=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)*2-1=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 1) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)*2-3=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(multiply)(int 2)(subtract)(int 3) - -# Clearlooks, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop -width-((width-(Bmin`max`height-Bpad*2))/2)-1=(str width)(subtract)( ( (str width)(subtract)( (str Bmin)(max)(str height)(subtract)(str Bpad)(multiply)(int 2) ) )(divide)(int 2) )(subtract)(int 1) - -# Chiro, c2 -width-(ButtonIPad+1)=(str width)(subtract)( (str ButtonIPad)(add)(int 1) ) - -# Chiro, c2 -width-(ButtonIPad+1)*2-1=(str width)(subtract)( (str ButtonIPad)(add)(int 1) )(multiply)(int 2)(subtract)(int 1) - -# Mista -width-(TitlebarPad*2)=(str width)(subtract)( (str TitlebarPad)(multiply)(int 2) ) - -# 4DWM -width-(left_width+right_width - 1)=(str width)(subtract)( (str left_width)(add)(str right_width)(subtract)(int 1) ) - -# 4DWM -width-(right_width-1)=(str width)(subtract)( (str right_width)(subtract)(int 1) ) - -# 4DWM -width-(right_width-2)=(str width)(subtract)( (str right_width)(subtract)(int 2) ) - -# Maemo -width-(title_width+80)=(str width)(subtract)( (str title_width)(add)(int 80) ) - -# Maemo -width-(title_width+88+8)=(str width)(subtract)( (str title_width)(add)(int 88)(add)(int 8) ) - -# Metabox -width-(width-ButtonIPad)/2-1=(str width)(subtract)( (str width)(subtract)(str ButtonIPad) )(divide)(int 2)(subtract)(int 1) - -# sky, sky-blue -width-0=(str width)(subtract)(int 0) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, Maemo, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, Redmond, River, Shiny, Shiny-Tango, Simple, Simplebox, Sloth , SmoothGNOME, Soft Squares, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -width-1=(str width)(subtract)(int 1) - -# 4DWM, Almond, Outcrop, Shiny, Shiny-Tango -width-10=(str width)(subtract)(int 10) - -# Graphite -width-12=(str width)(subtract)(int 12) - -# Almond, Outcrop, pOS -width-15=(str width)(subtract)(int 15) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Atlanta, Bentham, Bright, Carved2, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, Gilouche, GiloucheIM, MWM, MetaGrip, Metabox, Outcrop, Quiet-Environment, Quiet-Environment-v2, Quiet-Graphite, Quiet-Graphite-v2, Quiet-Human, Quiet-Purple-2K6, Quiet-Purple-2K6-v2, River, Shiny, Shiny-Tango, Silverado, Simple, SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, W2k, boxx, c2, pOS -width-2=(str width)(subtract)(int 2) - -# 4DWM, Aquarius, Bright, Carved2, Chiro, Clearbox-in, Clearbox-look-2, Clearbox-out, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Gilouche, GiloucheIM, Maemo, Outcrop, River, Simple, Simplebox, SmoothGNOME, Tetelestai-Modern, Vista Basic, W2k, c2 -width-3=(str width)(subtract)(int 3) - -# 4DWM, Almond, Amiga, AmigaRelief, Aquarius, Carved2, Chiro, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, Crux, Maemo, MetaGrip, Outcrop, River, Sandwish, Shiny, Shiny-Tango, SmoothGNOME, Tactile, Tetelestai-Modern, Vista Basic, boxx, c2, pOS -width-4=(str width)(subtract)(int 4) - -# 4DWM, Amiga, AmigaRelief, Aquarius, Bright, Chiro, Clearbox-look-2, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, River, Shiny-Tango, Sloth , SmoothGNOME, boxx, c2, pOS -width-5=(str width)(subtract)(int 5) - -# 4DWM, Aquarius, Clearlooks, Clearlooks-2.0-blend, Clearlooks-Pinstripe, Clearlooks-RedExit, Clearlooks2-Squared, Clearlooks2-Squared-Berries, ClearlooksWithACherryOnTop, EasyListening, MWM, MetaGrip, Shiny, Shiny-Tango, Vista Basic, W2k -width-6=(str width)(subtract)(int 6) - -# 4DWM, MWM, MetaGrip, Outcrop, Shiny, Shiny-Tango, pOS -width-7=(str width)(subtract)(int 7) - -# Maemo -width-70=(str width)(subtract)(int 70) - -# Maemo -width-72=(str width)(subtract)(int 72) - -# Almond, Outcrop, W2k, pOS -width-8=(str width)(subtract)(int 8) - -# 4DWM, Almond, Maemo, Outcrop, pOS -width-9=(str width)(subtract)(int 9) - -# Atlanta, Carved2, Chiro, Metabox, Redmond, River, SmoothGNOME, Tetelestai-Modern, c2 -width-ButtonIPad=(str width)(subtract)(str ButtonIPad) - -# Carved2 -width-ButtonIPad + 1=(str width)(subtract)(str ButtonIPad)(add)(int 1) - -# Simple -width-ButtonIPad + 2=(str width)(subtract)(str ButtonIPad)(add)(int 2) - -# Chiro, River, c2 -width-ButtonIPad - 3=(str width)(subtract)(str ButtonIPad)(subtract)(int 3) - -# Carved2, Chiro, River, c2 -width-ButtonIPad*2=(str width)(subtract)(str ButtonIPad)(multiply)(int 2) - -# Simple -width-ButtonIPad*2 + 2=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(add)(int 2) - -# Carved2 -width-ButtonIPad*2+1=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(add)(int 1) - -# Atlanta, Chiro, Metabox, Redmond, River, SmoothGNOME, Tetelestai-Modern, c2 -width-ButtonIPad*2-1=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 1) - -# Bright -width-ButtonIPad*2-2=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 2) - -# Chiro, River, c2 -width-ButtonIPad*2-5=(str width)(subtract)(str ButtonIPad)(multiply)(int 2)(subtract)(int 5) - -# Bright, Chiro, Metabox, River, c2 -width-ButtonIPad-1=(str width)(subtract)(str ButtonIPad)(subtract)(int 1) - -# Clearbox-look-2 -width-ButtonPad=(str width)(subtract)(str ButtonPad) - -# Clearbox-look-2 -width-ButtonPad*2+1=(str width)(subtract)(str ButtonPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -width-ButtonPad*2-1=(str width)(subtract)(str ButtonPad)(multiply)(int 2)(subtract)(int 1) - -# Clearbox-look-2 -width-ButtonPad+1=(str width)(subtract)(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -width-ButtonPad-1=(str width)(subtract)(str ButtonPad)(subtract)(int 1) - -# Clearbox-look-2 -width-ButtonPad-2=(str width)(subtract)(str ButtonPad)(subtract)(int 2) - -# Clearbox-look-2 -width-PrelightPad=(str width)(subtract)(str PrelightPad) - -# Clearbox-look-2 -width-PrelightPad*2+1=(str width)(subtract)(str PrelightPad)(multiply)(int 2)(add)(int 1) - -# Clearbox-look-2 -width-PrelightPad*2-1=(str width)(subtract)(str PrelightPad)(multiply)(int 2)(subtract)(int 1) - -# Clearbox-look-2 -width-PrelightPad+1=(str width)(subtract)(str PrelightPad)(add)(int 1) - -# Clearbox-look-2 -width-PrelightPad-1=(str width)(subtract)(str PrelightPad)(subtract)(int 1) - -# Clearbox-look-2 -width-PrelightPad-2=(str width)(subtract)(str PrelightPad)(subtract)(int 2) - -# Atlanta, Outcrop, Simple -width-SpacerWidth=(str width)(subtract)(str SpacerWidth) - -# Bright -width-SpacerWidth+2=(str width)(subtract)(str SpacerWidth)(add)(int 2) - -# Bright -width-SpacerWidth+3=(str width)(subtract)(str SpacerWidth)(add)(int 3) - -# Bright -width-SpacerWidth-2=(str width)(subtract)(str SpacerWidth)(subtract)(int 2) - -# Chiro -width-left_width=(str width)(subtract)(str left_width) - -# Atlanta, Bright, Metabox, Simple, SmoothGNOME, TangoDance, Tetelestai-Modern -width-left_width-right_width+1=(str width)(subtract)(str left_width)(subtract)(str right_width)(add)(int 1) - -# Maemo, Mista -width-object_width=(str width)(subtract)(str object_width) - -# 4DWM, Gilouche, GiloucheIM, MWM, SmoothGNOME, Tetelestai-Modern -width-right_width=(str width)(subtract)(str right_width) - -# 4DWM, MWM, Tetelestai-Modern -width-right_width+1=(str width)(subtract)(str right_width)(add)(int 1) - -# 4DWM -width-right_width/2=(str width)(subtract)(str right_width)(divide)(int 2) - -# 4DWM, MWM -width-top_height=(str width)(subtract)(str top_height) - -# 4DWM -width-top_height+1=(str width)(subtract)(str top_height)(add)(int 1) - -# 4DWM -width-top_height+2=(str width)(subtract)(str top_height)(add)(int 2) - -# 4DWM, MWM -width-top_height-1=(str width)(subtract)(str top_height)(subtract)(int 1) - -# Bentham, Clearbox-in, Clearbox-look-2, Clearbox-out, Simplebox, Sloth -width/2=(str width)(divide)(int 2) - -# Bentham -width/2 + width/4 - 1=(str width)(divide)(int 2)(add)(str width)(divide)(int 4)(subtract)(int 1) - -# Bentham -width/2 + width/4 - 2=(str width)(divide)(int 2)(add)(str width)(divide)(int 4)(subtract)(int 2) - -# Bentham -width/2 - width/4 + 1=(str width)(divide)(int 2)(subtract)(str width)(divide)(int 4)(add)(int 1) - -# Clearbox-in, Clearbox-out, MWM, Simplebox -width/2+1=(str width)(divide)(int 2)(add)(int 1) - -# Clearbox-in, Clearbox-out, Metabox, Simplebox -width/2+2=(str width)(divide)(int 2)(add)(int 2) - -# 4DWM, Clearbox-in, Clearbox-out, Simplebox -width/2+3=(str width)(divide)(int 2)(add)(int 3) - -# Clearbox-in, Clearbox-out, Simplebox -width/2+4=(str width)(divide)(int 2)(add)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -width/2+5=(str width)(divide)(int 2)(add)(int 5) - -# Aquarius -width/2+height/4=(str width)(divide)(int 2)(add)(str height)(divide)(int 4) - -# Aquarius -width/2+height/4+1=(str width)(divide)(int 2)(add)(str height)(divide)(int 4)(add)(int 1) - -# Aquarius -width/2+height/4+2=(str width)(divide)(int 2)(add)(str height)(divide)(int 4)(add)(int 2) - -# Clearbox-look-2 -width/2+width/2-ButtonPad+1=(str width)(divide)(int 2)(add)(str width)(divide)(int 2)(subtract)(str ButtonPad)(add)(int 1) - -# Clearbox-look-2 -width/2+width/2-PrelightPad+1=(str width)(divide)(int 2)(add)(str width)(divide)(int 2)(subtract)(str PrelightPad)(add)(int 1) - -# 4DWM, Clearbox-in, Clearbox-look-2, Clearbox-out, MWM, Simplebox -width/2-1=(str width)(divide)(int 2)(subtract)(int 1) - -# 4DWM, Clearbox-in, Clearbox-out, MWM, Metabox, Simplebox -width/2-2=(str width)(divide)(int 2)(subtract)(int 2) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-3=(str width)(divide)(int 2)(subtract)(int 3) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-4=(str width)(divide)(int 2)(subtract)(int 4) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-5=(str width)(divide)(int 2)(subtract)(int 5) - -# Clearbox-in, Clearbox-out, Simplebox -width/2-6=(str width)(divide)(int 2)(subtract)(int 6) - -# Aquarius -width/2-height/4=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 4) - -# Aquarius -width/2-height/4+1=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 1) - -# Aquarius -width/2-height/4+2=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 4)(add)(int 2) - -# Aquarius -width/2-height/6=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 6) - -# Aquarius -width/2-height/6+1=(str width)(divide)(int 2)(subtract)(str height)(divide)(int 6)(add)(int 1) - -# Bentham -width/2-width/8-1=(str width)(divide)(int 2)(subtract)(str width)(divide)(int 8)(subtract)(int 1) - -# Bentham -width/2-width/8-2=(str width)(divide)(int 2)(subtract)(str width)(divide)(int 8)(subtract)(int 2) - -# Bentham -width/4=(str width)(divide)(int 4) - -# Bentham -width/4+2=(str width)(divide)(int 4)(add)(int 2) - -########################### - -# EOF tokentest.ini diff --git a/tools/xlib.py b/tools/xlib.py deleted file mode 100644 index 4a244c4f6..000000000 --- a/tools/xlib.py +++ /dev/null @@ -1,43 +0,0 @@ -# Very simple Xlib-based client in Python. -# Copyright (c) 2008 Thomas Thurman ; GPL 2.0 or later. -# Originally based around example code in python-xlib -# by Peter Liljenberg . - -import sys - -from Xlib import X -from Xlib.protocol import display -from Xlib.protocol.request import * - -display = display.Display() -screen = display.info.roots[display.default_screen] -window = display.allocate_resource_id() -gc = display.allocate_resource_id() - -CreateWindow(display, None, - depth = screen.root_depth, - wid = window, - parent = screen.root, - x = 100, y = 100, width = 250, height = 250, border_width = 2, - window_class = X.InputOutput, visual = X.CopyFromParent, - background_pixel = screen.white_pixel, - event_mask = (X.ExposureMask | - X.StructureNotifyMask | - X.ButtonPressMask | - X.ButtonReleaseMask | - X.Button1MotionMask), - colormap = X.CopyFromParent) - -CreateGC(display, None, gc, window) - -MapWindow(display, None, window) - -while 1: - event = display.next_event() - - if event.type == X.DestroyNotify: - sys.exit(0) - - print event - -