Compare commits
	
		
			33 Commits
		
	
	
		
			wip/nielsd
			...
			wip/displa
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 78b41e542b | ||
|   | 13557b39d0 | ||
|   | 39aecd2dde | ||
|   | c564515ef6 | ||
|   | d7b2ea37b1 | ||
|   | 0a1e0fe132 | ||
|   | 1a0513ea61 | ||
|   | 028fa6cd4e | ||
|   | 194b11186c | ||
|   | 40f064abc3 | ||
|   | 27b8716795 | ||
|   | 50b44d0445 | ||
|   | c74d40ac41 | ||
|   | c21f7d43bd | ||
|   | 80e0b4aac9 | ||
|   | 12cd4c216b | ||
|   | 91d193e5e8 | ||
|   | f82f3ef67b | ||
|   | 6125b3fa7e | ||
|   | 169780346b | ||
|   | 9b255f9292 | ||
|   | 60e11fbae3 | ||
|   | 355f0258b1 | ||
|   | 09984bb56d | ||
|   | f48ddb3683 | ||
|   | 9ac92336c9 | ||
|   | 2bc5e89a5e | ||
|   | a413bc106f | ||
|   | b04ac57f02 | ||
|   | c3a08ee589 | ||
|   | 1fdb161f54 | ||
|   | f3d1653f13 | ||
|   | 3093b5c95d | 
| @@ -75,6 +75,8 @@ MUTTER_PC_MODULES=" | ||||
|    xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0 | ||||
|    $CLUTTER_PACKAGE >= 1.14.3 | ||||
|    cogl-1.0 >= 1.13.3 | ||||
|    upower-glib > 0.9.11 | ||||
|    gnome-desktop-3.0 | ||||
| " | ||||
|  | ||||
| GLIB_GSETTINGS | ||||
|   | ||||
| @@ -19,7 +19,7 @@ INCLUDES=								\ | ||||
| 	-DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\"		\ | ||||
| 	-DMUTTER_PKGDATADIR=\"$(pkgdatadir)\"				\ | ||||
| 	-DMUTTER_DATADIR=\"$(datadir)\"					\ | ||||
| 	-DG_LOG_DOMAIN=\"mutter\"					\ | ||||
| 	-DG_LOG_DOMAIN=\"Mutter\"					\ | ||||
| 	-DSN_API_NOT_YET_FROZEN=1					\ | ||||
| 	-DMUTTER_MAJOR_VERSION=$(MUTTER_MAJOR_VERSION)			\ | ||||
| 	-DMUTTER_MINOR_VERSION=$(MUTTER_MINOR_VERSION)			\ | ||||
| @@ -30,6 +30,7 @@ INCLUDES=								\ | ||||
| 	-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" | ||||
|  | ||||
| mutter_built_sources = \ | ||||
| 	$(dbus_xrandr_built_sources)	\ | ||||
| 	mutter-enum-types.h \ | ||||
| 	mutter-enum-types.c | ||||
|  | ||||
| @@ -94,6 +95,8 @@ libmutter_la_SOURCES =				\ | ||||
| 	ui/draw-workspace.h			\ | ||||
| 	core/edge-resistance.c			\ | ||||
| 	core/edge-resistance.h			\ | ||||
| 	core/edid-parse.c			\ | ||||
| 	core/edid.h				\ | ||||
| 	core/errors.c				\ | ||||
| 	meta/errors.h				\ | ||||
| 	core/frame.c				\ | ||||
| @@ -110,6 +113,11 @@ libmutter_la_SOURCES =				\ | ||||
| 	core/keybindings.c			\ | ||||
| 	core/keybindings-private.h		\ | ||||
| 	core/main.c				\ | ||||
| 	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				\ | ||||
| @@ -323,3 +331,12 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in | ||||
| 	  $(libmutterinclude_base_headers) ) >> xgen-tetc && \ | ||||
| 	cp xgen-tetc mutter-enum-types.c && \ | ||||
| 	rm -f xgen-tetc | ||||
|  | ||||
| dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h | ||||
|  | ||||
| $(dbus_xrandr_built_sources) : Makefile.am xrandr.xml | ||||
| 	$(AM_V_GEN)gdbus-codegen								\ | ||||
| 		--interface-prefix org.gnome.Mutter					\ | ||||
| 		--c-namespace MetaDBus							\ | ||||
| 		--generate-c-code meta-dbus-xrandr					\ | ||||
| 		xrandr.xml | ||||
|   | ||||
| @@ -73,13 +73,12 @@ void | ||||
| meta_background_group_set_visible_region (MetaBackgroundGroup *self, | ||||
|                                           cairo_region_t      *region) | ||||
| { | ||||
|   GList *children, *l; | ||||
|   ClutterActorIter iter; | ||||
|   ClutterActor *actor; | ||||
|  | ||||
|   children = clutter_actor_get_children (CLUTTER_ACTOR (self)); | ||||
|   for (l = children; l; l = l->next) | ||||
|   clutter_actor_iter_init (&iter, CLUTTER_ACTOR (self)); | ||||
|   while (clutter_actor_iter_next (&iter, &actor)) | ||||
|     { | ||||
|       ClutterActor *actor = l->data; | ||||
|  | ||||
|       if (META_IS_BACKGROUND_ACTOR (actor)) | ||||
|         { | ||||
|           meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (actor), region); | ||||
| @@ -96,7 +95,6 @@ meta_background_group_set_visible_region (MetaBackgroundGroup *self, | ||||
|           cairo_region_translate (region, x, y); | ||||
|         } | ||||
|     } | ||||
|   g_list_free (children); | ||||
| } | ||||
|  | ||||
| ClutterActor * | ||||
|   | ||||
| @@ -85,12 +85,20 @@ meta_plugin_manager_load (const gchar       *plugin_name) | ||||
|   g_free (path); | ||||
| } | ||||
|  | ||||
| static void | ||||
| on_confirm_display_change (MetaMonitorManager *monitors, | ||||
|                            MetaPluginManager  *plugin_mgr) | ||||
| { | ||||
|   meta_plugin_manager_confirm_display_change (plugin_mgr); | ||||
| } | ||||
|  | ||||
| MetaPluginManager * | ||||
| meta_plugin_manager_new (MetaScreen *screen) | ||||
| { | ||||
|   MetaPluginManager *plugin_mgr; | ||||
|   MetaPluginClass *klass; | ||||
|   MetaPlugin *plugin; | ||||
|   MetaMonitorManager *monitors; | ||||
|  | ||||
|   plugin_mgr = g_new0 (MetaPluginManager, 1); | ||||
|   plugin_mgr->screen = screen; | ||||
| @@ -101,6 +109,10 @@ meta_plugin_manager_new (MetaScreen *screen) | ||||
|   if (klass->start) | ||||
|     klass->start (plugin); | ||||
|  | ||||
|   monitors = meta_monitor_manager_get (); | ||||
|   g_signal_connect (monitors, "confirm-display-change", | ||||
|                     G_CALLBACK (on_confirm_display_change), plugin_mgr); | ||||
|  | ||||
|   return plugin_mgr; | ||||
| } | ||||
|  | ||||
| @@ -320,3 +332,15 @@ meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr, | ||||
|   else | ||||
|     return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE; | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr) | ||||
| { | ||||
|   MetaPlugin *plugin = plugin_mgr->plugin; | ||||
|   MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin); | ||||
|  | ||||
|   if (klass->confirm_display_change) | ||||
|     return klass->confirm_display_change (plugin); | ||||
|   else | ||||
|     return meta_plugin_complete_display_change (plugin, TRUE); | ||||
| } | ||||
|   | ||||
| @@ -73,4 +73,6 @@ gboolean meta_plugin_manager_filter_keybinding (MetaPluginManager  *mgr, | ||||
| gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr, | ||||
|                                             XEvent            *xev); | ||||
|  | ||||
| void     meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -41,6 +41,7 @@ | ||||
|  | ||||
| #include "compositor-private.h" | ||||
| #include "meta-window-actor-private.h" | ||||
| #include "monitor-private.h" | ||||
|  | ||||
| G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT); | ||||
|  | ||||
| @@ -338,3 +339,13 @@ meta_plugin_get_screen (MetaPlugin *plugin) | ||||
|  | ||||
|   return priv->screen; | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_plugin_complete_display_change (MetaPlugin *plugin, | ||||
|                                      gboolean    ok) | ||||
| { | ||||
|   MetaMonitorManager *manager; | ||||
|  | ||||
|   manager = meta_monitor_manager_get (); | ||||
|   meta_monitor_manager_confirm_configuration (manager, ok); | ||||
| } | ||||
|   | ||||
| @@ -369,10 +369,10 @@ meta_window_actor_constructed (GObject *object) | ||||
|        */ | ||||
|       g_object_ref (priv->actor); | ||||
|  | ||||
|       g_signal_connect (window, "notify::decorated", | ||||
|                         G_CALLBACK (window_decorated_notify), self); | ||||
|       g_signal_connect (window, "notify::appears-focused", | ||||
|                         G_CALLBACK (window_appears_focused_notify), self); | ||||
|       g_signal_connect_object (window, "notify::decorated", | ||||
|                                G_CALLBACK (window_decorated_notify), self, 0); | ||||
|       g_signal_connect_object (window, "notify::appears-focused", | ||||
|                                G_CALLBACK (window_appears_focused_notify), self, 0); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|   | ||||
| @@ -24,6 +24,8 @@ | ||||
| #include <meta/meta-plugin.h> | ||||
| #include <meta/window.h> | ||||
| #include <meta/util.h> | ||||
| #include <meta/meta-background-group.h> | ||||
| #include <meta/meta-background-actor.h> | ||||
|  | ||||
| #include <libintl.h> | ||||
| #define _(x) dgettext (GETTEXT_PACKAGE, x) | ||||
| @@ -98,6 +100,8 @@ static void kill_window_effects   (MetaPlugin      *plugin, | ||||
|                                    MetaWindowActor *actor); | ||||
| static void kill_switch_workspace (MetaPlugin      *plugin); | ||||
|  | ||||
| static void confirm_display_change (MetaPlugin *plugin); | ||||
|  | ||||
| static const MetaPluginInfo * plugin_info (MetaPlugin *plugin); | ||||
|  | ||||
| META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin); | ||||
| @@ -113,6 +117,8 @@ struct _MetaDefaultPluginPrivate | ||||
|   ClutterActor          *desktop1; | ||||
|   ClutterActor          *desktop2; | ||||
|  | ||||
|   ClutterActor          *background_group; | ||||
|  | ||||
|   MetaPluginInfo         info; | ||||
| }; | ||||
|  | ||||
| @@ -203,6 +209,7 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass) | ||||
|   plugin_class->plugin_info      = plugin_info; | ||||
|   plugin_class->kill_window_effects   = kill_window_effects; | ||||
|   plugin_class->kill_switch_workspace = kill_switch_workspace; | ||||
|   plugin_class->confirm_display_change = confirm_display_change; | ||||
|  | ||||
|   g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate)); | ||||
| } | ||||
| @@ -299,9 +306,58 @@ show_stage (MetaPlugin *plugin) | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| on_monitors_changed (MetaScreen *screen, | ||||
|                      MetaPlugin *plugin) | ||||
| { | ||||
|   MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin); | ||||
|   int i, n; | ||||
|  | ||||
|   clutter_actor_destroy_all_children (self->priv->background_group); | ||||
|  | ||||
|   n = meta_screen_get_n_monitors (screen); | ||||
|   for (i = 0; i < n; i++) | ||||
|     { | ||||
|       MetaRectangle rect; | ||||
|       ClutterActor *background; | ||||
|       ClutterColor color; | ||||
|  | ||||
|       meta_screen_get_monitor_geometry (screen, i, &rect); | ||||
|  | ||||
|       background = meta_background_actor_new (); | ||||
|  | ||||
|       clutter_actor_set_position (background, rect.x, rect.y); | ||||
|       clutter_actor_set_size (background, rect.width, rect.height); | ||||
|  | ||||
|       /* Don't use rand() here, mesa calls srand() internally when | ||||
|          parsing the driconf XML, but it's nice if the colors are | ||||
|          reproducible. | ||||
|       */ | ||||
|       clutter_color_init (&color, | ||||
|                           g_random_int () % 255, | ||||
|                           g_random_int () % 255, | ||||
|                           g_random_int () % 255, | ||||
|                           255); | ||||
|       clutter_actor_set_background_color (background, &color); | ||||
|  | ||||
|       clutter_actor_add_child (self->priv->background_group, background); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| start (MetaPlugin *plugin) | ||||
| { | ||||
|   MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin); | ||||
|   MetaScreen *screen = meta_plugin_get_screen (plugin); | ||||
|  | ||||
|   self->priv->background_group = meta_background_group_new (); | ||||
|   clutter_actor_insert_child_below (meta_get_window_group_for_screen (screen), | ||||
|                                     self->priv->background_group, NULL); | ||||
|  | ||||
|   g_signal_connect (screen, "monitors-changed", | ||||
|                     G_CALLBACK (on_monitors_changed), plugin); | ||||
|   on_monitors_changed (screen, plugin); | ||||
|  | ||||
|   meta_later_add (META_LATER_BEFORE_REDRAW, | ||||
|                   (GSourceFunc) show_stage, | ||||
|                   plugin, | ||||
| @@ -782,3 +838,33 @@ plugin_info (MetaPlugin *plugin) | ||||
|  | ||||
|   return &priv->info; | ||||
| } | ||||
|  | ||||
| static void | ||||
| on_dialog_closed (GPid     pid, | ||||
|                   gint     status, | ||||
|                   gpointer user_data) | ||||
| { | ||||
|   MetaPlugin *plugin = user_data; | ||||
|   gboolean ok; | ||||
|  | ||||
|   ok = g_spawn_check_exit_status (status, NULL); | ||||
|   meta_plugin_complete_display_change (plugin, ok); | ||||
| } | ||||
|  | ||||
| static void | ||||
| confirm_display_change (MetaPlugin *plugin) | ||||
| { | ||||
|   GPid pid; | ||||
|  | ||||
|   pid = meta_show_dialog ("--question", | ||||
|                           "Does the display look OK?", | ||||
|                           "20", | ||||
|                           NULL, | ||||
|                           "_Keep This Configuration", | ||||
|                           "_Restore Previous Configuration", | ||||
|                           "preferences-desktop-display", | ||||
|                           0, | ||||
|                           NULL, NULL); | ||||
|  | ||||
|   g_child_watch_add (pid, on_dialog_closed, plugin); | ||||
| } | ||||
|   | ||||
| @@ -2146,6 +2146,7 @@ event_callback (XEvent   *event, | ||||
|   gboolean bypass_compositor; | ||||
|   gboolean filter_out_event; | ||||
|   XIEvent *input_event; | ||||
|   MetaMonitorManager *monitor; | ||||
|  | ||||
|   display = data; | ||||
|    | ||||
| @@ -2157,6 +2158,14 @@ event_callback (XEvent   *event, | ||||
| #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; | ||||
| @@ -2822,32 +2831,10 @@ event_callback (XEvent   *event, | ||||
|                 meta_stack_tracker_configure_event (screen->stack_tracker, | ||||
|                                                     &event->xconfigure); | ||||
|             } | ||||
|  | ||||
|           if (window && window->override_redirect) | ||||
|             meta_window_configure_notify (window, &event->xconfigure); | ||||
|           else | ||||
|             /* Handle screen resize */ | ||||
|             { | ||||
|               MetaScreen *screen; | ||||
|  | ||||
|               screen = meta_display_screen_for_root (display, | ||||
|                                                      event->xconfigure.window); | ||||
|  | ||||
|               if (screen != NULL) | ||||
|                 { | ||||
| #ifdef HAVE_RANDR | ||||
|                   /* do the resize the official way */ | ||||
|                   XRRUpdateConfiguration (event); | ||||
| #else | ||||
|                   /* poke around in Xlib */ | ||||
|                   screen->xscreen->width   = event->xconfigure.width; | ||||
|                   screen->xscreen->height  = event->xconfigure.height; | ||||
| #endif | ||||
| 	       | ||||
|                   meta_screen_resize (screen,  | ||||
|                                       event->xconfigure.width, | ||||
|                                       event->xconfigure.height); | ||||
|                 } | ||||
|             } | ||||
|           break; | ||||
|         case ConfigureRequest: | ||||
|           /* This comment and code is found in both twm and fvwm */ | ||||
|   | ||||
							
								
								
									
										540
									
								
								src/core/edid-parse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								src/core/edid-parse.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,540 @@ | ||||
| /* | ||||
|  * Copyright 2007 Red Hat, Inc. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * on the rights to use, copy, modify, merge, publish, distribute, sub | ||||
|  * license, and/or sell copies of the Software, and to permit persons to whom | ||||
|  * the Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice (including the next | ||||
|  * paragraph) shall be included in all copies or substantial portions of the | ||||
|  * Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL | ||||
|  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
|  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
|  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /* Author: Soren Sandmann <sandmann@redhat.com> */ | ||||
|  | ||||
| #include "edid.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include <glib.h> | ||||
|  | ||||
| static int | ||||
| get_bit (int in, int bit) | ||||
| { | ||||
|     return (in & (1 << bit)) >> bit; | ||||
| } | ||||
|  | ||||
| static int | ||||
| get_bits (int in, int begin, int end) | ||||
| { | ||||
|     int mask = (1 << (end - begin + 1)) - 1; | ||||
|      | ||||
|     return (in >> begin) & mask; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_header (const uchar *edid) | ||||
| { | ||||
|     if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0) | ||||
| 	return TRUE; | ||||
|     return FALSE; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     int is_model_year; | ||||
|      | ||||
|     /* Manufacturer Code */ | ||||
|     info->manufacturer_code[0]  = get_bits (edid[0x08], 2, 6); | ||||
|     info->manufacturer_code[1]  = get_bits (edid[0x08], 0, 1) << 3; | ||||
|     info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7); | ||||
|     info->manufacturer_code[2]  = get_bits (edid[0x09], 0, 4); | ||||
|     info->manufacturer_code[3]  = '\0'; | ||||
|      | ||||
|     info->manufacturer_code[0] += 'A' - 1; | ||||
|     info->manufacturer_code[1] += 'A' - 1; | ||||
|     info->manufacturer_code[2] += 'A' - 1; | ||||
|  | ||||
|     /* Product Code */ | ||||
|     info->product_code = edid[0x0b] << 8 | edid[0x0a]; | ||||
|  | ||||
|     /* Serial Number */ | ||||
|     info->serial_number = | ||||
| 	edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24; | ||||
|  | ||||
|     /* Week and Year */ | ||||
|     is_model_year = FALSE; | ||||
|     switch (edid[0x10]) | ||||
|     { | ||||
|     case 0x00: | ||||
| 	info->production_week = -1; | ||||
| 	break; | ||||
|  | ||||
|     case 0xff: | ||||
| 	info->production_week = -1; | ||||
| 	is_model_year = TRUE; | ||||
| 	break; | ||||
|  | ||||
|     default: | ||||
| 	info->production_week = edid[0x10]; | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     if (is_model_year) | ||||
|     { | ||||
| 	info->production_year = -1; | ||||
| 	info->model_year = 1990 + edid[0x11]; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	info->production_year = 1990 + edid[0x11]; | ||||
| 	info->model_year = -1; | ||||
|     } | ||||
|  | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_edid_version (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     info->major_version = edid[0x12]; | ||||
|     info->minor_version = edid[0x13]; | ||||
|  | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_display_parameters (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     /* Digital vs Analog */ | ||||
|     info->is_digital = get_bit (edid[0x14], 7); | ||||
|  | ||||
|     if (info->is_digital) | ||||
|     { | ||||
| 	int bits; | ||||
| 	 | ||||
| 	static const int bit_depth[8] = | ||||
| 	{ | ||||
| 	    -1, 6, 8, 10, 12, 14, 16, -1 | ||||
| 	}; | ||||
|  | ||||
| 	static const Interface interfaces[6] = | ||||
| 	{ | ||||
| 	    UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT | ||||
| 	}; | ||||
|  | ||||
| 	bits = get_bits (edid[0x14], 4, 6); | ||||
| 	info->connector.digital.bits_per_primary = bit_depth[bits]; | ||||
|  | ||||
| 	bits = get_bits (edid[0x14], 0, 3); | ||||
| 	 | ||||
| 	if (bits <= 5) | ||||
| 	    info->connector.digital.interface = interfaces[bits]; | ||||
| 	else | ||||
| 	    info->connector.digital.interface = UNDEFINED; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	int bits = get_bits (edid[0x14], 5, 6); | ||||
| 	 | ||||
| 	static const double levels[][3] = | ||||
| 	{ | ||||
| 	    { 0.7,   0.3,    1.0 }, | ||||
| 	    { 0.714, 0.286,  1.0 }, | ||||
| 	    { 1.0,   0.4,    1.4 }, | ||||
| 	    { 0.7,   0.0,    0.7 }, | ||||
| 	}; | ||||
|  | ||||
| 	info->connector.analog.video_signal_level = levels[bits][0]; | ||||
| 	info->connector.analog.sync_signal_level = levels[bits][1]; | ||||
| 	info->connector.analog.total_signal_level = levels[bits][2]; | ||||
|  | ||||
| 	info->connector.analog.blank_to_black = get_bit (edid[0x14], 4); | ||||
|  | ||||
| 	info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3); | ||||
| 	info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2); | ||||
| 	info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1); | ||||
|  | ||||
| 	info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0); | ||||
|     } | ||||
|  | ||||
|     /* Screen Size / Aspect Ratio */ | ||||
|     if (edid[0x15] == 0 && edid[0x16] == 0) | ||||
|     { | ||||
| 	info->width_mm = -1; | ||||
| 	info->height_mm = -1; | ||||
| 	info->aspect_ratio = -1.0; | ||||
|     } | ||||
|     else if (edid[0x16] == 0) | ||||
|     { | ||||
| 	info->width_mm = -1; | ||||
| 	info->height_mm = -1;  | ||||
| 	info->aspect_ratio = 100.0 / (edid[0x15] + 99); | ||||
|     } | ||||
|     else if (edid[0x15] == 0) | ||||
|     { | ||||
| 	info->width_mm = -1; | ||||
| 	info->height_mm = -1; | ||||
| 	info->aspect_ratio = 100.0 / (edid[0x16] + 99); | ||||
| 	info->aspect_ratio = 1/info->aspect_ratio; /* portrait */ | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	info->width_mm = 10 * edid[0x15]; | ||||
| 	info->height_mm = 10 * edid[0x16]; | ||||
|     } | ||||
|  | ||||
|     /* Gamma */ | ||||
|     if (edid[0x17] == 0xFF) | ||||
| 	info->gamma = -1.0; | ||||
|     else | ||||
| 	info->gamma = (edid[0x17] + 100.0) / 100.0; | ||||
|  | ||||
|     /* Features */ | ||||
|     info->standby = get_bit (edid[0x18], 7); | ||||
|     info->suspend = get_bit (edid[0x18], 6); | ||||
|     info->active_off = get_bit (edid[0x18], 5); | ||||
|  | ||||
|     if (info->is_digital) | ||||
|     { | ||||
| 	info->connector.digital.rgb444 = TRUE; | ||||
| 	if (get_bit (edid[0x18], 3)) | ||||
| 	    info->connector.digital.ycrcb444 = 1; | ||||
| 	if (get_bit (edid[0x18], 4)) | ||||
| 	    info->connector.digital.ycrcb422 = 1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	int bits = get_bits (edid[0x18], 3, 4); | ||||
| 	ColorType color_type[4] = | ||||
| 	{ | ||||
| 	    MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR | ||||
| 	}; | ||||
|  | ||||
| 	info->connector.analog.color_type = color_type[bits]; | ||||
|     } | ||||
|  | ||||
|     info->srgb_is_standard = get_bit (edid[0x18], 2); | ||||
|  | ||||
|     /* In 1.3 this is called "has preferred timing" */ | ||||
|     info->preferred_timing_includes_native = get_bit (edid[0x18], 1); | ||||
|  | ||||
|     /* FIXME: In 1.3 this indicates whether the monitor accepts GTF */ | ||||
|     info->continuous_frequency = get_bit (edid[0x18], 0); | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static double | ||||
| decode_fraction (int high, int low) | ||||
| { | ||||
|     double result = 0.0; | ||||
|     int i; | ||||
|  | ||||
|     high = (high << 2) | low; | ||||
|  | ||||
|     for (i = 0; i < 10; ++i) | ||||
| 	result += get_bit (high, i) * pow (2, i - 10); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_color_characteristics (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7)); | ||||
|     info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4)); | ||||
|     info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3)); | ||||
|     info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1)); | ||||
|     info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7)); | ||||
|     info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5)); | ||||
|     info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3)); | ||||
|     info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1)); | ||||
|  | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_established_timings (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     static const Timing established[][8] =  | ||||
|     { | ||||
| 	{ | ||||
| 	    { 800, 600, 60 }, | ||||
| 	    { 800, 600, 56 }, | ||||
| 	    { 640, 480, 75 }, | ||||
| 	    { 640, 480, 72 }, | ||||
| 	    { 640, 480, 67 }, | ||||
| 	    { 640, 480, 60 }, | ||||
| 	    { 720, 400, 88 }, | ||||
| 	    { 720, 400, 70 } | ||||
| 	}, | ||||
| 	{ | ||||
| 	    { 1280, 1024, 75 }, | ||||
| 	    { 1024, 768, 75 }, | ||||
| 	    { 1024, 768, 70 }, | ||||
| 	    { 1024, 768, 60 }, | ||||
| 	    { 1024, 768, 87 }, | ||||
| 	    { 832, 624, 75 }, | ||||
| 	    { 800, 600, 75 }, | ||||
| 	    { 800, 600, 72 } | ||||
| 	}, | ||||
| 	{ | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 0, 0, 0 }, | ||||
| 	    { 1152, 870, 75 } | ||||
| 	}, | ||||
|     }; | ||||
|  | ||||
|     int i, j, idx; | ||||
|  | ||||
|     idx = 0; | ||||
|     for (i = 0; i < 3; ++i) | ||||
|     { | ||||
| 	for (j = 0; j < 8; ++j) | ||||
| 	{ | ||||
| 	    int byte = edid[0x23 + i]; | ||||
|  | ||||
| 	    if (get_bit (byte, j) && established[i][j].frequency != 0) | ||||
| 		info->established[idx++] = established[i][j]; | ||||
| 	} | ||||
|     } | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_standard_timings (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     int i; | ||||
|      | ||||
|     for (i = 0; i < 8; i++) | ||||
|     { | ||||
| 	int first = edid[0x26 + 2 * i]; | ||||
| 	int second = edid[0x27 + 2 * i]; | ||||
|  | ||||
| 	if (first != 0x01 && second != 0x01) | ||||
| 	{ | ||||
| 	    int w = 8 * (first + 31); | ||||
| 	    int h = 0; | ||||
|  | ||||
| 	    switch (get_bits (second, 6, 7)) | ||||
| 	    { | ||||
| 	    case 0x00: h = (w / 16) * 10; break; | ||||
| 	    case 0x01: h = (w / 4) * 3; break; | ||||
| 	    case 0x02: h = (w / 5) * 4; break; | ||||
| 	    case 0x03: h = (w / 16) * 9; break; | ||||
| 	    } | ||||
|  | ||||
| 	    info->standard[i].width = w; | ||||
| 	    info->standard[i].height = h; | ||||
| 	    info->standard[i].frequency = get_bits (second, 0, 5) + 60; | ||||
| 	} | ||||
|     } | ||||
|      | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| decode_lf_string (const uchar *s, int n_chars, char *result) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < n_chars; ++i) | ||||
|     { | ||||
| 	if (s[i] == 0x0a) | ||||
| 	{ | ||||
| 	    *result++ = '\0'; | ||||
| 	    break; | ||||
| 	} | ||||
| 	else if (s[i] == 0x00) | ||||
| 	{ | ||||
| 	    /* Convert embedded 0's to spaces */ | ||||
| 	    *result++ = ' '; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    *result++ = s[i]; | ||||
| 	} | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| decode_display_descriptor (const uchar *desc, | ||||
| 			   MonitorInfo *info) | ||||
| { | ||||
|     switch (desc[0x03]) | ||||
|     { | ||||
|     case 0xFC: | ||||
| 	decode_lf_string (desc + 5, 13, info->dsc_product_name); | ||||
| 	break; | ||||
|     case 0xFF: | ||||
| 	decode_lf_string (desc + 5, 13, info->dsc_serial_number); | ||||
| 	break; | ||||
|     case 0xFE: | ||||
| 	decode_lf_string (desc + 5, 13, info->dsc_string); | ||||
| 	break; | ||||
|     case 0xFD: | ||||
| 	/* Range Limits */ | ||||
| 	break; | ||||
|     case 0xFB: | ||||
| 	/* Color Point */ | ||||
| 	break; | ||||
|     case 0xFA: | ||||
| 	/* Timing Identifications */ | ||||
| 	break; | ||||
|     case 0xF9: | ||||
| 	/* Color Management */ | ||||
| 	break; | ||||
|     case 0xF8: | ||||
| 	/* Timing Codes */ | ||||
| 	break; | ||||
|     case 0xF7: | ||||
| 	/* Established Timings */ | ||||
| 	break; | ||||
|     case 0x10: | ||||
| 	break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| decode_detailed_timing (const uchar *timing, | ||||
| 			DetailedTiming *detailed) | ||||
| { | ||||
|     int bits; | ||||
|     StereoType stereo[] = | ||||
|     { | ||||
| 	NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT, | ||||
| 	TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN, | ||||
| 	FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE | ||||
|     }; | ||||
|      | ||||
|     detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000; | ||||
|     detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4); | ||||
|     detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8); | ||||
|     detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4); | ||||
|     detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8); | ||||
|     detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8; | ||||
|     detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8; | ||||
|     detailed->v_front_porch = | ||||
| 	get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4; | ||||
|     detailed->v_sync = | ||||
| 	get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4; | ||||
|     detailed->width_mm =  timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8; | ||||
|     detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8; | ||||
|     detailed->right_border = timing[0x0f]; | ||||
|     detailed->top_border = timing[0x10]; | ||||
|  | ||||
|     detailed->interlaced = get_bit (timing[0x11], 7); | ||||
|  | ||||
|     /* Stereo */ | ||||
|     bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0); | ||||
|     detailed->stereo = stereo[bits]; | ||||
|  | ||||
|     /* Sync */ | ||||
|     bits = timing[0x11]; | ||||
|  | ||||
|     detailed->digital_sync = get_bit (bits, 4); | ||||
|     if (detailed->digital_sync) | ||||
|     { | ||||
| 	detailed->connector.digital.composite = !get_bit (bits, 3); | ||||
|  | ||||
| 	if (detailed->connector.digital.composite) | ||||
| 	{ | ||||
| 	    detailed->connector.digital.serrations = get_bit (bits, 2); | ||||
| 	    detailed->connector.digital.negative_vsync = FALSE; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    detailed->connector.digital.serrations = FALSE; | ||||
| 	    detailed->connector.digital.negative_vsync = !get_bit (bits, 2); | ||||
| 	} | ||||
|  | ||||
| 	detailed->connector.digital.negative_hsync = !get_bit (bits, 0); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	detailed->connector.analog.bipolar = get_bit (bits, 3); | ||||
| 	detailed->connector.analog.serrations = get_bit (bits, 2); | ||||
| 	detailed->connector.analog.sync_on_green = !get_bit (bits, 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int | ||||
| decode_descriptors (const uchar *edid, MonitorInfo *info) | ||||
| { | ||||
|     int i; | ||||
|     int timing_idx; | ||||
|      | ||||
|     timing_idx = 0; | ||||
|      | ||||
|     for (i = 0; i < 4; ++i) | ||||
|     { | ||||
| 	int index = 0x36 + i * 18; | ||||
|  | ||||
| 	if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00) | ||||
| 	{ | ||||
| 	    decode_display_descriptor (edid + index, info); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    decode_detailed_timing ( | ||||
| 		edid + index, &(info->detailed_timings[timing_idx++])); | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     info->n_detailed_timings = timing_idx; | ||||
|  | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| decode_check_sum (const uchar *edid, | ||||
| 		  MonitorInfo *info) | ||||
| { | ||||
|     int i; | ||||
|     uchar check = 0; | ||||
|  | ||||
|     for (i = 0; i < 128; ++i) | ||||
| 	check += edid[i]; | ||||
|  | ||||
|     info->checksum = check; | ||||
| } | ||||
|  | ||||
| MonitorInfo * | ||||
| decode_edid (const uchar *edid) | ||||
| { | ||||
|     MonitorInfo *info = g_new0 (MonitorInfo, 1); | ||||
|  | ||||
|     decode_check_sum (edid, info); | ||||
|      | ||||
|     if (decode_header (edid) | ||||
| 	&& decode_vendor_and_product_identification (edid, info) | ||||
| 	&& decode_edid_version (edid, info) | ||||
| 	&& decode_display_parameters (edid, info) | ||||
| 	&& decode_color_characteristics (edid, info) | ||||
| 	&& decode_established_timings (edid, info) | ||||
| 	&& decode_standard_timings (edid, info) | ||||
| 	&& decode_descriptors (edid, info)) | ||||
|     { | ||||
| 	return info; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| 	g_free (info); | ||||
| 	return NULL; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										195
									
								
								src/core/edid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								src/core/edid.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | ||||
| /* edid.h | ||||
|  * | ||||
|  * Copyright 2007, 2008, Red Hat, Inc. | ||||
|  *  | ||||
|  * This file is part of the Gnome Library. | ||||
|  *  | ||||
|  * The Gnome Library is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Library General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * The Gnome 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 | ||||
|  * Library General Public License for more details. | ||||
|  *  | ||||
|  * You should have received a copy of the GNU Library General Public | ||||
|  * License along with the Gnome Library; see the file COPYING.LIB.  If not, | ||||
|  * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||||
|  * Boston, MA 02110-1301, USA. | ||||
|  *  | ||||
|  * Author: Soren Sandmann <sandmann@redhat.com> | ||||
|  */ | ||||
|  | ||||
| #ifndef EDID_H | ||||
| #define EDID_H | ||||
|  | ||||
| typedef unsigned char uchar; | ||||
| typedef struct MonitorInfo MonitorInfo; | ||||
| typedef struct Timing Timing; | ||||
| typedef struct DetailedTiming DetailedTiming; | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     UNDEFINED, | ||||
|     DVI, | ||||
|     HDMI_A, | ||||
|     HDMI_B, | ||||
|     MDDI, | ||||
|     DISPLAY_PORT | ||||
| } Interface; | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     UNDEFINED_COLOR, | ||||
|     MONOCHROME, | ||||
|     RGB, | ||||
|     OTHER_COLOR | ||||
| } ColorType; | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     NO_STEREO, | ||||
|     FIELD_RIGHT, | ||||
|     FIELD_LEFT, | ||||
|     TWO_WAY_RIGHT_ON_EVEN, | ||||
|     TWO_WAY_LEFT_ON_EVEN, | ||||
|     FOUR_WAY_INTERLEAVED, | ||||
|     SIDE_BY_SIDE | ||||
| } StereoType; | ||||
|  | ||||
| struct Timing | ||||
| { | ||||
|     int width; | ||||
|     int height; | ||||
|     int frequency; | ||||
| }; | ||||
|  | ||||
| struct DetailedTiming | ||||
| { | ||||
|     int		pixel_clock; | ||||
|     int		h_addr; | ||||
|     int		h_blank; | ||||
|     int		h_sync; | ||||
|     int		h_front_porch; | ||||
|     int		v_addr; | ||||
|     int		v_blank; | ||||
|     int		v_sync; | ||||
|     int		v_front_porch; | ||||
|     int		width_mm; | ||||
|     int		height_mm; | ||||
|     int		right_border; | ||||
|     int		top_border; | ||||
|     int		interlaced; | ||||
|     StereoType	stereo; | ||||
|  | ||||
|     int		digital_sync; | ||||
|     union | ||||
|     { | ||||
| 	struct | ||||
| 	{ | ||||
| 	    int bipolar; | ||||
| 	    int serrations; | ||||
| 	    int sync_on_green; | ||||
| 	} analog; | ||||
|  | ||||
| 	struct | ||||
| 	{ | ||||
| 	    int composite; | ||||
| 	    int serrations; | ||||
| 	    int negative_vsync; | ||||
| 	    int negative_hsync; | ||||
| 	} digital; | ||||
|     } connector; | ||||
| }; | ||||
|  | ||||
| struct MonitorInfo | ||||
| { | ||||
|     int			checksum; | ||||
|     char		manufacturer_code[4]; | ||||
|     int			product_code; | ||||
|     unsigned int	serial_number; | ||||
|      | ||||
|     int			production_week;	/* -1 if not specified */ | ||||
|     int			production_year;	/* -1 if not specified */ | ||||
|     int			model_year;		/* -1 if not specified */ | ||||
|  | ||||
|     int			major_version; | ||||
|     int			minor_version; | ||||
|  | ||||
|     int			is_digital; | ||||
|      | ||||
|     union | ||||
|     { | ||||
| 	struct | ||||
| 	{ | ||||
| 	    int		bits_per_primary; | ||||
| 	    Interface	interface; | ||||
| 	    int		rgb444; | ||||
| 	    int		ycrcb444; | ||||
| 	    int		ycrcb422; | ||||
| 	} digital; | ||||
|  | ||||
| 	struct | ||||
| 	{ | ||||
| 	    double	video_signal_level; | ||||
| 	    double	sync_signal_level; | ||||
| 	    double	total_signal_level; | ||||
|  | ||||
| 	    int		blank_to_black; | ||||
|  | ||||
| 	    int		separate_hv_sync; | ||||
| 	    int		composite_sync_on_h; | ||||
| 	    int		composite_sync_on_green; | ||||
| 	    int		serration_on_vsync; | ||||
| 	    ColorType	color_type; | ||||
| 	} analog; | ||||
|     } connector; | ||||
|  | ||||
|     int			width_mm;		/* -1 if not specified */ | ||||
|     int			height_mm;		/* -1 if not specified */ | ||||
|     double		aspect_ratio;		/* -1.0 if not specififed */ | ||||
|  | ||||
|     double		gamma;			/* -1.0 if not specified */ | ||||
|  | ||||
|     int			standby; | ||||
|     int			suspend; | ||||
|     int			active_off; | ||||
|  | ||||
|     int			srgb_is_standard; | ||||
|     int			preferred_timing_includes_native; | ||||
|     int			continuous_frequency; | ||||
|  | ||||
|     double		red_x; | ||||
|     double		red_y; | ||||
|     double		green_x; | ||||
|     double		green_y; | ||||
|     double		blue_x; | ||||
|     double		blue_y; | ||||
|     double		white_x; | ||||
|     double		white_y; | ||||
|  | ||||
|     Timing		established[24];	/* Terminated by 0x0x0 */ | ||||
|     Timing		standard[8]; | ||||
|      | ||||
|     int			n_detailed_timings; | ||||
|     DetailedTiming	detailed_timings[4];	/* If monitor has a preferred | ||||
| 						 * mode, it is the first one | ||||
| 						 * (whether it has, is | ||||
| 						 * determined by the  | ||||
| 						 * preferred_timing_includes | ||||
| 						 * bit. | ||||
| 						 */ | ||||
|  | ||||
|     /* Optional product description */ | ||||
|     char		dsc_serial_number[14]; | ||||
|     char		dsc_product_name[14]; | ||||
|     char		dsc_string[14];		/* Unspecified ASCII data */ | ||||
| }; | ||||
|  | ||||
| MonitorInfo *decode_edid (const uchar *data); | ||||
| char *make_display_name (const MonitorInfo *info); | ||||
| char *make_display_size_string (int width_mm, int height_mm); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										108
									
								
								src/core/main.c
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								src/core/main.c
									
									
									
									
									
								
							| @@ -56,6 +56,7 @@ | ||||
| #include <meta/prefs.h> | ||||
| #include <meta/compositor.h> | ||||
|  | ||||
| #include <glib-unix.h> | ||||
| #include <glib-object.h> | ||||
| #include <gdk/gdkx.h> | ||||
|  | ||||
| @@ -93,26 +94,6 @@ static GMainLoop *meta_main_loop = NULL; | ||||
| static void prefs_changed_callback (MetaPreference pref, | ||||
|                                     gpointer       data); | ||||
|  | ||||
| /** | ||||
|  * log_handler: | ||||
|  * @log_domain: the domain the error occurred in (we ignore this) | ||||
|  * @log_level: the log level so that we can filter out less | ||||
|  *             important messages | ||||
|  * @message: the message to log | ||||
|  * @user_data: arbitrary data (we ignore this) | ||||
|  * | ||||
|  * Prints log messages. If Mutter was compiled with backtrace support, | ||||
|  * also prints a backtrace (see meta_print_backtrace()). | ||||
|  */ | ||||
| static void | ||||
| log_handler (const gchar   *log_domain, | ||||
|              GLogLevelFlags log_level, | ||||
|              const gchar   *message, | ||||
|              gpointer       user_data) | ||||
| { | ||||
|   meta_warning ("Log level %d: %s\n", log_level, message); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_print_compilation_info: | ||||
|  * | ||||
| @@ -348,23 +329,8 @@ meta_finalize (void) | ||||
|                         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; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| on_sigterm (void) | ||||
| on_sigterm (gpointer user_data) | ||||
| { | ||||
|   meta_quit (META_EXIT_SUCCESS); | ||||
|   return FALSE; | ||||
| @@ -381,8 +347,7 @@ meta_init (void) | ||||
| { | ||||
|   struct sigaction act; | ||||
|   sigset_t empty_mask; | ||||
|   GIOChannel *channel; | ||||
|    | ||||
|  | ||||
|   sigemptyset (&empty_mask); | ||||
|   act.sa_handler = SIG_IGN; | ||||
|   act.sa_mask    = empty_mask; | ||||
| @@ -396,20 +361,9 @@ 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)); | ||||
|   g_unix_signal_add (SIGTERM, on_sigterm, NULL); | ||||
|  | ||||
|   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)); | ||||
|   meta_debug_init (); | ||||
|  | ||||
|   if (g_getenv ("MUTTER_VERBOSE")) | ||||
|     meta_set_verbose (TRUE); | ||||
| @@ -496,63 +450,25 @@ meta_register_with_session (void) | ||||
| int | ||||
| meta_run (void) | ||||
| { | ||||
|   const gchar *log_domains[] = { | ||||
|     NULL, G_LOG_DOMAIN, "Gtk", "Gdk", "GLib", | ||||
|     "Pango", "GLib-GObject", "GThread" | ||||
|   }; | ||||
|   guint i; | ||||
|  | ||||
|   /* Load prefs */ | ||||
|   meta_prefs_init (); | ||||
|   meta_prefs_add_listener (prefs_changed_callback, NULL); | ||||
|  | ||||
|   for (i=0; i<G_N_ELEMENTS(log_domains); i++) | ||||
|     g_log_set_handler (log_domains[i], | ||||
|                        G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, | ||||
|                        log_handler, NULL); | ||||
|  | ||||
|   if (g_getenv ("MUTTER_G_FATAL_WARNINGS") != NULL) | ||||
|     g_log_set_always_fatal (G_LOG_LEVEL_MASK); | ||||
|    | ||||
|   meta_ui_set_current_theme (meta_prefs_get_theme ()); | ||||
|  | ||||
|   /* Try to find some theme that'll work if the theme preference | ||||
|    * doesn't exist.  First try Simple (the default theme) then just | ||||
|    * try anything in the themes directory. | ||||
|   /* If the theme preference does not exists, fallback to | ||||
|    * Adwaita (the default theme), or abort if that doesn't | ||||
|    * exists. | ||||
|    */ | ||||
|   if (!meta_ui_have_a_theme ()) | ||||
|     meta_ui_set_current_theme ("Simple"); | ||||
|    | ||||
|     meta_ui_set_current_theme ("Adwaita"); | ||||
|  | ||||
|   if (!meta_ui_have_a_theme ()) | ||||
|     { | ||||
|       const char *dir_entry = NULL; | ||||
|       GError *err = NULL; | ||||
|       GDir   *themes_dir = NULL; | ||||
|        | ||||
|       if (!(themes_dir = g_dir_open (MUTTER_DATADIR"/themes", 0, &err))) | ||||
|         { | ||||
|           meta_fatal (_("Failed to scan themes directory: %s\n"), err->message); | ||||
|           g_error_free (err); | ||||
|         }  | ||||
|       else  | ||||
|         { | ||||
|           while (((dir_entry = g_dir_read_name (themes_dir)) != NULL) &&  | ||||
|                  (!meta_ui_have_a_theme ())) | ||||
|             { | ||||
|               meta_ui_set_current_theme (dir_entry); | ||||
|             } | ||||
|            | ||||
|           g_dir_close (themes_dir); | ||||
|         } | ||||
|     } | ||||
|    | ||||
|   if (!meta_ui_have_a_theme ()) | ||||
|     meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n"), | ||||
|                 MUTTER_DATADIR"/themes"); | ||||
|     meta_fatal ("Adwaita theme missing, please install the gnome-themes-standard package"); | ||||
|  | ||||
|   if (!meta_display_open ()) | ||||
|     meta_exit (META_EXIT_ERROR); | ||||
|    | ||||
|  | ||||
|   g_main_loop_run (meta_main_loop); | ||||
|  | ||||
|   meta_finalize (); | ||||
|   | ||||
							
								
								
									
										40
									
								
								src/core/meta-xrandr-shared.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/core/meta-xrandr-shared.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /* -*- 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. | ||||
|  */ | ||||
|  | ||||
| /* This file is shared between mutter (src/core/meta-xrandr-shared.h) | ||||
|    and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h). | ||||
|  | ||||
|    The canonical place for all changes is mutter. | ||||
|  | ||||
|    There should be no includes in this file. | ||||
| */ | ||||
|  | ||||
| #ifndef META_XRANDR_SHARED_H | ||||
| #define META_XRANDR_SHARED_H | ||||
|  | ||||
| typedef enum { | ||||
|   META_POWER_SAVE_UNKNOWN = -1, | ||||
|   META_POWER_SAVE_ON = 0, | ||||
|   META_POWER_SAVE_STANDBY, | ||||
|   META_POWER_SAVE_SUSPEND, | ||||
|   META_POWER_SAVE_OFF, | ||||
| } MetaPowerSave; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1771
									
								
								src/core/monitor-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1771
									
								
								src/core/monitor-config.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										390
									
								
								src/core/monitor-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								src/core/monitor-private.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,390 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
|  | ||||
| /** | ||||
|  * \file screen-private.h  Handling of monitor configuration | ||||
|  * | ||||
|  * Managing multiple monitors | ||||
|  * This file contains structures and functions that handle | ||||
|  * multiple monitors, including reading the current configuration | ||||
|  * and available hardware, and applying it. | ||||
|  * | ||||
|  * This interface is private to mutter, API users should look | ||||
|  * at MetaScreen instead. | ||||
|  */ | ||||
|  | ||||
| /*  | ||||
|  * 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, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef META_MONITOR_PRIVATE_H | ||||
| #define META_MONITOR_PRIVATE_H | ||||
|  | ||||
| #include <cogl/cogl.h> | ||||
| #include <libgnome-desktop/gnome-pnp-ids.h> | ||||
|  | ||||
| #include "display-private.h" | ||||
| #include <meta/screen.h> | ||||
| #include "stack-tracker.h" | ||||
| #include "ui.h" | ||||
| #ifdef HAVE_WAYLAND | ||||
| #include <wayland-server.h> | ||||
| #endif | ||||
| #include "meta-xrandr-shared.h" | ||||
|  | ||||
| #include "meta-dbus-xrandr.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; | ||||
| typedef struct _MetaMonitorInfo MetaMonitorInfo; | ||||
| typedef struct _MetaCRTCInfo MetaCRTCInfo; | ||||
| typedef struct _MetaOutputInfo MetaOutputInfo; | ||||
|  | ||||
| struct _MetaOutput | ||||
| { | ||||
|   /* The CRTC driving this output, NULL if the output is not enabled */ | ||||
|   MetaCRTC *crtc; | ||||
|   /* The low-level ID of this output, used to apply back configuration */ | ||||
|   glong output_id; | ||||
|   char *name; | ||||
|   char *vendor; | ||||
|   char *product; | ||||
|   char *serial; | ||||
|   int width_mm; | ||||
|   int height_mm; | ||||
|   CoglSubpixelOrder subpixel_order; | ||||
|  | ||||
|   MetaMonitorMode *preferred_mode; | ||||
|   MetaMonitorMode **modes; | ||||
|   unsigned int n_modes; | ||||
|  | ||||
|   MetaCRTC **possible_crtcs; | ||||
|   unsigned int n_possible_crtcs; | ||||
|  | ||||
|   MetaOutput **possible_clones; | ||||
|   unsigned int n_possible_clones; | ||||
|  | ||||
|   int backlight; | ||||
|   int backlight_min; | ||||
|   int backlight_max; | ||||
|  | ||||
|   /* Used when changing configuration */ | ||||
|   gboolean dirty; | ||||
|  | ||||
|   /* The low-level bits used to build the high-level info | ||||
|      in MetaMonitorInfo | ||||
|  | ||||
|      XXX: flags maybe? | ||||
|      There is a lot of code that uses MonitorInfo->is_primary, | ||||
|      but nobody uses MetaOutput yet | ||||
|   */ | ||||
|   gboolean is_primary; | ||||
|   gboolean is_presentation; | ||||
| }; | ||||
|  | ||||
| struct _MetaCRTC | ||||
| { | ||||
|   glong crtc_id; | ||||
|   MetaRectangle rect; | ||||
|   MetaMonitorMode *current_mode; | ||||
|   enum wl_output_transform transform; | ||||
|   unsigned int all_transforms; | ||||
|  | ||||
|   /* Only used to build the logical configuration | ||||
|      from the HW one | ||||
|   */ | ||||
|   MetaMonitorInfo *logical_monitor; | ||||
|  | ||||
|   /* Used when changing configuration */ | ||||
|   gboolean dirty; | ||||
| }; | ||||
|  | ||||
| struct _MetaMonitorMode | ||||
| { | ||||
|   /* The low-level ID of this mode, used to apply back configuration */ | ||||
|   glong mode_id; | ||||
|  | ||||
|   int width; | ||||
|   int height; | ||||
|   float refresh_rate; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * MetaMonitorInfo: | ||||
|  * | ||||
|  * A structure with high-level information about monitors. | ||||
|  * This corresponds to a subset of the compositor coordinate space. | ||||
|  * Clones are only reported once, irrespective of the way | ||||
|  * they're implemented (two CRTCs configured for the same | ||||
|  * coordinates or one CRTCs driving two outputs). Inactive CRTCs | ||||
|  * are ignored, and so are disabled outputs. | ||||
|  */ | ||||
| struct _MetaMonitorInfo | ||||
| { | ||||
|   int number; | ||||
|   int xinerama_index; | ||||
|   MetaRectangle rect; | ||||
|   gboolean is_primary; | ||||
|   gboolean is_presentation; /* XXX: not yet used */ | ||||
|   gboolean in_fullscreen; | ||||
|  | ||||
|   /* The primary or first output for this monitor, 0 if we can't figure out. | ||||
|      It can be matched to an output_id of a MetaOutput. | ||||
|  | ||||
|      This is used as an opaque token on reconfiguration when switching from | ||||
|      clone to extened, to decide on what output the windows should go next | ||||
|      (it's an attempt to keep windows on the same monitor, and preferably on | ||||
|      the primary one). | ||||
|   */ | ||||
|   glong output_id; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * MetaCRTCInfo: | ||||
|  * This represents the writable part of a CRTC, as deserialized from DBus | ||||
|  * or built by MetaMonitorConfig | ||||
|  * | ||||
|  * Note: differently from the other structures in this file, MetaCRTCInfo | ||||
|  * is handled by pointer. This is to accomodate the usage in MetaMonitorConfig | ||||
|  */ | ||||
| struct _MetaCRTCInfo { | ||||
|   MetaCRTC                 *crtc; | ||||
|   MetaMonitorMode          *mode; | ||||
|   int                       x; | ||||
|   int                       y; | ||||
|   enum wl_output_transform  transform; | ||||
|   GPtrArray                *outputs; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * MetaOutputInfo: | ||||
|  * this is the same as MetaOutputInfo, but for CRTCs | ||||
|  */ | ||||
| struct _MetaOutputInfo { | ||||
|   MetaOutput  *output; | ||||
|   gboolean     is_primary; | ||||
|   gboolean     is_presentation; | ||||
| }; | ||||
|  | ||||
| #define META_TYPE_MONITOR_MANAGER            (meta_monitor_manager_get_type ()) | ||||
| #define META_MONITOR_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager)) | ||||
| #define META_MONITOR_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass)) | ||||
| #define META_IS_MONITOR_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER)) | ||||
| #define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_MONITOR_MANAGER)) | ||||
| #define META_MONITOR_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass)) | ||||
|  | ||||
| struct _MetaMonitorManager | ||||
| { | ||||
|   MetaDBusDisplayConfigSkeleton parent_instance; | ||||
|  | ||||
|   /* XXX: this structure is very badly | ||||
|      packed, but I like the logical organization | ||||
|      of fields */ | ||||
|  | ||||
|   gboolean in_init; | ||||
|   unsigned int serial; | ||||
|  | ||||
|   MetaPowerSave power_save_mode; | ||||
|  | ||||
|   int max_screen_width; | ||||
|   int max_screen_height; | ||||
|   int screen_width; | ||||
|   int screen_height; | ||||
|  | ||||
|   /* Outputs refer to physical screens, | ||||
|      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; | ||||
|  | ||||
|   MetaMonitorMode *modes; | ||||
|   unsigned int n_modes; | ||||
|  | ||||
|   MetaCRTC *crtcs; | ||||
|   unsigned int n_crtcs; | ||||
|  | ||||
|   MetaMonitorInfo *monitor_infos; | ||||
|   unsigned int n_monitor_infos; | ||||
|   int primary_monitor_index; | ||||
|  | ||||
|   int dbus_name_id; | ||||
|  | ||||
|   int persistent_timeout_id; | ||||
|   MetaMonitorConfig *config; | ||||
|  | ||||
|   GnomePnpIds *pnp_ids; | ||||
| }; | ||||
|  | ||||
| struct _MetaMonitorManagerClass | ||||
| { | ||||
|   MetaDBusDisplayConfigSkeletonClass parent_class; | ||||
|  | ||||
|   void (*read_current) (MetaMonitorManager *); | ||||
|  | ||||
|   char* (*get_edid_file) (MetaMonitorManager *, | ||||
|                           MetaOutput         *); | ||||
|   GBytes* (*read_edid) (MetaMonitorManager *, | ||||
|                         MetaOutput         *); | ||||
|  | ||||
|   void (*apply_configuration) (MetaMonitorManager  *, | ||||
|                                MetaCRTCInfo       **, | ||||
|                                unsigned int         , | ||||
|                                MetaOutputInfo     **, | ||||
|                                unsigned int); | ||||
|  | ||||
|   void (*set_power_save_mode) (MetaMonitorManager *, | ||||
|                                MetaPowerSave); | ||||
|  | ||||
|   void (*change_backlight) (MetaMonitorManager *, | ||||
|                             MetaOutput         *, | ||||
|                             int); | ||||
|  | ||||
|   void (*get_crtc_gamma) (MetaMonitorManager  *, | ||||
|                           MetaCRTC            *, | ||||
|                           gsize               *, | ||||
|                           unsigned short     **, | ||||
|                           unsigned short     **, | ||||
|                           unsigned short     **); | ||||
|   void (*set_crtc_gamma) (MetaMonitorManager *, | ||||
|                           MetaCRTC           *, | ||||
|                           gsize               , | ||||
|                           unsigned short     *, | ||||
|                           unsigned short     *, | ||||
|                           unsigned short     *); | ||||
|  | ||||
|   gboolean (*handle_xevent) (MetaMonitorManager *, | ||||
|                              XEvent             *); | ||||
| }; | ||||
|  | ||||
| GType meta_monitor_manager_get_type (void); | ||||
|  | ||||
| void                meta_monitor_manager_initialize (void); | ||||
| MetaMonitorManager *meta_monitor_manager_get  (void); | ||||
|  | ||||
| MetaMonitorInfo    *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager, | ||||
| 							    unsigned int       *n_infos); | ||||
|  | ||||
| MetaOutput         *meta_monitor_manager_get_outputs       (MetaMonitorManager *manager, | ||||
| 							    unsigned int       *n_outputs); | ||||
|  | ||||
| void                meta_monitor_manager_get_resources     (MetaMonitorManager  *manager, | ||||
|                                                             MetaMonitorMode    **modes, | ||||
|                                                             unsigned int        *n_modes, | ||||
|                                                             MetaCRTC           **crtcs, | ||||
|                                                             unsigned int        *n_crtcs, | ||||
|                                                             MetaOutput         **outputs, | ||||
|                                                             unsigned int        *n_outputs); | ||||
|  | ||||
| int                 meta_monitor_manager_get_primary_index (MetaMonitorManager *manager); | ||||
|  | ||||
| gboolean            meta_monitor_manager_handle_xevent     (MetaMonitorManager *manager, | ||||
|                                                             XEvent             *event); | ||||
|  | ||||
| void                meta_monitor_manager_get_screen_size   (MetaMonitorManager *manager, | ||||
|                                                             int                *width, | ||||
|                                                             int                *height); | ||||
|  | ||||
| void                meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager, | ||||
|                                                             int                *width, | ||||
|                                                             int                *height); | ||||
|  | ||||
| void                meta_monitor_manager_apply_configuration (MetaMonitorManager  *manager, | ||||
|                                                               MetaCRTCInfo       **crtcs, | ||||
|                                                               unsigned int         n_crtcs, | ||||
|                                                               MetaOutputInfo     **outputs, | ||||
|                                                               unsigned int         n_outputs); | ||||
|  | ||||
| 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); | ||||
|  | ||||
| /* Returns true if transform causes width and height to be inverted | ||||
|    This is true for the odd transforms in the enum */ | ||||
| static inline gboolean | ||||
| meta_monitor_transform_is_rotated (enum wl_output_transform transform) | ||||
| { | ||||
|   return (transform % 2); | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										938
									
								
								src/core/monitor-xrandr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										938
									
								
								src/core/monitor-xrandr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,938 @@ | ||||
| /* -*- 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, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #include "config.h" | ||||
|  | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <clutter/clutter.h> | ||||
|  | ||||
| #include <X11/Xatom.h> | ||||
| #include <X11/extensions/Xrandr.h> | ||||
| #include <X11/extensions/dpms.h> | ||||
|  | ||||
| #include <meta/main.h> | ||||
| #include <meta/errors.h> | ||||
| #include "monitor-private.h" | ||||
|  | ||||
| #include "edid.h" | ||||
|  | ||||
| #define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) | ||||
|  | ||||
| /* Look for DPI_FALLBACK in: | ||||
|  * http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c | ||||
|  * for the reasoning */ | ||||
| #define DPI_FALLBACK 96.0 | ||||
|  | ||||
| struct _MetaMonitorManagerXrandr | ||||
| { | ||||
|   MetaMonitorManager parent_instance; | ||||
|  | ||||
|   Display *xdisplay; | ||||
|   XRRScreenResources *resources; | ||||
|   int time; | ||||
|   int rr_event_base; | ||||
|   int rr_error_base; | ||||
| }; | ||||
|  | ||||
| struct _MetaMonitorManagerXrandrClass | ||||
| { | ||||
|   MetaMonitorManagerClass parent_class; | ||||
| }; | ||||
|  | ||||
| G_DEFINE_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr, META_TYPE_MONITOR_MANAGER); | ||||
|  | ||||
| static enum wl_output_transform | ||||
| wl_transform_from_xrandr (Rotation rotation) | ||||
| { | ||||
|   static const enum wl_output_transform y_reflected_map[4] = { | ||||
|     WL_OUTPUT_TRANSFORM_FLIPPED_180, | ||||
|     WL_OUTPUT_TRANSFORM_FLIPPED_90, | ||||
|     WL_OUTPUT_TRANSFORM_FLIPPED, | ||||
|     WL_OUTPUT_TRANSFORM_FLIPPED_270 | ||||
|   }; | ||||
|   enum wl_output_transform ret; | ||||
|  | ||||
|   switch (rotation & 0x7F) | ||||
|     { | ||||
|     default: | ||||
|     case RR_Rotate_0: | ||||
|       ret = WL_OUTPUT_TRANSFORM_NORMAL; | ||||
|       break; | ||||
|     case RR_Rotate_90: | ||||
|       ret = WL_OUTPUT_TRANSFORM_90; | ||||
|       break; | ||||
|     case RR_Rotate_180: | ||||
|       ret = WL_OUTPUT_TRANSFORM_180; | ||||
|       break; | ||||
|     case RR_Rotate_270: | ||||
|       ret = WL_OUTPUT_TRANSFORM_270; | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|   if (rotation & RR_Reflect_X) | ||||
|     return ret + 4; | ||||
|   else if (rotation & RR_Reflect_Y) | ||||
|     return y_reflected_map[ret]; | ||||
|   else | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| #define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270) | ||||
|  | ||||
| static unsigned int | ||||
| wl_transform_from_xrandr_all (Rotation rotation) | ||||
| { | ||||
|   unsigned ret; | ||||
|  | ||||
|   /* Handle the common cases first (none or all) */ | ||||
|   if (rotation == 0 || rotation == RR_Rotate_0) | ||||
|     return (1 << WL_OUTPUT_TRANSFORM_NORMAL); | ||||
|  | ||||
|   /* All rotations and one reflection -> all of them by composition */ | ||||
|   if ((rotation & ALL_ROTATIONS) && | ||||
|       ((rotation & RR_Reflect_X) || (rotation & RR_Reflect_Y))) | ||||
|     return ALL_WL_TRANSFORMS; | ||||
|  | ||||
|   ret = 1 << WL_OUTPUT_TRANSFORM_NORMAL; | ||||
|   if (rotation & RR_Rotate_90) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_90; | ||||
|   if (rotation & RR_Rotate_180) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_180; | ||||
|   if (rotation & RR_Rotate_270) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_270; | ||||
|   if (rotation & (RR_Rotate_0 | RR_Reflect_X)) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED; | ||||
|   if (rotation & (RR_Rotate_90 | RR_Reflect_X)) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_90; | ||||
|   if (rotation & (RR_Rotate_180 | RR_Reflect_X)) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_180; | ||||
|   if (rotation & (RR_Rotate_270 | RR_Reflect_X)) | ||||
|     ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_270; | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr, | ||||
|                                 MetaOutput               *output) | ||||
| { | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|   gboolean value; | ||||
|   Atom actual_type; | ||||
|   int actual_format; | ||||
|   unsigned long nitems, bytes_after; | ||||
|   unsigned char *buffer; | ||||
|  | ||||
|   XRRGetOutputProperty (manager_xrandr->xdisplay, | ||||
|                         (XID)output->output_id, | ||||
|                         display->atom__MUTTER_PRESENTATION_OUTPUT, | ||||
|                         0, G_MAXLONG, False, False, XA_CARDINAL, | ||||
|                         &actual_type, &actual_format, | ||||
|                         &nitems, &bytes_after, &buffer); | ||||
|  | ||||
|   if (actual_type != XA_CARDINAL || actual_format != 32 || | ||||
|       nitems < 1) | ||||
|     return FALSE; | ||||
|  | ||||
|   value = ((int*)buffer)[0]; | ||||
|  | ||||
|   XFree (buffer); | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| static int | ||||
| normalize_backlight (MetaOutput *output, | ||||
|                      int         hw_value) | ||||
| { | ||||
|   return round((double)(hw_value - output->backlight_min) / | ||||
|                (output->backlight_max - output->backlight_min) * 100.0); | ||||
| } | ||||
|  | ||||
| static int | ||||
| output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr, | ||||
|                              MetaOutput               *output) | ||||
| { | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|   gboolean value; | ||||
|   Atom actual_type; | ||||
|   int actual_format; | ||||
|   unsigned long nitems, bytes_after; | ||||
|   unsigned char *buffer; | ||||
|  | ||||
|   XRRGetOutputProperty (manager_xrandr->xdisplay, | ||||
|                         (XID)output->output_id, | ||||
|                         display->atom_BACKLIGHT, | ||||
|                         0, G_MAXLONG, False, False, XA_INTEGER, | ||||
|                         &actual_type, &actual_format, | ||||
|                         &nitems, &bytes_after, &buffer); | ||||
|  | ||||
|   if (actual_type != XA_INTEGER || actual_format != 32 || | ||||
|       nitems < 1) | ||||
|     return -1; | ||||
|  | ||||
|   value = ((int*)buffer)[0]; | ||||
|  | ||||
|   XFree (buffer); | ||||
|   return normalize_backlight (output, value); | ||||
| } | ||||
|  | ||||
| static void | ||||
| output_get_backlight_limits_xrandr (MetaMonitorManagerXrandr *manager_xrandr, | ||||
|                                     MetaOutput               *output) | ||||
| { | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|   XRRPropertyInfo *info; | ||||
|  | ||||
|   meta_error_trap_push (display); | ||||
|   info = XRRQueryOutputProperty (manager_xrandr->xdisplay, | ||||
|                                  (XID)output->output_id, | ||||
|                                  display->atom_BACKLIGHT); | ||||
|   meta_error_trap_pop (display); | ||||
|  | ||||
|   if (info == NULL) | ||||
|     { | ||||
|       meta_verbose ("could not get output property for %s\n", output->name); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|   if (!info->range || info->num_values != 2) | ||||
|     { | ||||
|       meta_verbose ("backlight %s was not range\n", output->name); | ||||
|       goto out; | ||||
|     } | ||||
|  | ||||
|   output->backlight_min = info->values[0]; | ||||
|   output->backlight_max = info->values[1]; | ||||
|  | ||||
| out: | ||||
|   XFree (info); | ||||
| } | ||||
|  | ||||
| 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 guint8 * | ||||
| get_edid_property (Display  *dpy, | ||||
|                    RROutput  output, | ||||
|                    Atom      atom, | ||||
|                    gsize    *len) | ||||
| { | ||||
|   unsigned char *prop; | ||||
|   int actual_format; | ||||
|   unsigned long nitems, bytes_after; | ||||
|   Atom actual_type; | ||||
|   guint8 *result; | ||||
|  | ||||
|   XRRGetOutputProperty (dpy, output, atom, | ||||
|                         0, 100, False, False, | ||||
|                         AnyPropertyType, | ||||
|                         &actual_type, &actual_format, | ||||
|                         &nitems, &bytes_after, &prop); | ||||
|  | ||||
|   if (actual_type == XA_INTEGER && actual_format == 8) | ||||
|     { | ||||
|       result = g_memdup (prop, nitems); | ||||
|       if (len) | ||||
|         *len = nitems; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       result = NULL; | ||||
|     } | ||||
|  | ||||
|   XFree (prop); | ||||
|      | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static GBytes * | ||||
| read_output_edid (MetaMonitorManagerXrandr *manager_xrandr, | ||||
|                   XID                       output_id) | ||||
| { | ||||
|   Atom edid_atom; | ||||
|   guint8 *result; | ||||
|   gsize len; | ||||
|  | ||||
|   edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE); | ||||
|   result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len); | ||||
|  | ||||
|   if (!result) | ||||
|     { | ||||
|       edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE); | ||||
|       result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len); | ||||
|     } | ||||
|  | ||||
|   if (!result) | ||||
|     { | ||||
|       edid_atom = XInternAtom (manager_xrandr->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE); | ||||
|       result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len); | ||||
|     } | ||||
|  | ||||
|   if (result) | ||||
|     { | ||||
|       if (len > 0 && len % 128 == 0) | ||||
|         return g_bytes_new_take (result, len); | ||||
|       else | ||||
|         g_free (result); | ||||
|     } | ||||
|  | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|   XRRScreenResources *resources; | ||||
|   RROutput primary_output; | ||||
|   unsigned int i, j, k; | ||||
|   unsigned int n_actual_outputs; | ||||
|   int min_width, min_height; | ||||
|   Screen *screen; | ||||
|   BOOL dpms_capable, dpms_enabled; | ||||
|   CARD16 dpms_state; | ||||
|  | ||||
|   if (manager_xrandr->resources) | ||||
|     XRRFreeScreenResources (manager_xrandr->resources); | ||||
|   manager_xrandr->resources = NULL; | ||||
|  | ||||
|   meta_error_trap_push (meta_get_display ()); | ||||
|   dpms_capable = DPMSCapable (manager_xrandr->xdisplay); | ||||
|   meta_error_trap_pop (meta_get_display ()); | ||||
|  | ||||
|   if (dpms_capable && | ||||
|       DPMSInfo (manager_xrandr->xdisplay, &dpms_state, &dpms_enabled) && | ||||
|       dpms_enabled) | ||||
|     { | ||||
|       switch (dpms_state) | ||||
| 	{ | ||||
| 	case DPMSModeOn: | ||||
| 	  manager->power_save_mode = META_POWER_SAVE_ON; | ||||
| 	case DPMSModeStandby: | ||||
| 	  manager->power_save_mode = META_POWER_SAVE_STANDBY; | ||||
| 	case DPMSModeSuspend: | ||||
| 	  manager->power_save_mode = META_POWER_SAVE_SUSPEND; | ||||
| 	case DPMSModeOff: | ||||
| 	  manager->power_save_mode = META_POWER_SAVE_OFF; | ||||
| 	default: | ||||
| 	  manager->power_save_mode = META_POWER_SAVE_UNKNOWN; | ||||
| 	} | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       manager->power_save_mode = META_POWER_SAVE_UNKNOWN; | ||||
|     } | ||||
|  | ||||
|   XRRGetScreenSizeRange (manager_xrandr->xdisplay, DefaultRootWindow (manager_xrandr->xdisplay), | ||||
| 			 &min_width, | ||||
| 			 &min_height, | ||||
| 			 &manager->max_screen_width, | ||||
| 			 &manager->max_screen_height); | ||||
|  | ||||
|   screen = ScreenOfDisplay (manager_xrandr->xdisplay, | ||||
| 			    DefaultScreen (manager_xrandr->xdisplay)); | ||||
|   /* This is updated because we called RRUpdateConfiguration below */ | ||||
|   manager->screen_width = WidthOfScreen (screen); | ||||
|   manager->screen_height = HeightOfScreen (screen); | ||||
|  | ||||
|   resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay, | ||||
| 					    DefaultRootWindow (manager_xrandr->xdisplay)); | ||||
|   if (!resources) | ||||
|     return; | ||||
|  | ||||
|   manager_xrandr->resources = resources; | ||||
|   manager_xrandr->time = resources->configTimestamp; | ||||
|   manager->n_outputs = resources->noutput; | ||||
|   manager->n_crtcs = resources->ncrtc; | ||||
|   manager->n_modes = resources->nmode; | ||||
|   manager->outputs = g_new0 (MetaOutput, manager->n_outputs); | ||||
|   manager->modes = g_new0 (MetaMonitorMode, manager->n_modes); | ||||
|   manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs); | ||||
|  | ||||
|   for (i = 0; i < (unsigned)resources->nmode; i++) | ||||
|     { | ||||
|       XRRModeInfo *xmode = &resources->modes[i]; | ||||
|       MetaMonitorMode *mode; | ||||
|  | ||||
|       mode = &manager->modes[i]; | ||||
|  | ||||
|       mode->mode_id = xmode->id; | ||||
|       mode->width = xmode->width; | ||||
|       mode->height = xmode->height; | ||||
|       mode->refresh_rate = (xmode->dotClock / | ||||
| 			    ((float)xmode->hTotal * xmode->vTotal)); | ||||
|     } | ||||
|  | ||||
|   for (i = 0; i < (unsigned)resources->ncrtc; i++) | ||||
|     { | ||||
|       XRRCrtcInfo *crtc; | ||||
|       MetaCRTC *meta_crtc; | ||||
|  | ||||
|       crtc = XRRGetCrtcInfo (manager_xrandr->xdisplay, resources, resources->crtcs[i]); | ||||
|  | ||||
|       meta_crtc = &manager->crtcs[i]; | ||||
|  | ||||
|       meta_crtc->crtc_id = resources->crtcs[i]; | ||||
|       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->dirty = FALSE; | ||||
|       meta_crtc->transform = wl_transform_from_xrandr (crtc->rotation); | ||||
|       meta_crtc->all_transforms = wl_transform_from_xrandr_all (crtc->rotations); | ||||
|  | ||||
|       for (j = 0; j < (unsigned)resources->nmode; j++) | ||||
| 	{ | ||||
| 	  if (resources->modes[j].id == crtc->mode) | ||||
| 	    { | ||||
| 	      meta_crtc->current_mode = &manager->modes[j]; | ||||
| 	      break; | ||||
| 	    } | ||||
| 	} | ||||
|  | ||||
|       XRRFreeCrtcInfo (crtc); | ||||
|     } | ||||
|  | ||||
|   primary_output = XRRGetOutputPrimary (manager_xrandr->xdisplay, | ||||
| 					DefaultRootWindow (manager_xrandr->xdisplay)); | ||||
|  | ||||
|   n_actual_outputs = 0; | ||||
|   for (i = 0; i < (unsigned)resources->noutput; i++) | ||||
|     { | ||||
|       XRROutputInfo *output; | ||||
|       MetaOutput *meta_output; | ||||
|  | ||||
|       output = XRRGetOutputInfo (manager_xrandr->xdisplay, resources, resources->outputs[i]); | ||||
|  | ||||
|       meta_output = &manager->outputs[n_actual_outputs]; | ||||
|  | ||||
|       if (output->connection != RR_Disconnected) | ||||
| 	{ | ||||
|           GBytes *edid; | ||||
|           MonitorInfo *parsed_edid; | ||||
|  | ||||
| 	  meta_output->output_id = resources->outputs[i]; | ||||
| 	  meta_output->name = g_strdup (output->name); | ||||
|  | ||||
|           edid = read_output_edid (manager_xrandr, meta_output->output_id); | ||||
|           if (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"); | ||||
|             } | ||||
| 	  meta_output->width_mm = output->mm_width; | ||||
| 	  meta_output->height_mm = output->mm_height; | ||||
| 	  meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; | ||||
|  | ||||
| 	  meta_output->n_modes = output->nmode; | ||||
| 	  meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes); | ||||
| 	  for (j = 0; j < meta_output->n_modes; j++) | ||||
| 	    { | ||||
| 	      for (k = 0; k < manager->n_modes; k++) | ||||
| 		{ | ||||
| 		  if (output->modes[j] == (XID)manager->modes[k].mode_id) | ||||
| 		    { | ||||
| 		      meta_output->modes[j] = &manager->modes[k]; | ||||
| 		      break; | ||||
| 		    } | ||||
| 		} | ||||
| 	    } | ||||
| 	  meta_output->preferred_mode = meta_output->modes[0]; | ||||
|  | ||||
| 	  meta_output->n_possible_crtcs = output->ncrtc; | ||||
| 	  meta_output->possible_crtcs = g_new0 (MetaCRTC *, meta_output->n_possible_crtcs); | ||||
| 	  for (j = 0; j < (unsigned)output->ncrtc; j++) | ||||
| 	    { | ||||
| 	      for (k = 0; k < manager->n_crtcs; k++) | ||||
| 		{ | ||||
| 		  if ((XID)manager->crtcs[k].crtc_id == output->crtcs[j]) | ||||
| 		    { | ||||
| 		      meta_output->possible_crtcs[j] = &manager->crtcs[k]; | ||||
| 		      break; | ||||
| 		    } | ||||
| 		} | ||||
| 	    } | ||||
|  | ||||
| 	  meta_output->crtc = NULL; | ||||
| 	  for (j = 0; j < manager->n_crtcs; j++) | ||||
| 	    { | ||||
| 	      if ((XID)manager->crtcs[j].crtc_id == output->crtc) | ||||
| 		{ | ||||
| 		  meta_output->crtc = &manager->crtcs[j]; | ||||
| 		  break; | ||||
| 		} | ||||
| 	    } | ||||
|  | ||||
| 	  meta_output->n_possible_clones = output->nclone; | ||||
| 	  meta_output->possible_clones = g_new0 (MetaOutput *, meta_output->n_possible_clones); | ||||
| 	  /* We can build the list of clones now, because we don't have the list of outputs | ||||
| 	     yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them | ||||
| 	     in a second pass | ||||
| 	  */ | ||||
| 	  for (j = 0; j < (unsigned)output->nclone; j++) | ||||
| 	    { | ||||
| 	      meta_output->possible_clones = GINT_TO_POINTER (output->clones[j]); | ||||
| 	    } | ||||
|  | ||||
| 	  meta_output->is_primary = ((XID)meta_output->output_id == primary_output); | ||||
| 	  meta_output->is_presentation = output_get_presentation_xrandr (manager_xrandr, meta_output); | ||||
| 	  output_get_backlight_limits_xrandr (manager_xrandr, meta_output); | ||||
|  | ||||
| 	  if (!(meta_output->backlight_min == 0 && meta_output->backlight_max == 0)) | ||||
| 	    meta_output->backlight = output_get_backlight_xrandr (manager_xrandr, meta_output); | ||||
| 	  else | ||||
| 	    meta_output->backlight = -1; | ||||
|  | ||||
| 	  n_actual_outputs++; | ||||
| 	} | ||||
|  | ||||
|       XRRFreeOutputInfo (output); | ||||
|     } | ||||
|  | ||||
|   manager->n_outputs = n_actual_outputs; | ||||
|  | ||||
|   /* Sort the outputs for easier handling in MetaMonitorConfig */ | ||||
|   qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs); | ||||
|  | ||||
|   /* Now fix the clones */ | ||||
|   for (i = 0; i < manager->n_outputs; i++) | ||||
|     { | ||||
|       MetaOutput *meta_output; | ||||
|  | ||||
|       meta_output = &manager->outputs[i]; | ||||
|  | ||||
|       for (j = 0; j < meta_output->n_possible_clones; j++) | ||||
| 	{ | ||||
| 	  RROutput clone = GPOINTER_TO_INT (meta_output->possible_clones[j]); | ||||
|  | ||||
| 	  for (k = 0; k < manager->n_outputs; k++) | ||||
| 	    { | ||||
| 	      if (clone == (XID)manager->outputs[k].output_id) | ||||
| 		{ | ||||
| 		  meta_output->possible_clones[j] = &manager->outputs[k]; | ||||
| 		  break; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| } | ||||
|  | ||||
| static GBytes * | ||||
| meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager, | ||||
|                                        MetaOutput         *output) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|  | ||||
|   return read_output_edid (manager_xrandr, output->output_id); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_set_power_save_mode (MetaMonitorManager *manager, | ||||
| 						 MetaPowerSave       mode) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|   CARD16 state; | ||||
|  | ||||
|   switch (mode) { | ||||
|   case META_POWER_SAVE_ON: | ||||
|     state = DPMSModeOn; | ||||
|     break; | ||||
|   case META_POWER_SAVE_STANDBY: | ||||
|     state = DPMSModeStandby; | ||||
|     break; | ||||
|   case META_POWER_SAVE_SUSPEND: | ||||
|     state = DPMSModeSuspend; | ||||
|     break; | ||||
|   case META_POWER_SAVE_OFF: | ||||
|     state = DPMSModeOff; | ||||
|     break; | ||||
|   default: | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   meta_error_trap_push (meta_get_display ()); | ||||
|   DPMSForceLevel (manager_xrandr->xdisplay, state); | ||||
|   DPMSSetTimeouts (manager_xrandr->xdisplay, 0, 0, 0); | ||||
|   meta_error_trap_pop (meta_get_display ()); | ||||
| } | ||||
|  | ||||
| static Rotation | ||||
| wl_transform_to_xrandr (enum wl_output_transform transform) | ||||
| { | ||||
|   switch (transform) | ||||
|     { | ||||
|     case WL_OUTPUT_TRANSFORM_NORMAL: | ||||
|       return RR_Rotate_0; | ||||
|     case WL_OUTPUT_TRANSFORM_90: | ||||
|       return RR_Rotate_90; | ||||
|     case WL_OUTPUT_TRANSFORM_180: | ||||
|       return RR_Rotate_180; | ||||
|     case WL_OUTPUT_TRANSFORM_270: | ||||
|       return RR_Rotate_270; | ||||
|     case WL_OUTPUT_TRANSFORM_FLIPPED: | ||||
|       return RR_Reflect_X | RR_Rotate_0; | ||||
|     case WL_OUTPUT_TRANSFORM_FLIPPED_90: | ||||
|       return RR_Reflect_X | RR_Rotate_90; | ||||
|     case WL_OUTPUT_TRANSFORM_FLIPPED_180: | ||||
|       return RR_Reflect_X | RR_Rotate_180; | ||||
|     case WL_OUTPUT_TRANSFORM_FLIPPED_270: | ||||
|       return RR_Reflect_X | RR_Rotate_270; | ||||
|     } | ||||
|  | ||||
|   g_assert_not_reached (); | ||||
| } | ||||
|  | ||||
| static void | ||||
| output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr, | ||||
|                                 MetaOutput               *output, | ||||
|                                 gboolean                  presentation) | ||||
| { | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|   int value = presentation; | ||||
|  | ||||
|   XRRChangeOutputProperty (manager_xrandr->xdisplay, | ||||
|                            (XID)output->output_id, | ||||
|                            display->atom__MUTTER_PRESENTATION_OUTPUT, | ||||
|                            XA_CARDINAL, 32, PropModeReplace, | ||||
|                            (unsigned char*) &value, 1); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager, | ||||
| 						 MetaCRTCInfo       **crtcs, | ||||
| 						 unsigned int         n_crtcs, | ||||
| 						 MetaOutputInfo     **outputs, | ||||
| 						 unsigned int         n_outputs) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|   unsigned i; | ||||
|   int width, height, width_mm, height_mm; | ||||
|  | ||||
|   meta_display_grab (meta_get_display ()); | ||||
|  | ||||
|   /* First compute the new size of the screen (framebuffer) */ | ||||
|   width = 0; height = 0; | ||||
|   for (i = 0; i < n_crtcs; i++) | ||||
|     { | ||||
|       MetaCRTCInfo *crtc_info = crtcs[i]; | ||||
|       MetaCRTC *crtc = crtc_info->crtc; | ||||
|       crtc->dirty = TRUE; | ||||
|  | ||||
|       if (crtc_info->mode == NULL) | ||||
|         continue; | ||||
|  | ||||
|       if (meta_monitor_transform_is_rotated (crtc_info->transform)) | ||||
|         { | ||||
|           width = MAX (width, crtc_info->x + crtc_info->mode->height); | ||||
|           height = MAX (height, crtc_info->y + crtc_info->mode->width); | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           width = MAX (width, crtc_info->x + crtc_info->mode->width); | ||||
|           height = MAX (height, crtc_info->y + crtc_info->mode->height); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   /* Second disable all newly disabled CRTCs, or CRTCs that in the previous | ||||
|      configuration would be outside the new framebuffer (otherwise X complains | ||||
|      loudly when resizing) | ||||
|      CRTC will be enabled again after resizing the FB | ||||
|   */ | ||||
|   for (i = 0; i < n_crtcs; i++) | ||||
|     { | ||||
|       MetaCRTCInfo *crtc_info = crtcs[i]; | ||||
|       MetaCRTC *crtc = crtc_info->crtc; | ||||
|  | ||||
|       if (crtc_info->mode == NULL || | ||||
|           crtc->rect.x + crtc->rect.width > width || | ||||
|           crtc->rect.y + crtc->rect.height > height) | ||||
|         { | ||||
|           XRRSetCrtcConfig (manager_xrandr->xdisplay, | ||||
|                             manager_xrandr->resources, | ||||
|                             (XID)crtc->crtc_id, | ||||
|                             manager_xrandr->time, | ||||
|                             0, 0, | ||||
|                             None, | ||||
|                             RR_Rotate_0, | ||||
|                             NULL, 0); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   /* Disable CRTCs not mentioned in the list */ | ||||
|   for (i = 0; i < manager->n_crtcs; i++) | ||||
|     { | ||||
|       MetaCRTC *crtc = &manager->crtcs[i]; | ||||
|  | ||||
|       if (crtc->dirty) | ||||
|         { | ||||
|           crtc->dirty = FALSE; | ||||
|           continue; | ||||
|         } | ||||
|       if (crtc->current_mode == NULL) | ||||
|         continue; | ||||
|  | ||||
|       XRRSetCrtcConfig (manager_xrandr->xdisplay, | ||||
|                         manager_xrandr->resources, | ||||
|                         (XID)crtc->crtc_id, | ||||
|                         manager_xrandr->time, | ||||
|                         0, 0, | ||||
|                         None, | ||||
|                         RR_Rotate_0, | ||||
|                         NULL, 0); | ||||
|     } | ||||
|  | ||||
|   g_assert (width > 0 && height > 0); | ||||
|   /* The 'physical size' of an X screen is meaningless if that screen | ||||
|    * can consist of many monitors. So just pick a size that make the | ||||
|    * dpi 96. | ||||
|    * | ||||
|    * Firefox and Evince apparently believe what X tells them. | ||||
|    */ | ||||
|   width_mm = (width / DPI_FALLBACK) * 25.4 + 0.5; | ||||
|   height_mm = (height / DPI_FALLBACK) * 25.4 + 0.5; | ||||
|   meta_error_trap_push (meta_get_display ()); | ||||
|   XRRSetScreenSize (manager_xrandr->xdisplay, DefaultRootWindow (manager_xrandr->xdisplay), | ||||
|                     width, height, width_mm, height_mm); | ||||
|   meta_error_trap_pop (meta_get_display ()); | ||||
|  | ||||
|   for (i = 0; i < n_crtcs; i++) | ||||
|     { | ||||
|       MetaCRTCInfo *crtc_info = crtcs[i]; | ||||
|       MetaCRTC *crtc = crtc_info->crtc; | ||||
|  | ||||
|       if (crtc_info->mode != NULL) | ||||
|         { | ||||
|           MetaMonitorMode *mode; | ||||
|           XID *outputs; | ||||
|           int j, n_outputs; | ||||
|           Status ok; | ||||
|  | ||||
|           mode = crtc_info->mode; | ||||
|  | ||||
|           n_outputs = crtc_info->outputs->len; | ||||
|           outputs = g_new (XID, n_outputs); | ||||
|  | ||||
|           for (j = 0; j < n_outputs; j++) | ||||
|             outputs[j] = ((MetaOutput**)crtc_info->outputs->pdata)[j]->output_id; | ||||
|  | ||||
|           meta_error_trap_push (meta_get_display ()); | ||||
|           ok = XRRSetCrtcConfig (manager_xrandr->xdisplay, | ||||
|                                  manager_xrandr->resources, | ||||
|                                  (XID)crtc->crtc_id, | ||||
|                                  manager_xrandr->time, | ||||
|                                  crtc_info->x, crtc_info->y, | ||||
|                                  (XID)mode->mode_id, | ||||
|                                  wl_transform_to_xrandr (crtc_info->transform), | ||||
|                                  outputs, n_outputs); | ||||
|           meta_error_trap_pop (meta_get_display ()); | ||||
|  | ||||
|           if (ok != Success) | ||||
|             meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n", | ||||
|                           (unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id), | ||||
|                           mode->width, mode->height, (float)mode->refresh_rate, | ||||
|                           crtc_info->x, crtc_info->y, crtc_info->transform); | ||||
|  | ||||
|           g_free (outputs); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   for (i = 0; i < n_outputs; i++) | ||||
|     { | ||||
|       MetaOutputInfo *output_info = outputs[i]; | ||||
|  | ||||
|       if (output_info->is_primary) | ||||
|         { | ||||
|           XRRSetOutputPrimary (manager_xrandr->xdisplay, | ||||
|                                DefaultRootWindow (manager_xrandr->xdisplay), | ||||
|                                (XID)output_info->output->output_id); | ||||
|         } | ||||
|  | ||||
|       output_set_presentation_xrandr (manager_xrandr, | ||||
|                                       output_info->output, | ||||
|                                       output_info->is_presentation); | ||||
|     } | ||||
|  | ||||
|   meta_display_ungrab (meta_get_display ()); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager, | ||||
| 					      MetaOutput         *output, | ||||
| 					      gint                value) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|   int hw_value; | ||||
|  | ||||
|   hw_value = round((double)value / 100.0 * output->backlight_max + output->backlight_min); | ||||
|  | ||||
|   meta_error_trap_push (display); | ||||
|   XRRChangeOutputProperty (manager_xrandr->xdisplay, | ||||
|                            (XID)output->output_id, | ||||
|                            display->atom_BACKLIGHT, | ||||
|                            XA_INTEGER, 32, PropModeReplace, | ||||
|                            (unsigned char *) &hw_value, 1); | ||||
|   meta_error_trap_pop (display); | ||||
|  | ||||
|   /* We're not selecting for property notifies, so update the value immediately */ | ||||
|   output->backlight = normalize_backlight (output, hw_value); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_get_crtc_gamma (MetaMonitorManager  *manager, | ||||
| 					    MetaCRTC            *crtc, | ||||
| 					    gsize               *size, | ||||
| 					    unsigned short     **red, | ||||
| 					    unsigned short     **green, | ||||
| 					    unsigned short     **blue) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|   XRRCrtcGamma *gamma; | ||||
|  | ||||
|   gamma = XRRGetCrtcGamma (manager_xrandr->xdisplay, (XID)crtc->crtc_id); | ||||
|  | ||||
|   *size = gamma->size; | ||||
|   *red = g_memdup (gamma->red, sizeof (unsigned short) * gamma->size); | ||||
|   *green = g_memdup (gamma->green, sizeof (unsigned short) * gamma->size); | ||||
|   *blue = g_memdup (gamma->blue, sizeof (unsigned short) * gamma->size); | ||||
|  | ||||
|   XRRFreeGamma (gamma); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager, | ||||
| 					    MetaCRTC           *crtc, | ||||
| 					    gsize               size, | ||||
| 					    unsigned short     *red, | ||||
| 					    unsigned short     *green, | ||||
| 					    unsigned short     *blue) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|   XRRCrtcGamma gamma; | ||||
|  | ||||
|   gamma.size = size; | ||||
|   gamma.red = red; | ||||
|   gamma.green = green; | ||||
|   gamma.blue = blue; | ||||
|  | ||||
|   XRRSetCrtcGamma (manager_xrandr->xdisplay, (XID)crtc->crtc_id, &gamma); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, | ||||
| 					   XEvent             *event) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager); | ||||
|  | ||||
|   if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) | ||||
|     return FALSE; | ||||
|  | ||||
|   XRRUpdateConfiguration (event); | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) | ||||
| { | ||||
|   MetaDisplay *display = meta_get_display (); | ||||
|  | ||||
|   manager_xrandr->xdisplay = display->xdisplay; | ||||
|  | ||||
|   if (!XRRQueryExtension (manager_xrandr->xdisplay, | ||||
| 			  &manager_xrandr->rr_event_base, | ||||
| 			  &manager_xrandr->rr_error_base)) | ||||
|     { | ||||
|       return; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       /* We only use ScreenChangeNotify, but GDK uses the others, | ||||
| 	 and we don't want to step on its toes */ | ||||
|       XRRSelectInput (manager_xrandr->xdisplay, | ||||
| 		      DefaultRootWindow (manager_xrandr->xdisplay), | ||||
| 		      RRScreenChangeNotifyMask | ||||
| 		      | RRCrtcChangeNotifyMask | ||||
| 		      | RROutputPropertyNotifyMask); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_finalize (GObject *object) | ||||
| { | ||||
|   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object); | ||||
|  | ||||
|   if (manager_xrandr->resources) | ||||
|     XRRFreeScreenResources (manager_xrandr->resources); | ||||
|   manager_xrandr->resources = NULL; | ||||
|  | ||||
|   G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) | ||||
| { | ||||
|   MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); | ||||
|   GObjectClass *object_class = G_OBJECT_CLASS (klass); | ||||
|  | ||||
|   object_class->finalize = meta_monitor_manager_xrandr_finalize; | ||||
|  | ||||
|   manager_class->read_current = meta_monitor_manager_xrandr_read_current; | ||||
|   manager_class->read_edid = meta_monitor_manager_xrandr_read_edid; | ||||
|   manager_class->apply_configuration = meta_monitor_manager_xrandr_apply_configuration; | ||||
|   manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode; | ||||
|   manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight; | ||||
|   manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma; | ||||
|   manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma; | ||||
|   manager_class->handle_xevent = meta_monitor_manager_xrandr_handle_xevent; | ||||
| } | ||||
|  | ||||
							
								
								
									
										1553
									
								
								src/core/monitor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1553
									
								
								src/core/monitor.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -38,17 +38,7 @@ | ||||
| #include <X11/Xutil.h> | ||||
| #include "stack-tracker.h" | ||||
| #include "ui.h" | ||||
|  | ||||
| typedef struct _MetaMonitorInfo MetaMonitorInfo; | ||||
|  | ||||
| struct _MetaMonitorInfo | ||||
| { | ||||
|   int number; | ||||
|   MetaRectangle rect; | ||||
|   gboolean is_primary; | ||||
|   gboolean in_fullscreen; | ||||
|   XID output; /* The primary or first output for this crtc, None if no xrandr */ | ||||
| }; | ||||
| #include "monitor-private.h" | ||||
|  | ||||
| typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window, | ||||
|                                        gpointer user_data); | ||||
| @@ -100,10 +90,11 @@ struct _MetaScreen | ||||
|   Window wm_sn_selection_window; | ||||
|   Atom wm_sn_atom; | ||||
|   guint32 wm_sn_timestamp; | ||||
|    | ||||
|  | ||||
|   MetaMonitorInfo *monitor_infos; | ||||
|   int primary_monitor_index; | ||||
|   int n_monitor_infos; | ||||
|   int primary_monitor_index; | ||||
|   gboolean has_xinerama_indices; | ||||
|  | ||||
|   /* Cache the current monitor */ | ||||
|   int last_monitor_index; | ||||
| @@ -231,10 +222,6 @@ void meta_screen_calc_workspace_layout (MetaScreen          *screen, | ||||
|                                         MetaWorkspaceLayout *layout); | ||||
| void meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout); | ||||
|  | ||||
| void meta_screen_resize (MetaScreen *screen, | ||||
|                          int         width, | ||||
|                          int         height); | ||||
|  | ||||
| void     meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen, | ||||
|                                                               MetaWindow *keep); | ||||
|  | ||||
| @@ -257,4 +244,9 @@ void     meta_screen_workspace_switched (MetaScreen         *screen, | ||||
|  | ||||
| void meta_screen_set_active_workspace_hint (MetaScreen *screen); | ||||
|  | ||||
| int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen, | ||||
|                                                  int         index); | ||||
| int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, | ||||
|                                                  int         index); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -48,10 +48,6 @@ | ||||
|  | ||||
| #include <X11/extensions/Xinerama.h> | ||||
|  | ||||
| #ifdef HAVE_RANDR | ||||
| #include <X11/extensions/Xrandr.h> | ||||
| #endif | ||||
|  | ||||
| #include <X11/Xatom.h> | ||||
| #include <locale.h> | ||||
| #include <string.h> | ||||
| @@ -76,6 +72,9 @@ static void meta_screen_sn_event   (SnMonitorEvent *event, | ||||
|                                     void           *user_data); | ||||
| #endif | ||||
|  | ||||
| static void on_monitors_changed (MetaMonitorManager *manager, | ||||
|                                  MetaScreen         *screen); | ||||
|  | ||||
| enum | ||||
| { | ||||
|   PROP_N_WORKSPACES = 1, | ||||
| @@ -350,250 +349,93 @@ set_wm_icon_size_hint (MetaScreen *screen) | ||||
| #undef N_VALS | ||||
| } | ||||
|  | ||||
| /* The list of monitors reported by the windowing system might include | ||||
|  * mirrored monitors with identical bounds. Since mirrored monitors | ||||
|  * shouldn't be treated as separate monitors for most purposes, we | ||||
|  * filter them out here. (We ignore the possibility of partially | ||||
|  * overlapping monitors because they are rare and it's hard to come | ||||
|  * up with any sensible interpretation.) | ||||
|  */ | ||||
| static void | ||||
| filter_mirrored_monitors (MetaScreen *screen) | ||||
| meta_screen_ensure_xinerama_indices (MetaScreen *screen) | ||||
| { | ||||
|   int i, j; | ||||
|   XineramaScreenInfo *infos; | ||||
|   int n_infos, i, j; | ||||
|  | ||||
|   /* Currently always true and simplifies things */ | ||||
|   g_assert (screen->primary_monitor_index == 0); | ||||
|   if (screen->has_xinerama_indices) | ||||
|     return; | ||||
|  | ||||
|   for (i = 1; i < screen->n_monitor_infos; i++) | ||||
|   screen->has_xinerama_indices = TRUE; | ||||
|  | ||||
|   if (!XineramaIsActive (screen->display->xdisplay)) | ||||
|     return; | ||||
|  | ||||
|   infos = XineramaQueryScreens (screen->display->xdisplay, &n_infos); | ||||
|   if (n_infos <= 0 || infos == NULL) | ||||
|     { | ||||
|       /* In case we've filtered previous monitors */ | ||||
|       screen->monitor_infos[i].number = i; | ||||
|       meta_XFree (infos); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|       for (j = 0; j < i; j++) | ||||
|   for (i = 0; i < screen->n_monitor_infos; ++i) | ||||
|     { | ||||
|       for (j = 0; j < n_infos; ++j) | ||||
|         { | ||||
|           if (meta_rectangle_equal (&screen->monitor_infos[i].rect, | ||||
|                                     &screen->monitor_infos[j].rect)) | ||||
|             { | ||||
|               memmove (&screen->monitor_infos[i], | ||||
|                        &screen->monitor_infos[i + 1], | ||||
|                        (screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo)); | ||||
|               screen->n_monitor_infos--; | ||||
|               i--; | ||||
|  | ||||
|               continue; | ||||
|             } | ||||
|           if (screen->monitor_infos[i].rect.x == infos[j].x_org && | ||||
| 	      screen->monitor_infos[i].rect.y == infos[j].y_org && | ||||
| 	      screen->monitor_infos[i].rect.width == infos[j].width && | ||||
| 	      screen->monitor_infos[i].rect.height == infos[j].height) | ||||
|             screen->monitor_infos[i].xinerama_index = j; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   meta_XFree (infos); | ||||
| } | ||||
|  | ||||
| #ifdef HAVE_RANDR | ||||
| static MetaMonitorInfo * | ||||
| find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h) | ||||
| int | ||||
| meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, | ||||
|                                              int         index) | ||||
| { | ||||
|   meta_screen_ensure_xinerama_indices (screen); | ||||
|  | ||||
|   return screen->monitor_infos[index].xinerama_index; | ||||
| } | ||||
|  | ||||
| int | ||||
| meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen, | ||||
|                                              int         index) | ||||
| { | ||||
|   MetaMonitorInfo *info; | ||||
|   int i; | ||||
|  | ||||
|   meta_screen_ensure_xinerama_indices (screen); | ||||
|  | ||||
|   for (i = 0; i < screen->n_monitor_infos; i++) | ||||
|     { | ||||
|       info = &screen->monitor_infos[i]; | ||||
|       if (x == info->rect.x && | ||||
|           y == info->rect.y && | ||||
|           w == info->rect.width && | ||||
|           h == info->rect.height) | ||||
|         return info; | ||||
|     } | ||||
|   return NULL; | ||||
|     if (screen->monitor_infos[i].xinerama_index == index) | ||||
|       return i; | ||||
|  | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| /* In the case of multiple outputs of a single crtc (mirroring), we consider one of the | ||||
|  * outputs the "main". This is the one we consider "owning" the windows, so if | ||||
|  * the mirroring is changed to a dual monitor setup then the windows are moved to the | ||||
|  * crtc that now has that main output. If one of the outputs is the primary that is | ||||
|  * always the main, otherwise we just use the first. | ||||
|  */ | ||||
| static XID | ||||
| find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc) | ||||
| { | ||||
|   XRROutputInfo *output; | ||||
|   RROutput primary_output; | ||||
|   int i; | ||||
|   XID res; | ||||
|  | ||||
|   primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot); | ||||
|  | ||||
|   res = None; | ||||
|   for (i = 0; i < crtc->noutput; i++) | ||||
|     { | ||||
|       output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]); | ||||
|       if (output->connection != RR_Disconnected && | ||||
|           (res == None || crtc->outputs[i] == primary_output)) | ||||
|         res = crtc->outputs[i]; | ||||
|       XRRFreeOutputInfo (output); | ||||
|     } | ||||
|  | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| static void | ||||
| reload_monitor_infos (MetaScreen *screen) | ||||
| { | ||||
|   MetaDisplay *display; | ||||
|   GList *tmp; | ||||
|   MetaMonitorManager *manager; | ||||
|  | ||||
|   { | ||||
|     GList *tmp; | ||||
|   tmp = screen->workspaces; | ||||
|   while (tmp != NULL) | ||||
|     { | ||||
|       MetaWorkspace *space = tmp->data; | ||||
|  | ||||
|     tmp = screen->workspaces; | ||||
|     while (tmp != NULL) | ||||
|       { | ||||
|         MetaWorkspace *space = tmp->data; | ||||
|       meta_workspace_invalidate_work_area (space); | ||||
|        | ||||
|       tmp = tmp->next; | ||||
|     } | ||||
|  | ||||
|         meta_workspace_invalidate_work_area (space); | ||||
|          | ||||
|         tmp = tmp->next; | ||||
|       } | ||||
|   } | ||||
|   /* Any previous screen->monitor_infos or screen->outputs is freed by the caller */ | ||||
|  | ||||
|   display = screen->display; | ||||
|  | ||||
|   /* Any previous screen->monitor_infos is freed by the caller */ | ||||
|  | ||||
|   screen->monitor_infos = NULL; | ||||
|   screen->n_monitor_infos = 0; | ||||
|   screen->last_monitor_index = 0; | ||||
|  | ||||
|   /* Xinerama doesn't have a concept of primary monitor, however XRandR | ||||
|    * does. However, the XRandR xinerama compat code always sorts the | ||||
|    * primary output first, so we rely on that here. We could use the | ||||
|    * native XRandR calls instead of xinerama, but that would be | ||||
|    * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as | ||||
|    * that is defined in terms of xinerama monitor indexes. | ||||
|    * So, since we don't need anything in xrandr except the primary | ||||
|    * we can keep using xinerama and use the first monitor as the | ||||
|    * primary. | ||||
|    */ | ||||
|   screen->primary_monitor_index = 0; | ||||
|  | ||||
|   screen->has_xinerama_indices = FALSE; | ||||
|   screen->display->monitor_cache_invalidated = TRUE; | ||||
|  | ||||
|   if (g_getenv ("MUTTER_DEBUG_XINERAMA")) | ||||
|     { | ||||
|       meta_topic (META_DEBUG_XINERAMA, | ||||
|                   "Pretending a single monitor has two Xinerama screens\n"); | ||||
|   manager = meta_monitor_manager_get (); | ||||
|  | ||||
|       screen->monitor_infos = g_new0 (MetaMonitorInfo, 2); | ||||
|       screen->n_monitor_infos = 2; | ||||
|  | ||||
|       screen->monitor_infos[0].number = 0; | ||||
|       screen->monitor_infos[0].rect = screen->rect; | ||||
|       screen->monitor_infos[0].rect.width = screen->rect.width / 2; | ||||
|       screen->monitor_infos[0].in_fullscreen = -1; | ||||
|  | ||||
|       screen->monitor_infos[1].number = 1; | ||||
|       screen->monitor_infos[1].rect = screen->rect; | ||||
|       screen->monitor_infos[1].rect.x = screen->rect.width / 2; | ||||
|       screen->monitor_infos[1].rect.width = screen->rect.width / 2; | ||||
|       screen->monitor_infos[0].in_fullscreen = -1; | ||||
|     } | ||||
|  | ||||
|   if (screen->n_monitor_infos == 0 && | ||||
|       XineramaIsActive (display->xdisplay)) | ||||
|     { | ||||
|       XineramaScreenInfo *infos; | ||||
|       int n_infos; | ||||
|       int i; | ||||
|        | ||||
|       n_infos = 0; | ||||
|       infos = XineramaQueryScreens (display->xdisplay, &n_infos); | ||||
|  | ||||
|       meta_topic (META_DEBUG_XINERAMA, | ||||
|                   "Found %d Xinerama screens on display %s\n", | ||||
|                   n_infos, display->name); | ||||
|  | ||||
|       if (n_infos > 0) | ||||
|         { | ||||
|           screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos); | ||||
|           screen->n_monitor_infos = n_infos; | ||||
|            | ||||
|           i = 0; | ||||
|           while (i < n_infos) | ||||
|             { | ||||
|               screen->monitor_infos[i].number = infos[i].screen_number; | ||||
|               screen->monitor_infos[i].rect.x = infos[i].x_org; | ||||
|               screen->monitor_infos[i].rect.y = infos[i].y_org; | ||||
|               screen->monitor_infos[i].rect.width = infos[i].width; | ||||
|               screen->monitor_infos[i].rect.height = infos[i].height; | ||||
|               screen->monitor_infos[i].in_fullscreen = -1; | ||||
|  | ||||
|               meta_topic (META_DEBUG_XINERAMA, | ||||
|                           "Monitor %d is %d,%d %d x %d\n", | ||||
|                           screen->monitor_infos[i].number, | ||||
|                           screen->monitor_infos[i].rect.x, | ||||
|                           screen->monitor_infos[i].rect.y, | ||||
|                           screen->monitor_infos[i].rect.width, | ||||
|                           screen->monitor_infos[i].rect.height); | ||||
|                | ||||
|               ++i; | ||||
|             } | ||||
|         } | ||||
|        | ||||
|       meta_XFree (infos); | ||||
|  | ||||
| #ifdef HAVE_RANDR | ||||
|       { | ||||
|         XRRScreenResources *resources; | ||||
|  | ||||
|         resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot); | ||||
|         if (resources) | ||||
|           { | ||||
|             for (i = 0; i < resources->ncrtc; i++) | ||||
|               { | ||||
|                 XRRCrtcInfo *crtc; | ||||
|                 MetaMonitorInfo *info; | ||||
|  | ||||
|                 crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]); | ||||
|                 info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height); | ||||
|                 if (info) | ||||
|                   info->output = find_main_output_for_crtc (screen, resources, crtc); | ||||
|  | ||||
|                 XRRFreeCrtcInfo (crtc); | ||||
|               } | ||||
|             XRRFreeScreenResources (resources); | ||||
|           } | ||||
|       } | ||||
| #endif | ||||
|     } | ||||
|   else if (screen->n_monitor_infos > 0) | ||||
|     { | ||||
|       meta_topic (META_DEBUG_XINERAMA, | ||||
|                   "No Xinerama extension or Xinerama inactive on display %s\n", | ||||
|                   display->name); | ||||
|     } | ||||
|  | ||||
|   /* If no Xinerama, fill in the single screen info so | ||||
|    * we can use the field unconditionally | ||||
|    */ | ||||
|   if (screen->n_monitor_infos == 0) | ||||
|     { | ||||
|       meta_topic (META_DEBUG_XINERAMA, | ||||
|                   "No Xinerama screens, using default screen info\n"); | ||||
|            | ||||
|       screen->monitor_infos = g_new0 (MetaMonitorInfo, 1); | ||||
|       screen->n_monitor_infos = 1; | ||||
|            | ||||
|       screen->monitor_infos[0].number = 0; | ||||
|       screen->monitor_infos[0].rect = screen->rect; | ||||
|       screen->monitor_infos[0].in_fullscreen = -1; | ||||
|     } | ||||
|  | ||||
|   filter_mirrored_monitors (screen); | ||||
|  | ||||
|   screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE; | ||||
|  | ||||
|   g_assert (screen->n_monitor_infos > 0); | ||||
|   g_assert (screen->monitor_infos != NULL); | ||||
|   screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager, | ||||
|                                                                   (unsigned*)&screen->n_monitor_infos); | ||||
|   screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager); | ||||
| } | ||||
|  | ||||
| /* The guard window allows us to leave minimized windows mapped so | ||||
| @@ -668,6 +510,7 @@ meta_screen_new (MetaDisplay *display, | ||||
|   char buf[128]; | ||||
|   guint32 manager_timestamp; | ||||
|   gulong current_workspace; | ||||
|   MetaMonitorManager *manager; | ||||
|    | ||||
|   replace_current_wm = meta_get_replace_current_wm (); | ||||
|    | ||||
| @@ -826,8 +669,17 @@ meta_screen_new (MetaDisplay *display, | ||||
|   screen->xscreen = ScreenOfDisplay (xdisplay, number); | ||||
|   screen->xroot = xroot; | ||||
|   screen->rect.x = screen->rect.y = 0; | ||||
|   screen->rect.width = WidthOfScreen (screen->xscreen); | ||||
|   screen->rect.height = HeightOfScreen (screen->xscreen); | ||||
|    | ||||
|   meta_monitor_manager_initialize (); | ||||
|  | ||||
|   manager = meta_monitor_manager_get (); | ||||
|   g_signal_connect (manager, "monitors-changed", | ||||
|                     G_CALLBACK (on_monitors_changed), screen); | ||||
|  | ||||
|   meta_monitor_manager_get_screen_size (manager, | ||||
|                                         &screen->rect.width, | ||||
|                                         &screen->rect.height); | ||||
|  | ||||
|   screen->current_cursor = -1; /* invalid/unset */ | ||||
|   screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); | ||||
|   screen->default_depth = DefaultDepthOfScreen (screen->xscreen); | ||||
| @@ -852,10 +704,6 @@ meta_screen_new (MetaDisplay *display, | ||||
|   screen->compositor_data = NULL; | ||||
|   screen->guard_window = None; | ||||
|  | ||||
|   screen->monitor_infos = NULL; | ||||
|   screen->n_monitor_infos = 0; | ||||
|   screen->last_monitor_index = 0;   | ||||
|    | ||||
|   reload_monitor_infos (screen); | ||||
|    | ||||
|   meta_screen_set_cursor (screen, META_CURSOR_DEFAULT); | ||||
| @@ -941,7 +789,7 @@ meta_screen_new (MetaDisplay *display, | ||||
|  | ||||
|   meta_verbose ("Added screen %d ('%s') root 0x%lx\n", | ||||
|                 screen->number, screen->screen_name, screen->xroot); | ||||
|    | ||||
|  | ||||
|   return screen; | ||||
| } | ||||
|  | ||||
| @@ -2997,19 +2845,15 @@ meta_screen_resize_func (MetaScreen *screen, | ||||
|   meta_window_recalc_features (window); | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_screen_resize (MetaScreen *screen, | ||||
|                     int         width, | ||||
|                     int         height) | ||||
| static void | ||||
| on_monitors_changed (MetaMonitorManager *manager, | ||||
|                      MetaScreen         *screen) | ||||
| { | ||||
|   GSList *windows, *tmp; | ||||
|   MetaMonitorInfo *old_monitor_infos; | ||||
|   GSList *tmp, *windows; | ||||
|  | ||||
|   screen->rect.width = width; | ||||
|   screen->rect.height = height; | ||||
|  | ||||
|   /* Save the old monitor infos, so they stay valid during the update */ | ||||
|   old_monitor_infos = screen->monitor_infos; | ||||
|   meta_monitor_manager_get_screen_size (manager, | ||||
|                                         &screen->rect.width, | ||||
|                                         &screen->rect.height); | ||||
|  | ||||
|   reload_monitor_infos (screen); | ||||
|   set_desktop_geometry_hint (screen); | ||||
| @@ -3021,8 +2865,8 @@ meta_screen_resize (MetaScreen *screen, | ||||
|  | ||||
|       changes.x = 0; | ||||
|       changes.y = 0; | ||||
|       changes.width = width; | ||||
|       changes.height = height; | ||||
|       changes.width = screen->rect.width; | ||||
|       changes.height = screen->rect.height; | ||||
|  | ||||
|       XConfigureWindow(screen->display->xdisplay, | ||||
|                        screen->guard_window, | ||||
| @@ -3032,7 +2876,8 @@ meta_screen_resize (MetaScreen *screen, | ||||
|  | ||||
|   if (screen->display->compositor) | ||||
|     meta_compositor_sync_screen_size (screen->display->compositor, | ||||
| 				      screen, width, height); | ||||
| 				      screen, | ||||
|                                       screen->rect.width, screen->rect.height); | ||||
|  | ||||
|   /* Queue a resize on all the windows */ | ||||
|   meta_screen_foreach_window (screen, meta_screen_resize_func, 0); | ||||
| @@ -3048,7 +2893,6 @@ meta_screen_resize (MetaScreen *screen, | ||||
|         meta_window_update_for_monitors_changed (window); | ||||
|     } | ||||
|  | ||||
|   g_free (old_monitor_infos); | ||||
|   g_slist_free (windows); | ||||
|  | ||||
|   meta_screen_queue_check_fullscreen (screen); | ||||
|   | ||||
							
								
								
									
										133
									
								
								src/core/util.c
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								src/core/util.c
									
									
									
									
									
								
							| @@ -332,6 +332,8 @@ topic_name (MetaDebugTopic topic) | ||||
|       return "COMPOSITOR"; | ||||
|     case META_DEBUG_EDGE_RESISTANCE: | ||||
|       return "EDGE_RESISTANCE"; | ||||
|     case META_DEBUG_DBUS: | ||||
|       return "DBUS"; | ||||
|     case META_DEBUG_VERBOSE: | ||||
|       return "VERBOSE"; | ||||
|     } | ||||
| @@ -389,91 +391,100 @@ meta_topic_real (MetaDebugTopic topic, | ||||
| } | ||||
| #endif /* WITH_VERBOSE_MODE */ | ||||
|  | ||||
| #ifdef WITH_VERBOSE_MODE | ||||
| static void | ||||
| logfile_log_handler (const gchar *log_domain, | ||||
|                      GLogLevelFlags log_level, | ||||
|                      const gchar *message, | ||||
|                      gpointer user_data) | ||||
| { | ||||
|   switch (log_level & G_LOG_LEVEL_MASK) { | ||||
|   case G_LOG_LEVEL_ERROR: | ||||
|     utf8_fputs ("ERROR: ", logfile); | ||||
|     break; | ||||
|  | ||||
|   case G_LOG_LEVEL_CRITICAL: | ||||
|     utf8_fputs ("CRITICAL: ", logfile); | ||||
|     break; | ||||
|  | ||||
|   case G_LOG_LEVEL_WARNING: | ||||
|     utf8_fputs ("WARNING: ", logfile); | ||||
|     break; | ||||
|  | ||||
|   default: | ||||
|     /* the other levels don't go through | ||||
|        g_log, they go directly to the log file */ | ||||
|     ; | ||||
|   } | ||||
|  | ||||
|   utf8_fputs (message, logfile); | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_debug_init (void) | ||||
| { | ||||
|   ensure_logfile (); | ||||
|  | ||||
|   if (logfile) | ||||
|     g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, | ||||
|                        logfile_log_handler, NULL); | ||||
| } | ||||
| #else | ||||
| void | ||||
| meta_debug_init (void) | ||||
| { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void | ||||
| meta_bug (const char *format, ...) | ||||
| { | ||||
|   char *stripped; | ||||
|   va_list args; | ||||
|   gchar *str; | ||||
|   FILE *out; | ||||
|  | ||||
|   g_return_if_fail (format != NULL); | ||||
|    | ||||
|  | ||||
|   stripped = g_strstrip (g_strdup (format)); | ||||
|  | ||||
|   va_start (args, format); | ||||
|   str = g_strdup_vprintf (format, args); | ||||
|   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, stripped, args); | ||||
|   va_end (args); | ||||
|  | ||||
| #ifdef WITH_VERBOSE_MODE | ||||
|   out = logfile ? logfile : stderr; | ||||
| #else | ||||
|   out = stderr; | ||||
| #endif | ||||
|  | ||||
|   if (no_prefix == 0) | ||||
|     utf8_fputs (_("Bug in window manager: "), out); | ||||
|   utf8_fputs (str, out); | ||||
|  | ||||
|   fflush (out); | ||||
|    | ||||
|   g_free (str); | ||||
|    | ||||
|   /* stop us in a debugger */ | ||||
|   abort (); | ||||
|   g_free (stripped); | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_warning (const char *format, ...) | ||||
| { | ||||
|   char *stripped; | ||||
|   va_list args; | ||||
|   gchar *str; | ||||
|   FILE *out; | ||||
|    | ||||
|  | ||||
|   g_return_if_fail (format != NULL); | ||||
|    | ||||
|  | ||||
|   stripped = g_strstrip (g_strdup (format)); | ||||
|  | ||||
|   va_start (args, format); | ||||
|   str = g_strdup_vprintf (format, args); | ||||
|   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, stripped, args); | ||||
|   va_end (args); | ||||
|  | ||||
| #ifdef WITH_VERBOSE_MODE | ||||
|   out = logfile ? logfile : stderr; | ||||
| #else | ||||
|   out = stderr; | ||||
| #endif | ||||
|  | ||||
|   if (no_prefix == 0) | ||||
|     utf8_fputs (_("Window manager warning: "), out); | ||||
|   utf8_fputs (str, out); | ||||
|  | ||||
|   fflush (out); | ||||
|    | ||||
|   g_free (str); | ||||
|   g_free (stripped); | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_fatal (const char *format, ...) | ||||
| { | ||||
|   char *stripped; | ||||
|   va_list args; | ||||
|   gchar *str; | ||||
|   FILE *out; | ||||
|    | ||||
|  | ||||
|   g_return_if_fail (format != NULL); | ||||
|    | ||||
|  | ||||
|   stripped = g_strstrip (g_strdup (format)); | ||||
|  | ||||
|   va_start (args, format); | ||||
|   str = g_strdup_vprintf (format, args); | ||||
|   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, stripped, args); | ||||
|   va_end (args); | ||||
|  | ||||
| #ifdef WITH_VERBOSE_MODE | ||||
|   out = logfile ? logfile : stderr; | ||||
| #else | ||||
|   out = stderr; | ||||
| #endif | ||||
|  | ||||
|   if (no_prefix == 0) | ||||
|     utf8_fputs (_("Window manager error: "), out); | ||||
|   utf8_fputs (str, out); | ||||
|  | ||||
|   fflush (out); | ||||
|    | ||||
|   g_free (str); | ||||
|   g_free (stripped); | ||||
|  | ||||
|   meta_exit (META_EXIT_ERROR); | ||||
| } | ||||
| @@ -495,7 +506,6 @@ meta_pop_no_msg_prefix (void) | ||||
| void | ||||
| meta_exit (MetaExitCode code) | ||||
| { | ||||
|    | ||||
|   exit (code); | ||||
| } | ||||
|  | ||||
| @@ -637,8 +647,13 @@ meta_show_dialog (const char *type, | ||||
|  | ||||
|   append_argument (args, "zenity"); | ||||
|   append_argument (args, type); | ||||
|   append_argument (args, "--display"); | ||||
|   append_argument (args, display); | ||||
|  | ||||
|   if (display) | ||||
|     { | ||||
|       append_argument (args, "--display"); | ||||
|       append_argument (args, display); | ||||
|     } | ||||
|  | ||||
|   append_argument (args, "--class"); | ||||
|   append_argument (args, "mutter-dialog"); | ||||
|   append_argument (args, "--title"); | ||||
|   | ||||
| @@ -165,7 +165,7 @@ struct _MetaWindow | ||||
|    * been overridden (via a client message), the window will cover the union of | ||||
|    * these monitors.  If not, this is the single monitor which the window's | ||||
|    * origin is on. */ | ||||
|   long fullscreen_monitors[4]; | ||||
|   gint fullscreen_monitors[4]; | ||||
|    | ||||
|   /* Whether we're trying to constrain the window to be fully onscreen */ | ||||
|   guint require_fully_onscreen : 1; | ||||
|   | ||||
| @@ -2108,10 +2108,14 @@ set_net_wm_state (MetaWindow *window) | ||||
|  | ||||
|   if (window->fullscreen) | ||||
|     { | ||||
|       data[0] = window->fullscreen_monitors[0]; | ||||
|       data[1] = window->fullscreen_monitors[1]; | ||||
|       data[2] = window->fullscreen_monitors[2]; | ||||
|       data[3] = window->fullscreen_monitors[3]; | ||||
|       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); | ||||
| @@ -4785,7 +4789,8 @@ meta_window_update_for_monitors_changed (MetaWindow *window) | ||||
|     { | ||||
|       MetaMonitorInfo *info = &window->screen->monitor_infos[i]; | ||||
|  | ||||
|       if (info->output == old->output) | ||||
|       if (info->output_id != 0 && | ||||
|           info->output_id == old->output_id) | ||||
|         { | ||||
|           new = info; | ||||
|           break; | ||||
| @@ -7130,10 +7135,14 @@ meta_window_client_message (MetaWindow *window, | ||||
|       meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", | ||||
|                     window->desc); | ||||
|  | ||||
|       top = event->xclient.data.l[0]; | ||||
|       bottom = event->xclient.data.l[1]; | ||||
|       left = event->xclient.data.l[2]; | ||||
|       right = event->xclient.data.l[3]; | ||||
|       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); | ||||
|   | ||||
| @@ -72,6 +72,7 @@ item(_MUTTER_TIMESTAMP_PING) | ||||
| item(_MUTTER_FOCUS_SET) | ||||
| item(_MUTTER_SENTINEL) | ||||
| item(_MUTTER_VERSION) | ||||
| item(_MUTTER_PRESENTATION_OUTPUT) | ||||
| item(WM_CLIENT_MACHINE) | ||||
| item(MANAGER) | ||||
| item(TARGETS) | ||||
| @@ -79,6 +80,7 @@ item(MULTIPLE) | ||||
| item(TIMESTAMP) | ||||
| item(VERSION) | ||||
| item(ATOM_PAIR) | ||||
| item(BACKLIGHT) | ||||
|  | ||||
| /* Oddities: These are used, and we need atoms for them, | ||||
|  * but when we need all _NET_WM hints (i.e. when we're making | ||||
|   | ||||
| @@ -205,6 +205,21 @@ struct _MetaPluginClass | ||||
|   gboolean (*keybinding_filter) (MetaPlugin     *plugin, | ||||
|                                  MetaKeyBinding *binding); | ||||
|  | ||||
|   /** | ||||
|    * MetaPluginClass::confirm_display_config: | ||||
|    * @plugin: a #MetaPlugin | ||||
|    * | ||||
|    * Virtual function called when the display configuration changes. | ||||
|    * The common way to implement this function is to show some form | ||||
|    * of modal dialog that should ask the user if everything was ok. | ||||
|    * | ||||
|    * When confirmed by the user, the plugin must call meta_plugin_complete_display_change() | ||||
|    * to make the configuration permanent. If that function is not | ||||
|    * called within the timeout, the previous configuration will be | ||||
|    * reapplied. | ||||
|    */ | ||||
|   void (*confirm_display_change) (MetaPlugin *plugin); | ||||
|  | ||||
|   /** | ||||
|    * MetaPluginClass::plugin_info: | ||||
|    * @plugin: a #MetaPlugin | ||||
| @@ -214,6 +229,7 @@ struct _MetaPluginClass | ||||
|    * Returns: a #MetaPluginInfo. | ||||
|    */ | ||||
|   const MetaPluginInfo * (*plugin_info) (MetaPlugin *plugin); | ||||
|  | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -360,6 +376,10 @@ void | ||||
| meta_plugin_destroy_completed (MetaPlugin      *plugin, | ||||
|                                MetaWindowActor *actor); | ||||
|  | ||||
| void | ||||
| meta_plugin_complete_display_change (MetaPlugin *plugin, | ||||
|                                      gboolean    ok); | ||||
|  | ||||
| /** | ||||
|  * MetaModalOptions: | ||||
|  * @META_MODAL_POINTER_ALREADY_GRABBED: if set the pointer is already | ||||
|   | ||||
| @@ -100,7 +100,8 @@ typedef enum | ||||
|   META_DEBUG_RESIZING        = 1 << 18, | ||||
|   META_DEBUG_SHAPES          = 1 << 19, | ||||
|   META_DEBUG_COMPOSITOR      = 1 << 20, | ||||
|   META_DEBUG_EDGE_RESISTANCE = 1 << 21 | ||||
|   META_DEBUG_EDGE_RESISTANCE = 1 << 21, | ||||
|   META_DEBUG_DBUS            = 1 << 22 | ||||
| } MetaDebugTopic; | ||||
|  | ||||
| void meta_topic_real      (MetaDebugTopic topic, | ||||
| @@ -109,6 +110,8 @@ void meta_topic_real      (MetaDebugTopic topic, | ||||
| void meta_add_verbose_topic    (MetaDebugTopic topic); | ||||
| void meta_remove_verbose_topic (MetaDebugTopic topic); | ||||
|  | ||||
| void meta_debug_init      (void); | ||||
|  | ||||
| void meta_push_no_msg_prefix (void); | ||||
| void meta_pop_no_msg_prefix  (void); | ||||
|  | ||||
|   | ||||
							
								
								
									
										281
									
								
								src/xrandr.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								src/xrandr.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,281 @@ | ||||
| <!DOCTYPE node PUBLIC | ||||
| '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' | ||||
| 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'> | ||||
| <node> | ||||
|   <!-- | ||||
|       org.gnome.Mutter.DisplayConfig: | ||||
|       @short_description: display configuration interface | ||||
|  | ||||
|       This interface is used by mutter and gnome-settings-daemon | ||||
|       to apply multiple monitor configuration. | ||||
|   --> | ||||
|  | ||||
|   <interface name="org.gnome.Mutter.DisplayConfig"> | ||||
|  | ||||
|     <!-- | ||||
|         GetResources: | ||||
| 	@serial: configuration serial | ||||
| 	@crtcs: available CRTCs | ||||
| 	@outputs: available outputs | ||||
| 	@modes: available modes | ||||
| 	@max_screen_width: | ||||
| 	@max_screen_height: | ||||
|  | ||||
|         Retrieves the current layout of the hardware. | ||||
|  | ||||
|         @serial is an unique identifier representing the current state | ||||
|         of the screen. It must be passed back to ApplyConfiguration() | ||||
| 	and will be increased for every configuration change (so that | ||||
| 	mutter can detect that the new configuration is based on old | ||||
| 	state). | ||||
|  | ||||
| 	A CRTC (CRT controller) is a logical monitor, ie a portion | ||||
| 	of the compositor coordinate space. It might correspond | ||||
| 	to multiple monitors, when in clone mode, but not that | ||||
| 	it is possible to implement clone mode also by setting different | ||||
| 	CRTCs to the same coordinates. | ||||
|  | ||||
| 	The number of CRTCs represent the maximum number of monitors | ||||
| 	that can be set to expand and it is a HW constraint; if more | ||||
| 	monitors are connected,	then necessarily some will clone. This | ||||
| 	is complementary to the concept of the encoder (not exposed in | ||||
| 	the API), which groups outputs that necessarily will show the | ||||
| 	same image (again a HW constraint). | ||||
|  | ||||
| 	A CRTC is represented by a DBus structure with the following | ||||
| 	layout: | ||||
| 	* u ID: the ID in the API of this CRTC | ||||
| 	* x winsys_id: the low-level ID of this CRTC (which might | ||||
| 	               be a XID, a KMS handle or something entirely | ||||
| 		       different) | ||||
| 	* i x, y, width, height: the geometry of this CRTC | ||||
| 	                         (might be invalid if the CRTC is not in | ||||
| 				 use) | ||||
| 	* i current_mode: the current mode of the CRTC, or -1 if this | ||||
| 	                  CRTC is not used | ||||
| 			  Note: the size of the mode will always correspond | ||||
| 			  to the width and height of the CRTC | ||||
| 	* u current_transform: the current transform (espressed according | ||||
| 	                       to the wayland protocol) | ||||
| 	* au transforms: all possible transforms | ||||
| 	* a{sv} properties: other high-level properties that affect this | ||||
| 	                    CRTC; they are not necessarily reflected in | ||||
| 			    the hardware. | ||||
| 			    No property is specified in this version of the API. | ||||
|  | ||||
|         Note: all geometry information refers to the untransformed | ||||
| 	display. | ||||
|  | ||||
| 	An output represents a physical screen, connected somewhere to | ||||
| 	the computer. Floating connectors are not exposed in the API. | ||||
| 	An output is a DBus struct with the following fields: | ||||
| 	* u ID: the ID in the API | ||||
| 	* x winsys_id: the low-level ID of this output (XID or KMS handle) | ||||
| 	* i current_crtc: the CRTC that is currently driving this output, | ||||
| 	                  or -1 if the output is disabled | ||||
| 	* au possible_crtcs: all CRTCs that can control this output | ||||
| 	* s name: the name of the connector to which the output is attached | ||||
| 	          (like VGA1 or HDMI) | ||||
| 	* au modes: valid modes for this output | ||||
| 	* au clones: valid clones for this output, ie other outputs that | ||||
| 	             can be assigned the same CRTC as this one; if you | ||||
| 	             want to mirror two outputs that don't have each other | ||||
| 	             in the clone list, you must configure two different | ||||
| 	             CRTCs for the same geometry | ||||
| 	* a{sv} properties: other high-level properties that affect this | ||||
| 	                    output; they are not necessarily reflected in | ||||
| 			    the hardware. | ||||
| 			    Known properties: | ||||
|                             - "vendor" (s): (readonly) the human readable name | ||||
|                                             of the manufacturer | ||||
|                             - "product" (s): (readonly) the human readable name | ||||
|                                              of the display model | ||||
|                             - "serial" (s): (readonly) the serial number of this | ||||
|                                             particular hardware part | ||||
| 			    - "display-name" (s): (readonly) a human readable name | ||||
| 			                          of this output, to be shown in the UI | ||||
| 	                    - "backlight" (i): (readonly, use the specific interface) | ||||
|                                                the backlight value as a percentage | ||||
|                                                (-1 if not supported) | ||||
| 			    - "primary" (b): whether this output is primary | ||||
| 			                     or not | ||||
| 			    - "presentation" (b): whether this output is | ||||
| 			                          for presentation only | ||||
| 			    Note: properties might be ignored if not consistenly | ||||
| 			    applied to all outputs in the same clone group. In | ||||
| 			    general, it's expected that presentation or primary | ||||
| 			    outputs will not be cloned. | ||||
|  | ||||
|         A mode represents a set of parameters that are applied to | ||||
| 	each output, such as resolution and refresh rate. It is a separate | ||||
| 	object so that it can be referenced by CRTCs and outputs. | ||||
| 	Multiple outputs in the same CRTCs must all have the same mode. | ||||
| 	A mode is exposed as: | ||||
| 	* u ID: the ID in the API | ||||
| 	* x winsys_id: the low-level ID of this mode | ||||
| 	* u width, height: the resolution | ||||
| 	* d frequency: refresh rate | ||||
|  | ||||
|         Output and modes are read-only objects (except for output properties), | ||||
| 	they can change only in accordance to HW changes (such as hotplugging | ||||
| 	a monitor), while CRTCs can be changed with ApplyConfiguration(). | ||||
|  | ||||
|         XXX: actually, if you insist enough, you can add new modes | ||||
| 	through xrandr command line or the KMS API, overriding what the | ||||
| 	kernel driver and the EDID say. | ||||
| 	Usually, it only matters with old cards with broken drivers, or | ||||
| 	old monitors with broken EDIDs, but it happens more often with | ||||
| 	projectors (if for example the kernel driver doesn't add the | ||||
| 	640x480 - 800x600 - 1024x768 default modes). Probably something | ||||
| 	that we need to handle in mutter anyway. | ||||
|     --> | ||||
|     <method name="GetResources"> | ||||
|       <arg name="serial" direction="out" type="u" /> | ||||
|       <arg name="crtcs" direction="out" type="a(uxiiiiiuaua{sv})" /> | ||||
|       <arg name="outputs" direction="out" type="a(uxiausauaua{sv})" /> | ||||
|       <arg name="modes" direction="out" type="a(uxuud)" /> | ||||
|       <arg name="max_screen_width" direction="out" type="i" /> | ||||
|       <arg name="max_screen_height" direction="out" type="i" /> | ||||
|     </method> | ||||
|  | ||||
|     <!-- | ||||
|         ApplyConfiguration: | ||||
| 	@serial: configuration serial | ||||
| 	@persistent: whether this configuration should be saved on disk | ||||
| 	@crtcs: new data for CRTCs | ||||
| 	@outputs: new data for outputs | ||||
|  | ||||
| 	Applies the requested configuration changes. | ||||
|  | ||||
| 	@serial must match the serial from the last GetResources() call, | ||||
| 	or org.freedesktop.DBus.AccessDenied will be generated. | ||||
|  | ||||
| 	If @persistent is true, mutter will attempt to replicate this | ||||
| 	configuration the next time this HW layout appears. | ||||
|  | ||||
| 	@crtcs represents the new logical configuration, as a list | ||||
| 	of structures containing: | ||||
| 	- u ID: the API ID from the corresponding GetResources() call | ||||
| 	- i new_mode: the API ID of the new mode to configure the CRTC | ||||
| 	              with, or -1 if the CRTC should be disabled | ||||
|         - i x, y: the new coordinates of the top left corner | ||||
| 	          the geometry will be completed with the size information | ||||
| 		  from @new_mode | ||||
|         - u transform: the desired transform | ||||
| 	- au outputs: the API ID of outputs that should be assigned to | ||||
| 	              this CRTC | ||||
|         - a{sv} properties: properties whose value should be changed | ||||
|  | ||||
| 	Note: CRTCs not referenced in the array will be	disabled. | ||||
|  | ||||
| 	@outputs represent the output property changes as: | ||||
| 	- u ID: the API ID of the output to change | ||||
| 	- a{sv} properties: properties whose value should be changed | ||||
|  | ||||
| 	Note: both for CRTCs and outputs, properties not included in | ||||
| 	the dictionary will not be changed. | ||||
|  | ||||
| 	Note: unrecognized properties will have no effect, but if the | ||||
| 	configuration change succeeds the property will be reported | ||||
| 	by the next GetResources() call, and if @persistent is true, | ||||
| 	it will also be saved to disk. | ||||
|  | ||||
| 	If the configuration is invalid according to the previous | ||||
| 	GetResources() call, for example because a CRTC references | ||||
| 	an output it cannot drive, or not all outputs support the | ||||
| 	chosen mode, the error org.freedesktop.DBus.InvalidArgs will | ||||
| 	be generated. | ||||
|  | ||||
| 	If the configuration cannot be applied for any other reason | ||||
| 	(eg. the screen size would exceed texture limits), the error | ||||
| 	org.freedesktop.DBus.Error.LimitsExceeded will be generated. | ||||
|     --> | ||||
|     <method name="ApplyConfiguration"> | ||||
|       <arg name="serial" direction="in" type="u" /> | ||||
|       <arg name="persistent" direction="in" type="b" /> | ||||
|       <arg name="crtcs" direction="in" type="a(uiiiuaua{sv})" /> | ||||
|       <arg name="outputs" direction="in" type="a(ua{sv})" /> | ||||
|     </method> | ||||
|  | ||||
|     <!-- | ||||
|         ChangeBacklight: | ||||
| 	@serial: configuration serial | ||||
| 	@output: the API id of the output | ||||
| 	@value: the new backlight value | ||||
|  | ||||
| 	Changes the backlight of @output to @value, which is | ||||
| 	expressed as a percentage and rounded to the HW limits. | ||||
|     --> | ||||
|     <method name="ChangeBacklight"> | ||||
|       <arg name="serial" direction="in" type="u" /> | ||||
|       <arg name="output" direction="in" type="u" /> | ||||
|       <arg name="value" direction="in" type="i" /> | ||||
|     </method> | ||||
|  | ||||
|     <!-- | ||||
|         GetCrtcGamma: | ||||
| 	@serial: configuration serial | ||||
| 	@crtc: API id of the crtc | ||||
| 	@red: red gamma ramp | ||||
| 	@green: green gamma ramp | ||||
| 	@blue: blue gamma ramp | ||||
|  | ||||
| 	Requests the current gamma ramps of @crtc. | ||||
|     --> | ||||
|     <method name="GetCrtcGamma"> | ||||
|       <arg name="serial" direction="in" type="u" /> | ||||
|       <arg name="crtc" direction="in" type="u" /> | ||||
|       <arg name="red" direction="out" type="aq" /> | ||||
|       <arg name="green" direction="out" type="aq" /> | ||||
|       <arg name="blue" direction="out" type="aq" /> | ||||
|     </method> | ||||
|  | ||||
|     <!-- | ||||
|         SetCrtcGamma: | ||||
| 	@serial: configuration serial | ||||
| 	@crtc: API id of the crtc | ||||
| 	@red: red gamma ramp | ||||
| 	@green: green gamma ramp | ||||
| 	@blue: blue gamma ramp | ||||
|  | ||||
| 	Changes the gamma ramps of @crtc. | ||||
|     --> | ||||
|     <method name="SetCrtcGamma"> | ||||
|       <arg name="serial" direction="in" type="u" /> | ||||
|       <arg name="crtc" direction="in" type="u" /> | ||||
|       <arg name="red" direction="in" type="aq" /> | ||||
|       <arg name="green" direction="in" type="aq" /> | ||||
|       <arg name="blue" direction="in" type="aq" /> | ||||
|     </method> | ||||
|  | ||||
|     <!-- | ||||
|         PowerSaveMode: | ||||
|  | ||||
| 	Contains the current power saving mode for the screen, and | ||||
| 	allows changing it. | ||||
|  | ||||
|         Possible values: | ||||
| 	- 0: on | ||||
| 	- 1: standby | ||||
| 	- 2: suspend | ||||
| 	- 3: off | ||||
| 	- -1: unknown (unsupported) | ||||
|  | ||||
|         A client should not attempt to change the powersave mode | ||||
| 	from -1 (unknown) to any other value, and viceversa. | ||||
| 	Note that the actual effects of the different values | ||||
| 	depend on the hardware and the kernel driver in use, and | ||||
| 	it's perfectly possible that all values different than on | ||||
| 	have the same effect. | ||||
| 	Also, setting the PowerSaveMode to 3 (off) may or may | ||||
| 	not have the same effect as disabling all outputs by | ||||
| 	setting no CRTC on them with ApplyConfiguration(), and | ||||
| 	may or may not cause a configuration change. | ||||
|  | ||||
|         Also note that this property might become out of date | ||||
| 	if changed through different means (for example using the | ||||
| 	XRandR interface directly). | ||||
|     --> | ||||
|     <property name="PowerSaveMode" type="i" access="readwrite" /> | ||||
|   </interface> | ||||
| </node> | ||||
		Reference in New Issue
	
	Block a user