cinnamon-desktop-5.2.1/ 0000775 0001750 0001750 00000000000 14167325242 013722 5 ustar fabio fabio cinnamon-desktop-5.2.1/schemas/ 0000775 0001750 0001750 00000000000 14167325242 015345 5 ustar fabio fabio cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.interface.gschema.xml.in 0000664 0001750 0001750 00000025621 14167325242 026107 0 ustar fabio fabio
falseEnable Toolkit Accessibility
Whether toolkits should load accessibility related modules.
trueEnable Animations
Whether animations should be displayed. Note: This is a global key,
it changes the behaviour of the window manager, the panel etc.
falseMenus Have Tearoff
Whether menus should have a tearoff.
falseCan Change Accels
Whether the user can dynamically type a new accelerator when
positioned over an active menuitem.
'both-horiz'Toolbar Style
Toolbar Style. Valid values are "both", "both-horiz", "icons",
and "text".
trueMenus Have Icons
Whether menus may display an icon next to a menu entry.
falseButtons Have Icons
Whether buttons may display an icon in addition to the button text.
falseMenubar Detachable
Whether the user can detach menubars and move them around.
falseToolbar Detachable
Whether the user can detach toolbars and move them around.
'large'Toolbar Icon Size
Size of icons in toolbars, either "small" or "large".
trueCursor Blink
Whether the cursor should blink.
1200Cursor Blink Time
Length of the cursor blink cycle, in milliseconds.
10Cursor Blink Timeout
Time after which the cursor stops blinking, in seconds.
'gnome'Icon Theme
Icon theme to use for the panel, nautilus etc.
'gnome'Icon Theme Backup
This is used to store the current icon theme when high contrast is enabled.
'Adwaita'Gtk+ Theme
Basename of the default theme used by gtk+.
'Adwaita'Gtk+ Theme Backup
This is used to store the current theme when enabling high contrast.
'Default'Gtk+ Keybinding Theme
Basename of the default keybinding theme used by gtk+.
'Sans 9'Default font
Name of the default font used by gtk+.
1.0Text scaling factor
Factor used to enlarge or reduce text display, without changing font size.
'callback'GTK IM Preedit Style
Name of the GTK+ input method Preedit Style used by gtk+.
0Window scaling factor
Integer factor used to scale windows by. For use on high-dpi screens.
0 means pick automatically based on monitor.
falseAchieve fractional scaling by scaling up.
Fractional scaling is usually achieved by setting the global scale factor to a higher value and then scaling down. Scaling up instead yields better performance but poorer quality - in certain configurations and hardware, this may be acceptable.
'callback'GTK IM Status Style
Name of the GTK+ input method Status Style used by gtk+.
''GTK IM Module
Name of the input method module used by GTK+.
'F10'Menubar accelerator
Keyboard shortcut to open the menu bars.
trueShow the 'Input Methods' menu
Whether the context menus of entries and text views should offer to
change the input method.
trueShow the 'Unicode Control Character' menu
Whether the context menus of entries and text views should offer to
insert control characters.
'Adwaita'Cursor themeCursor theme name. Used only by Xservers that support the Xcursor extension.24Cursor sizeSize of the cursor used as cursor theme. Note, depending on the ui scale (hidpi), this number
may not represent the actual cursor size200Timeout before click repeatTimeout in milliseconds before a click starts repeating (on spinner buttons for example).20Timeout between click repeatsTimeout in milliseconds between repeated clicks when a button is left pressed.'black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90'Palette used in the color selectorPalette used in the color selector as defined by the 'gtk-color-palette' setting''List of symbolic names and color equivalentsA '\n' separated list of "name:color" as defined by the 'gtk-color-scheme' settingtrueWhether the clock displays in 24h format
Whether the clock displays in 24h format
falseWhether the clock shows seconds
If true, display seconds in the clock.
falseShow date in clock
If true, display date in the clock, in addition to time.
7First day of week in the calendar
Sets the first day of week, with 7 the locale default.
trueOnly show mnemonics on when the Alt key is pressed
Whether mnemonics should be automatically shown and hidden when the user
presses the Alt key.
trueEnable or disable gtk overlay scrollbarstruePrefer country flags to group names when showing keyboard layouts.falsePrefer upper-case group names showing keyboard layouts. False for lowercase.falsePrefer variant names instead of country codes when showing keyboard layouts.
cinnamon-desktop-5.2.1/schemas/meson.build 0000664 0001750 0001750 00000001537 14167325242 017515 0 ustar fabio fabio desktop_gschemas = [
'a11y.applications',
'a11y.keyboard',
'a11y.magnifier',
'a11y.mouse',
'background',
'default-applications',
'input-sources',
'interface',
'keybindings.media-keys',
'keybindings.wm',
'keybindings',
'lockdown',
'media-handling',
'notifications',
'privacy',
'screensaver',
'session',
'sound',
'thumbnail-cache',
'thumbnailers',
'wm.preferences',
]
gschema_conf = configuration_data()
gschema_conf.set('datadir', join_paths(get_option('prefix'), get_option('datadir')))
foreach schema : desktop_gschemas
schema_file = 'org.cinnamon.desktop.' + schema + '.gschema.xml'
schema_configured = configure_file(
input : schema_file + '.in',
output: schema_file,
configuration : gschema_conf,
install : true,
install_dir : get_option('datadir') / 'glib-2.0' / 'schemas'
)
endforeach
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.notifications.gschema.xml.in 0000664 0001750 0001750 00000002645 14167325242 027021 0 ustar fabio fabio
trueNotifications fade outSet this to TRUE to allow notifications to fade under the mouse.falseRemove old notificationsCheck this to automatically remove old notifications.1800Notification timeoutDuration to keep store a notification in persitence.40Opacity (percent) to use when mousing over a notificationOpacity (percent) to use for notification fadestrueWhether notifications are to be displayedfalseWhether notifications are displayed on the bottom side of the screen
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.thumbnail-cache.gschema.xml.in 0000664 0001750 0001750 00000001063 14167325242 027165 0 ustar fabio fabio
180Maximum age for thumbnails in the cache, in days. Set to -1 to disable cleaning.512Maximum size of the thumbnail cache, in megabytes. Set to -1 to disable cleaning.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.default-applications.gschema.xml.in 0000664 0001750 0001750 00000006127 14167325242 030257 0 ustar fabio fabio
'evolution -c calendar'Default calendar
Default calendar application
falseCalendar needs terminal
Whether the default calendar application needs a terminal to run.
'evolution -c tasks'Default tasks
Default tasks application.
falseTasks needs terminal
Whether the default tasks application needs a terminal to run.
'gnome-terminal'Terminal application
Terminal program to use when starting applications that require one.
'--'Exec Arguments
Argument used to execute programs in the terminal defined by the
'exec' key.
'gnome-calculator'Default calculator
Default calculator application.
falseCalculator needs terminal
Whether the default calculator application needs a terminal to run.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.session.gschema.xml.in 0000664 0001750 0001750 00000001637 14167325242 025633 0 ustar fabio fabio
900Time before session is considered idleThe number of seconds of inactivity before the session is considered idle."cinnamon"Session typeThe name of the session to use. Known values are
"gnome" and "gnome-fallback".true*no longer used*true*no longer used*
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.sound.gschema.xml.in 0000664 0001750 0001750 00000002746 14167325242 025302 0 ustar fabio fabio
falseSounds for eventsWhether to play sounds on user events.'freedesktop'Sound theme nameThe XDG sound theme to use for event sounds.falseInput feedback soundsWhether to play sounds on input events.falseWhether to play a sound when the volume is changedWhether to play a sound when the volume is changed.""Which sound to play when the volume is changedWhich sound to play when the volume is changed.100The maximum sound volumeThe maximum sound volume the user can set via the sound applet, settings and volume keys.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.a11y.mouse.gschema.xml.in 0000664 0001750 0001750 00000005371 14167325242 026051 0 ustar fabio fabio
1.20Dwell click timeTime in seconds before a click is triggered.10Movement thresholdDistance in pixels before movement will be recognized.'left'Gesture single clickDirection to perform a single click ('left', 'right', 'up', 'down).'up'Gesture double clickDirection to perform a double click ('left', 'right', 'up', 'down).'down'Gesture drag clickDirection to perform dragging ('left', 'right', 'up', 'down).'right'Gesture secondary clickDirection to perform a secondary click ('left', 'right', 'up', 'down).'window'Dwell click modeThe active dwell click mode. Possible values are 'window' and 'gesture'.trueShow click type windowShow click type window.falseEnable dwell clicksEnable dwell clicks.falseSecondary click enabledEnable simulated secondary clicks1.20Secondary click timeTime in seconds before a simulated secondary click is triggered.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.wm.preferences.gschema.xml.in 0000664 0001750 0001750 00000037355 14167325242 027101 0 ustar fabio fabio
']]>Modifier to use for modified window click actions
Clicking a window while holding down this modifier key will move the
window (left click), resize the window (middle click), or show the
window menu (right click). The middle and right click operations may
be swapped using the "resize-with-right-button" key. Modifier is
expressed as "]]> or "]]> for example.
']]>Modifier to use for a11y mouse desktop zoom
Operating the mouse wheel while holding down this modifier key will
zoom the desktop in and out if desktop magnifier is enabled. Modifier is
expressed as "]]> or "]]> for example.
trueWhether to resize with the right button
Set this to true to resize with the right button and show a menu with
the middle button while holding down the key given in
"mouse-button-modifier"; set it to false to make it work
the opposite way around.
'menu:minimize,maximize,close'Arrangement of buttons on the titlebar
Arrangement of buttons on the titlebar. The value should be a string,
such as "menu:minimize,maximize,spacer,close"; the colon separates
the left corner of the window from the right corner, and the button
names are comma-separated. Duplicate buttons are not allowed. Unknown
button names are silently ignored so that buttons can be added in
future metacity versions without breaking older versions. A special
spacer tag can be used to insert some space between
two adjacent buttons.
'click'Window focus mode
The window focus mode indicates how windows are activated. It has
three possible values; "click" means windows must be clicked in order
to focus them, "sloppy" means windows are focused when the mouse enters
the window, and "mouse" means windows are focused when the mouse enters
the window and unfocused when the mouse leaves the window.
'smart'Control how new windows get focus
This option provides additional control over how newly created windows
get focus. It has two possible values; "smart" applies the user's
normal focus mode, and "strict" results in windows started from a
terminal not being given focus.
true
Whether raising should be a side-effect of other user interactions
Setting this option to false can lead to buggy behavior, so users are
strongly discouraged from changing it from the default of true. Many
actions (e.g. clicking in the client area, moving or resizing the window)
normally raise the window as a side-effect. Setting this option to false,
which is strongly discouraged, will decouple raising from other user
actions, and ignore raise requests generated by applications.
See http://bugzilla.gnome.org/show_bug.cgi?id=445447#c6.
Even when this option is false, windows can still be raised by an
alt-left-click anywhere on the window, a normal click on the window
decorations, or by special messages from pagers, such as activation
requests from tasklist applets. This option is currently disabled
in click-to-focus mode. Note that the list of ways to raise windows
when raise-on-click is false does not include programmatic requests
from applications to raise windows; such requests will be ignored
regardless of the reason for the request.
If you are an application developer and have a user complaining that
your application does not work with this setting disabled, tell them
it is -their- fault for breaking their window manager and that they
need to change this option back to true or live with the "bug"
they requested.
'toggle-maximize'Action on title bar double-click
This option determines the effects of double-clicking on the title bar.
Current valid options are 'toggle-shade', which will shade/unshade the
window, 'toggle-maximize' which will maximize/unmaximize the window,
'toggle-maximize-horizontally' and 'toggle-maximize-vertically'
which will maximize/unmaximize the window in that direction only,
'minimize' which will minimize the window, 'shade' which will roll
the window up, 'menu' which will display the window menu,
'lower' which will put the window behind all the others,
and 'none' which will not do anything.
'lower'Action on title bar middle-click
This option determines the effects of middle-clicking on the title bar.
Current valid options are 'toggle-shade', which will shade/unshade
the window, 'toggle-maximize' which will maximize/unmaximize the window,
'toggle-maximize-horizontally' and 'toggle-maximize-vertically'
which will maximize/unmaximize the window in that direction only,
'minimize' which will minimize the window, 'shade' which will roll
the window up, 'menu' which will display the window menu,
'lower' which will put the window behind all the others,
and 'none' which will not do anything.
'menu'Action on title bar right-click
This option determines the effects of right-clicking on the title bar.
Current valid options are 'toggle-shade', which will shade/unshade
the window, 'toggle-maximize' which will maximize/unmaximize
the window, 'toggle-maximize-horizontally' and
'toggle-maximize-vertically' which will maximize/unmaximize
the window in that direction only, 'minimize' which will minimize
the window, 'shade' which will roll the window up,
'menu' which will display the window menu, 'lower' which will put
the window behind all the others, and 'none' which will not do anything.
'none'Action on spinning the mouse wheel on the titlebar
This option determines the effects of using the mouse wheel on the title bar.
Current options are: opacity, shade
30Minimum allowable window opacity (by percent) via user adjustment
This is the minimum opacity (by percent) a user can adjust the window to when
using keybindings or the mouse wheel.
falseAutomatically raises the focused window
If set to true, and the focus mode is either "sloppy" or "mouse"
then the focused window will be automatically raised after a delay
specified by the auto-raise-delay key. This is not related to clicking
on a window to raise it, nor to entering a window during drag-and-drop.
500Delay in milliseconds for the auto raise option
The time delay before raising a window if auto-raise is set to true.
The delay is given in thousandths of a second.
'Adwaita'Current theme
The theme determines the appearance of window borders, titlebar,
and so forth.
'Adwaita'Current theme backup
This is used to store the current theme when enabling high contrast.
falseUse standard system font in window titles
If true, ignore the titlebar-font option, and use the standard
application font for window titles.
'Sans Bold 10'Window title font
A font description string describing a font for window titlebars.
The size from the description will only be used if the
titlebar-font-size option is set to 0. Also, this option is disabled
if the titlebar-uses-desktop-font option is set to true.
4Number of workspaces
Number of workspaces. Must be more than zero, and has a fixed maximum
to prevent making the desktop unusable by accidentally asking
for too many workspaces.
falseSystem Bell is Audible
Determines whether applications or the system can generate audible
'beeps'; may be used in conjunction with 'visual bell'
to allow silent 'beeps'.
falseEnable Visual Bell
Turns on a visual indication when an application or the system issues
a 'bell' or 'beep'; useful for the hard-of-hearing and for use
in noisy environments.
'fullscreen-flash'Visual Bell Type
Tells the WM how to implement the visual indication that the
system bell or another application 'bell' indicator has been rung.
Currently there are two valid values, "fullscreen-flash", which
causes a fullscreen white-black flash, and "frame-flash" which
causes the titlebar of the application which sent the bell signal
to flash.
If the application which sent the bell is unknown (as is usually
the case for the default "system beep"), the currently focused
window's titlebar is flashed.
'/usr/share/cinnamon/sounds/bell.ogg'Sound to use for the event bellfalse
(Not implemented) Navigation works in terms of applications not windows
If true, then the WM works in terms of applications rather than
windows. The concept is a bit abstract, but in general an
application-based setup is more like the Mac and less like Windows.
When you focus a window in application-based mode, all the windows
in the application will be raised. Also, in application-based mode,
focus clicks are not passed through to windows in other applications.
Application-based mode is, however, largely unimplemented
at the moment.
false
Disable misfeatures that are required by old or broken applications
Some applications disregard specifications in ways that result in
window manager misfeatures. This option puts the WM in a
rigorously correct mode, which gives a more consistent
user interface, provided one does not need to run any
misbehaving applications.
[]The names of the workspaces
Defines the names that should be assigned to workspaces.
If the list is too long for the current number of workspaces,
names in excess will be ignored. If the list is too short, or
includes empty names, missing values will be replaced with the
default ("Workspace N").
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.thumbnailers.gschema.xml.in 0000664 0001750 0001750 00000001510 14167325242 026633 0 ustar fabio fabio
falseDisable all external thumbnailers
Set to true to disable all external thumbnailer programs,
independent on whether they are independently disabled/enabled.
["image/jp2"]
List of mime-types for which external thumbnailer
programs will be disabled
Thumbnails will not be created for files whose mime-type is
contained in the list.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.screensaver.gschema.xml.in 0000664 0001750 0001750 00000015264 14167325242 026471 0 ustar fabio fabio
trueActivate when idleSet this to TRUE to activate the screensaver when the session is idle.trueLock on activationSet this to TRUE to lock the screen when the screensaver goes active.0Time before lockingThe number of seconds after screensaver activation before locking the screen.falseShow notifications in the lock screenWhether notifications are shown in the lock screen or not. This only affects the standard experience.falseAllow embedding a keyboard into the windowSet this to TRUE to allow embedding a keyboard into the window when trying to unlock. The "keyboard_command" key must be set with the appropriate command.''Embedded keyboard commandThe command that will be run, if the "embedded_keyboard_enabled" key is set to TRUE, to embed a keyboard widget into the window. This command should implement an XEMBED plug interface and output a window XID on the standard output.trueAllow user switchingSet this to TRUE to offer an option in the unlock dialog to switch to a different user account.trueAllow the session status message to be displayedAllow the session status message to be displayed when the screen is locked.""Default message for the screensaver
This is the message that appears on the lock screen by default.
falseWhether to ask for an away message when locking the screen
Whether to ask for an away message when locking the screen.
falseWhether to define a custom format for the date and time
Whether to use a custom date and time format for the lock screen.
"%H:%M"The custom time format
This is the time format that the lock screen will use if use-custom-format is enabled.
"%A %B %e"The custom date format
This is the date format that the lock screen will use if use-custom-format is enabled.
"Ubuntu 24"The date time font
This is the font that the date uses for the screen locker.
"Ubuntu 64"The time font
This is the font that the time uses for the screen locker.
"Ubuntu 14"The away message font
This is the font that the away message use for the screen locker.
""deprecated - does nothing""deprecated - does nothing""deprecated - does nothingtrueDisplay album art on the lock screenSet this to true to show album art on the lock screen, if available.trueControl whether keyboard shortcuts are allowed on the lock screentrueControl whether volume and media player controls are allowed on the lock screentrueControl whether the notification and power widgets are shown on the lock screentrueShow the clock when the normal wallpaper screensaver is activeThis controls whether the clock is shown while the wallpaper is active. Note, the clock will always show when unlocking, and it will never show if a screensaver plugin is active, regardless of this settingtrueControl whether the clock and albumart widgets will randomly change position over time.-1Keyboard layout group to use when entering your passwordThis stores the last active keyboard layout group for entering your password.""Specify custom screen locker commandIf empty, cinnamon-screensaver will be used
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.privacy.gschema.xml.in 0000664 0001750 0001750 00000003070 14167325242 025616 0 ustar fabio fabio
falseWhether to remove old files from the trash automaticallyIf TRUE, automatically remove files from the trash when they are older than 'old-files-age' days.falseWhether to remove old temporary files automaticallyIf TRUE, automatically remove temporary files when they are older than 'old-files-age' days.30Number of days to keep trash and temporary filesConsider trash and temporary files old after this many days.trueWhether to remember recently used filesIf FALSE, applications will not remember recently used files.7Number of days to remember recently used files forRecently used files will be remembered for this many days. If set to 0, recent files will not be remembered; if set to -1, they will be retained indefinitively.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.background.gschema.xml.in 0000664 0001750 0001750 00000006604 14167325242 026266 0 ustar fabio fabio
'zoom'Picture Options
Determines how the image set by wallpaper_filename is rendered.
Possible values are "none", "wallpaper", "centered", "scaled",
"stretched", "zoom", "spanned".
'file://@datadir@/themes/Adwaita/backgrounds/adwaita-timed.xml'Picture URI
URI to use for the background image. Not that the backend only supports
local (file://) URIs.
100Picture Opacity
Opacity with which to draw the background picture.
'#000000'Primary Color
Left or Top color when drawing gradients, or the solid color.
'#000000'Secondary Color
Right or Bottom color when drawing gradients, not used for solid color.
'solid'Color Shading Type
How to shade the background color. Possible values are "horizontal",
"vertical", and "solid".
falseWhether or not to use a slideshow for the desktop background
This key defines the whether the desktop background shows one single wallpaper,
or a slideshow of images.
""Source to use for the background slideshow
This key defines the source for the slideshow to get images from.
15Delay for the slideshow
This key defines the delay for the slideshow.
falseWhether or not to play the images in random order
This key defines whether images are shown in order or chosen randomly.
falseWhether the slideshow is currently playing or paused
This key defines whether the slideshow in currently in a playing or paused state.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.lockdown.gschema.xml.in 0000664 0001750 0001750 00000004607 14167325242 025770 0 ustar fabio fabio
falseDisable command line
Prevent the user from accessing the terminal or specifying a command
line to be executed. For example, this would disable access to the
panel's "Run Application" dialog.
falseDisable saving files to disk
Prevent the user from saving files to disk. For example, this would
disable access to all applications' "Save as" dialogs.
falseDisable printing
Prevent the user from printing. For example, this would disable access
to all applications' "Print" dialogs.
falseDisable print setup
Prevent the user from modifying print settings. For example, this would
disable access to all applications' "Print Setup" dialogs.
falseDisable user switching
Prevent the user from switching to another account while his session
is active.
falseDisable lock screen
Prevent the user to lock his screen.
falseDisable URL and MIME type handlers
Prevent running any URL or MIME type handler applications.
falseDisable log out
Prevent the user from logging out.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.keybindings.wm.gschema.xml.in 0000664 0001750 0001750 00000027773 14167325242 027111 0 ustar fabio fabio
r']]]>Left']]]>Right']]]>Up']]]>Down']]]>Left']]]>Right']]]>Up']]]>Down']]]>[]Select window from tab popup[]Cancel tab popup[]Switch to workspace 1[]Switch to workspace 2[]Switch to workspace 3[]Switch to workspace 4[]Switch to workspace 5[]Switch to workspace 6[]Switch to workspace 7[]Switch to workspace 8[]Switch to workspace 9[]Switch to workspace 10[]Switch to workspace 11[]Switch to workspace 12Left']]]>Switch to workspace leftRight']]]>Switch to workspace rightUp','F1']]]>Switch to workspace aboveDown']]]>Switch to workspace belowAbove_Tab']]]>Switch windows of an application[]Reverse switch windows of an applicationTab']]]>Switch applications[]Reverse switch applicationsTab']]]>Switch system controls[]Reverse switch system controlsd']]]>Hide all normal windowsF2']]]>Show the run command prompt[]Don't usespace']]]>Activate the window menu[]Toggle fullscreen modeF10']]]>Toggle maximization state[]Toggle window always appearing on top[]Maximize windowF5']]]>Restore window[]Toggle shaded state[]Minimize windowF4']]]>Close windowF7']]]>Move windowF8']]]>Resize window[]Toggle window on all workspaces or one[]Move window to workspace 1[]Move window to workspace 2[]Move window to workspace 3[]Move window to workspace 4[]Move window to workspace 5[]Move window to workspace 6[]Move window to workspace 7[]Move window to workspace 8[]Move window to workspace 9[]Move window to workspace 10[]Move window to workspace 11[]Move window to workspace 12Left']]]>Move window one workspace to the leftRight']]]>Move window one workspace to the rightUp']]]>Move window one workspace upDown']]]>Move window one workspace down[]Move window to a new workspaceLeft']]]>Move window one monitor to the leftRight']]]>Move window one monitor to the rightUp']]]>Move window one monitor upDown']]]>Move window one monitor down[]Raise window if covered, otherwise lower it[]Raise window above other windows[]Lower window below other windows[]Maximize window vertically[]Maximize window horizontally[]Move window to top left corner[]Move window to top right corner[]Move window to bottom left corner[]Move window to bottom right corner[]Move window to top edge of screen[]Move window to bottom edge of screen[]Move window to right side of screen[]Move window to left side of screen[]Move window to center of screen[]Increase the opacity of the current window[]Decrease the opacity of the current window
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.media-handling.gschema.xml.in 0000664 0001750 0001750 00000004731 14167325242 027007 0 ustar fabio fabio
trueWhether to automatically mount mediaIf set to true, then Nautilus will automatically mount media such as user-visible hard disks and removable media on start-up and media insertion.trueWhether to automatically open a folder for automounted mediaIf set to true, then Nautilus will automatically open a folder when media is automounted. This only applies to media where no known x-content/* type was detected; for media where a known x-content type is detected, the user configurable action will be taken instead.falseNever prompt or autorun/autostart programs when media are insertedIf set to true, then Nautilus will never prompt nor autorun/autostart programs when a medium is inserted.[ 'x-content/unix-software' ]List of x-content/* types where the preferred application will be launchedList of x-content/* types for which the user have chosen to start an application in the preference capplet. The preferred application for the given type will be started on insertion on media matching these types.[]List of x-content/* types set to "Do Nothing"List of x-content/* types for which the user have chosen "Do Nothing" in the preference capplet. No prompt will be shown nor will any matching application be started on insertion of media matching these types.[]List of x-content/* types set to "Open Folder"List of x-content/* types for which the user have chosen "Open Folder" in the preferences capplet. A folder window will be opened on insertion of media matching these types.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.a11y.magnifier.gschema.xml.in 0000664 0001750 0001750 00000017317 14167325242 026665 0 ustar fabio fabio
'proportional'Mouse Tracking Mode
Determines the position of the magnified mouse image within the
magnified view and how it reacts to system mouse movement. The values
are
- none: no mouse tracking;
- centered: the mouse image is
displayed at the center of the zoom region (which also represents
the point under the system mouse) and the magnified contents are
scrolled as the system mouse moves;
- proportional: the position of the magnified mouse in the zoom region
is proportionally the same as the position of the system mouse on screen;
- push: when the magnified mouse intersects a boundary of the zoom
region, the contents are scrolled into view.
'square'
The shape of lens to use in lens mode - a square, or a vertical or horizontal band.
'full-screen'Screen position
The magnified view either fills the entire screen, or occupies the
top-half, bottom-half, left-half, or right-half of the screen.
1.0Magnification factor
The power of the magnification. A value of 1.0 means no magnification.
A value of 2.0 doubles the size.
falseEnable lens mode
Whether the magnified view should be centered over the location of
the system mouse and move with it.
false
Scroll magnified contents beyond the edges of the desktop
For centered mouse tracking, when the system pointer is at or near the
edge of the screen, the magnified contents continue to scroll such that
the screen edge moves into the magnified view.
falseShow or hide crosshairs
Enables/disables display of crosshairs centered on the magnified
mouse sprite.
8Thickness of the crosshairs in pixels
Width in pixels of the vertical and horizontal lines that make up the crosshairs.
'#ff0000'Color of the crosshairs
The color of the the vertical and horizontal lines that make up
the crosshairs.
0.66Opacity of the crosshairs
Determines the transparency of the crosshairs, from fully opaque
to fully transparent.
4096Length of the crosshairs in pixels
Determines the length in pixels of the vertical and horizontal
lines that make up the crosshairs.
falseClip the crosshairs at the center
Determines whether the crosshairs intersect the magnified mouse sprite,
or are clipped such that the ends of the horizontal and vertical lines
surround the mouse image.
falseInverse lightness
Determines whether the lightness values are inverted: darker colors
become lighter and vice versa, and white and black are interchanged.
1.0Color Saturation
Represents a change to the color saturation, from 0.0 (grayscale)
to 1.0 (full color).
0.0Change brightness of red
Represents a change to the default brightness of the red component. Zero
indicates no change, values less than zero indicate a decrease, and
values greater than zero indicate an increase.
0.0Change brightness of green
Represents a change to the default brightness for the green component.
Zero indicates no change, values less than zero indicate a decrease, and
values greater than zero indicate an increase.
0.0Change brightness of blue
Represents a change to the default brightness for the blue component.
Zero indicates no change, values less than zero indicate a decrease, and
values greater than zero indicate an increase.
0.0Change contrast of red
Represents a change to the default contrast of the red component. Zero
indicates no change in contrast, values less than zero indicate a
decrease, and values greater than zero indicate an increase.
0.0Change contrast of green
Represents a change to the default contrast of the green component.
Zero indicates no change in contrast, values less than zero indicate a
decrease, and values greater than zero indicate an increase.
0.0Change contrast of blue
Represents a change to the default contrast of the blue component. Zero
indicates no change in contrast, values less than zero indicate a
decrease, and values greater than zero indicate an increase.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.a11y.keyboard.gschema.xml.in 0000664 0001750 0001750 00000013124 14167325242 026514 0 ustar fabio fabio
falseEnable accessibility keyboard shortcutsfalseBeep when a keyboard accessibility feature changesWhether to beep when a keyboard accessibility feature is enabled or disabled.falseDisable keyboard accessibility after a timeoutWhether to disable keyboard accessibility after a timeout, useful for shared machines.200Duration of the disabling timeoutDuration of the timeout before disabling the keyboard accessibility.falseEnable the bounce keysWhether the bounce keys keyboard accessibility feature is turned on.300Minimum interval in millisecondsIgnore multiple presses of the same key within this many milliseconds.falseBeep when a key is rejectedWhether to beep when a key is rejected.falseEnable mouse keysWhether the mouse keys accessibility feature is turned on.10Pixels per secondsHow many pixels per second to move at the maximum speed.300How long to accelerate in millisecondsHow many milliseconds it takes to go from 0 to maximum speed.300Initial delay in millisecondsHow many milliseconds to wait before mouse movement keys start to operate.falseEnable slow keysWhether the slow keys accessibility feature is turned on.300Minimum interval in millisecondsDo not accept a key as being pressed unless held for this many milliseconds.falseBeep when a key is first pressedWhether to beep when a key is first pressed.falseBeep when a key is acceptedWhether to beep when a key is accepted.falseBeep when a key is rejectedWhether to beep when a key is rejected.falseEnable sticky keysWhether the sticky keys accessibility feature is turned on.falseDisable when two keys are pressed at the same timeWhether to disable sticky keys if two keys are pressed at the same time.falseBeep when a modifier is pressed.Whether to beep when a modifier key is pressed.falseEnable toggle keys osd popups when num or capslock are changedWhether the toggle keys osd accessibility feature is turned on.falseEnable toggle keys sounds when num or capslock are changedWhether the toggle keys beep accessibility feature is turned on.falsedeprecateddeprecated'/usr/share/cinnamon/sounds/togglekeys-sound-on.ogg'Sound to use when turning caps/num lock on'/usr/share/cinnamon/sounds/togglekeys-sound-off.ogg'Sound to use when turning caps/num lock off
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.input-sources.gschema.xml.in 0000664 0001750 0001750 00000003430 14167325242 026761 0 ustar fabio fabio
0Current input source
The zero-based index into the input sources list specifying
the current one in effect. The value is automatically capped
to remain in the range [0, sources_length) as long as the
sources list isn't empty.
[]List of input sources
List of input source identifiers available. Each source is
specified as a tuple of 2 strings. The first string is the
type and can be one of 'xkb' or 'ibus'. For 'xkb' sources the
second string is 'xkb_layout+xkb_variant' or just 'xkb_layout'
if a XKB variant isn't needed. For 'ibus' sources the second
string is the IBus engine name. An empty list means that the X
server's current XKB layout and variant won't be touched and
IBus won't be used.
[]List of XKB options
List of XKB options. Each option is an XKB option string as
defined by xkeyboard-config's rules files.
falseShow all installed input sources
Makes all installed input sources available for choosing in
System Settings.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.keybindings.media-keys.gschema.xml.in 0000664 0001750 0001750 00000026441 14167325242 030505 0 ustar fabio fabio
['XF86Calculator']Launch calculatorBinding to launch the calculator.['XF86Mail']Launch email clientBinding to launch the email client.['XF86Eject']EjectBinding to eject an optical disc.['']Launch help browserBinding to launch the help browser.['<Super>e', 'XF86Explorer']Home folderBinding to open the Home folder.['XF86AudioMedia']Launch media playerBinding to launch the media player.['XF86AudioNext']Next trackBinding to skip to next track.['XF86AudioPause']Pause playbackBinding to pause playback.['XF86AudioPlay']Play (or play/pause)Binding to start playback (or toggle play/pause).['<Control><Alt>Delete']Log outBinding to log out.['<Control><Alt>End', 'XF86PowerOff']Shut down the computerBinding to shut down.['<Control><Alt>Escape']Restart CinnamonBinding to restart Cinnamon.['XF86AudioPrev']Previous trackBinding to skip to previous track.['<Control><Alt>l','XF86ScreenSaver']Lock screenBinding to lock the screen.['XF86Search']SearchBinding to launch the search tool.['XF86AudioStop']Stop playbackBinding to stop playback.['XF86AudioLowerVolume']Volume downBinding to lower the system volume.['XF86AudioMute']Volume muteBinding to mute the system volume.['XF86AudioRaiseVolume']Volume upBinding to raise the system volume.['XF86AudioMicMute']Mic muteBinding to mute the system microphone.['Print']Take a screenshotBinding to take a screenshot.['<Alt>Print']Take a screenshot of a windowBinding to take a screenshot of a window.['<Shift>Print']Take a screenshot of an areaBinding to take a screenshot of an area.['<Control>Print']Copy a screenshot to clipboardBinding to copy a screenshot to clipboard.['<Control><Alt>Print']Copy a screenshot of a window to clipboardBinding to copy a screenshot of a window to clipboard.['<Control><Shift>Print']Copy a screenshot of an area to clipboardBinding to copy a screenshot of an area to clipboard.['<Primary><Alt>t']Launch terminalBinding to launch the terminal.['XF86WWW']Launch web browserBinding to launch the web browser.['<Alt><Super>s']Toggle screen readerBinding to start the screen reader['']Toggle on-screen keyboardBinding to show the on-screen keyboard['']Increase text sizeBinding to increase the text size['']Decrease text sizeBinding to decrease the text size['']Toggle contrastBinding to toggle the interface contrast['XF86TouchpadToggle']Toggle the touchpad on and offToggle the touchpad on and off['XF86TouchpadOn']Turn the touchpad onTurn the touchpad on['XF86TouchpadOff']Turn the touchpad offTurn the touchpad off['XF86AudioMute']Mute the audio quietlyMute the audio quietly['<Alt>XF86AudioRaiseVolume']Turn the volume up quietlyTurn the volume up quietly['<Alt>XF86AudioLowerVolume']Turn the volume down quietlyTurn the volume down quietly['XF86AudioRewind']Rewind the currently playing streamRewind the currently playing stream['XF86AudioForward']Fast-forward the currently playing streamFast-forward the currently playing stream['XF86AudioRepeat']Toggle audio repeat modesToggle audio repeat modes['XF86AudioRandomPlay']Choose an audio track at randomChoose an audio track at random['<Super>p', 'XF86Display']Re-detect display devicesRe-detect display devices['XF86RotateWindows']Rotate displayRotate display['<Super>o']Orientation LockOrientation Lock['XF86Sleep']Suspend the systemSuspend the system['XF86Suspend', 'XF86Hibernate']Hibernate the systemHibernate the system['XF86MonBrightnessUp']Increase display brightnessIncrease display brightness['XF86MonBrightnessDown']Decrease display brightnessDecrease display brightness['XF86KbdBrightnessUp']Increase keyboard backlight brightnessIncrease keyboard backlight brightness['XF86KbdBrightnessDown']Decrease keyboard backlight brightnessDecrease keyboard backlight brightness['XF86KbdLightOnOff']Toggle keyboard backlightToggle keyboard backlight['XF86Battery']Display battery statusDisplay battery status
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.a11y.applications.gschema.xml.in 0000664 0001750 0001750 00000001450 14167325242 027401 0 ustar fabio fabio
falseOn-screen keyboardWhether the on-screen keyboard is turned on.falseScreen magnifierWhether the screen magnifier is turned on.falseScreen readerWhether the screen reader is turned on.
cinnamon-desktop-5.2.1/schemas/org.cinnamon.desktop.keybindings.gschema.xml.in 0000664 0001750 0001750 00000003553 14167325242 026455 0 ustar fabio fabio
[]List of gsettings custom keybinding paths to look in['<Super>l']Keybinding for toggling the looking glass
Stores the keybinding for toggling the looking glass window
['<Super>s']Show deskletsRaises desklets above windows['<Alt><Super>equal']Magnifier zoom inBinding for the magnifier to zoom in['<Alt><Super>minus']Magnifier zoom outBinding for the magnifier to zoom out''NameName of the custom binding[]BindingBinding for the custom binding''CommandCommand to run when the binding is invoked
cinnamon-desktop-5.2.1/debian/ 0000775 0001750 0001750 00000000000 14167325242 015144 5 ustar fabio fabio cinnamon-desktop-5.2.1/meson.build 0000664 0001750 0001750 00000011032 14167325242 016061 0 ustar fabio fabio # Meson build file
# https://github.com/linuxmint/cinnamon-desktop
project('cinnamon-desktop', 'c', version: '5.2.1',
meson_version: '>=0.41.0'
)
# Before making a release, the LT_VERSION string should be modified.
# The string is of the form C.R.A.
# - If interfaces have been changed or added, but binary compatibility has
# been preserved, change to C+1.0.A+1
# - If binary compatibility has been broken (eg removed or changed interfaces)
# change to C+1.0.0
# - If the interface is the same as the previous version, change to C.R+1.A
LT_VERSION='4.0.0'
################################################################################
conf = configuration_data()
pkgconfig = import('pkgconfig')
i18n = import('i18n')
gnome = import('gnome')
cc = meson.get_compiler('c')
if not get_option('deprecation_warnings')
add_global_arguments('-Wno-deprecated-declarations', language: 'c')
endif
################################################################################
math = cc.find_library('m')
gdk_pixb= dependency('gdk-pixbuf-2.0', version: '>=2.22.0')
gio = dependency('gio-2.0', version: '>=2.37.3')
glib = dependency('glib-2.0', version: '>=2.37.3')
gtk = dependency('gtk+-3.0', version: '>=3.3.16')
x11 = dependency('x11')
xext = dependency('xext', version: '>=1.1')
xkbconf = dependency('xkeyboard-config')
xkbfile = dependency('xkbfile')
xrandr = dependency('xrandr', version: '>=1.3')
cinnamon_deps = [
gdk_pixb,
gio,
glib,
gtk,
math,
x11,
xext,
xkbconf,
xkbfile,
xrandr,
]
# CVC dependencies
gobject = dependency('gobject-2.0')
pulse = dependency('libpulse')
pulsegl = dependency('libpulse-mainloop-glib')
cvc_deps = cinnamon_deps + [
pulse,
pulsegl,
gobject
]
use_alsa = get_option('alsa')
if use_alsa
cvc_deps += dependency('alsa')
endif
xkb_base = xkbconf.get_pkgconfig_variable('xkb_base')
# Path to the pnp.ids file -- to know if we use one shipped with another
# package, or an internal file
pnp_ids_path = get_option('pnp_ids')
pnp_ids_install_internal = (pnp_ids_path == '')
if pnp_ids_install_internal
# Default value
pnp_ids_path = join_paths(get_option('datadir'), 'libcinnamon-desktop')
pnp_ids_abspath = join_paths(get_option('prefix'), pnp_ids_path)
else
pnp_ids_abspath = pnp_ids_path
endif
################################################################################
# Config
timerfd_check = cc.compiles('''
#include
#include
int main () {
timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC);
return 0;
}
''')
gettext_package = meson.project_name()
conf.set_quoted('GETTEXT_PACKAGE', gettext_package)
conf.set_quoted('GNOMELOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
conf.set_quoted('PACKAGE_VERSION', meson.project_version())
conf.set('HAVE_BIND_TEXTDOMAIN_CODESET', cc.has_function('bind_textdomain_codeset'))
conf.set('datadir', get_option('datadir'))
conf.set('ENABLE_NLS', cc.has_header('libintl.h'))
conf.set('HAVE_ALSA', use_alsa)
conf.set('HAVE_GETTEXT', true)
conf.set('HAVE_INTROSPECTION', true)
conf.set('HAVE_TIMERFD', timerfd_check)
################################################################################
rootInclude = include_directories('.')
configure_file(
output: 'config.h',
configuration: conf
)
subdir('install-scripts')
subdir('po')
subdir('libcinnamon-desktop')
subdir('libcvc')
subdir('schemas')
pnp_message = '@0@: @1@'.format(
''+(pnp_ids_install_internal ? 'internal' : 'system'),
pnp_ids_abspath
)
message('\n'.join([
'',
' prefix: ' + get_option('prefix'),
' exec_prefix: ' + get_option('prefix'),
' libdir: ' + get_option('libdir'),
' bindir: ' + get_option('bindir'),
' sbindir: ' + get_option('sbindir'),
' sysconfdir: ' + get_option('sysconfdir'),
' localstatedir: ' + get_option('localstatedir'),
' datadir: ' + get_option('datadir'),
' source code location: ' + meson.source_root(),
' compiler: ' + cc.get_id(),
' debugging support: ' + get_option('buildtype'),
' Use *_DISABLE_DEPRECATED: @0@'.format(get_option('deprecation_warnings')),
' Use PNP files: ' + pnp_message,
' Use ALSA: ' + '@0@'.format(use_alsa),
'',
]))
cinnamon-desktop-5.2.1/libcinnamon-desktop/ 0000775 0001750 0001750 00000000000 14167325242 017662 5 ustar fabio fabio cinnamon-desktop-5.2.1/libcinnamon-desktop/cinnamon-rr-debug.c 0000664 0001750 0001750 00000006477 14167325242 023353 0 ustar fabio fabio /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2012 Richard Hughes
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include
#include
#include
#include
#include
#include
/**
* get_property:
**/
static guint8 *
get_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 = NULL;
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;
}
XFree (prop);
return result;
}
/**
* main:
**/
int
main (int argc, char *argv[])
{
Atom edid_atom;
Display *display;
GError *error = NULL;
GnomeRROutput **outputs;
GnomeRRScreen *screen;
gsize len = 0;
guint8 *result = NULL;
guint i;
gtk_init (&argc, &argv);
screen = gnome_rr_screen_new (gdk_screen_get_default (), &error);
if (screen == NULL) {
g_warning ("failed to get screen: %s", error->message);
g_error_free (error);
goto out;
}
display = GDK_SCREEN_XDISPLAY (gdk_screen_get_default ());
outputs = gnome_rr_screen_list_outputs (screen);
for (i = 0; outputs[i] != NULL; i++) {
g_print ("[%s]\n", gnome_rr_output_get_name (outputs[i]));
g_print ("\tconnected: %i\n", gnome_rr_output_is_connected (outputs[i]));
g_print ("\tlaptop: %i\n", gnome_rr_output_is_laptop (outputs[i]));
g_print ("\tprimary: %i\n", gnome_rr_output_get_is_primary (outputs[i]));
g_print ("\tid: %i\n", gnome_rr_output_get_id (outputs[i]));
/* get EDID (first try) */
edid_atom = XInternAtom (display, "EDID", FALSE);
result = get_property (display,
gnome_rr_output_get_id (outputs[i]),
edid_atom,
&len);
if (result != NULL) {
g_print ("\tedid: %" G_GSIZE_FORMAT " bytes [%i:%i:%i:%i]\n",
len, result[0], result[1],
result[2], result[3]);
g_free (result);
}
/* get EDID (second try) */
edid_atom = XInternAtom (display, "EDID_DATA", FALSE);
result = get_property (display,
gnome_rr_output_get_id (outputs[i]),
edid_atom,
&len);
if (result != NULL) {
g_print ("\tedid2: %" G_GSIZE_FORMAT " bytes [%i:%i:%i:%i]\n",
len, result[0], result[1],
result[2], result[3]);
g_free (result);
}
}
out:
g_object_unref (screen);
return 0;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-datetime-source.h 0000664 0001750 0001750 00000002435 14167325242 024234 0 ustar fabio fabio /* gnome-rr.h
*
* Copyright 2011, 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: Colin Walters
*/
#ifndef GNOME_DATETIME_SOURCE_H
#define GNOME_DATETIME_SOURCE_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error This is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API
#endif
#include
GSource *_gnome_datetime_source_new (GDateTime *now,
GDateTime *expiry,
gboolean cancel_on_set);
#endif /* GNOME_DATETIME_SOURCE_H */
cinnamon-desktop-5.2.1/libcinnamon-desktop/edid-parse.c 0000664 0001750 0001750 00000031407 14167325242 022050 0 ustar fabio fabio /*
* 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 */
#include "edid.h"
#include
#include
#include
#include
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;
}
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/meson.build 0000664 0001750 0001750 00000006232 14167325242 022027 0 ustar fabio fabio libcinnamon_desktop_gir_sources = [
'display-name.c',
'edid-parse.c',
'gnome-bg-crossfade.c',
'gnome-bg.c',
'gnome-desktop-thumbnail.c',
'gnome-desktop-utils.c',
'gnome-installer.c',
'gnome-pnp-ids.c',
'gnome-rr-config.c',
'gnome-rr-labeler.c',
'gnome-rr-output-info.c',
'gnome-rr.c',
'gnome-thumbnail-pixbuf-utils.c',
'gnome-wall-clock.c',
'gnome-xkb-info.c',
]
libcinnamon_desktop_misc_headers = [
'gnome-datetime-source.h',
'gnome-rr-private.h',
'edid.h',
'private.h'
]
libcinnamon_desktop_sources = [
libcinnamon_desktop_gir_sources,
libcinnamon_desktop_misc_headers,
'gnome-datetime-source.c',
]
cdesktop_headers = [
'cdesktop-enums.h',
]
libcinnamon_desktop_headers = [
'gnome-bg-crossfade.h',
'gnome-bg.h',
'gnome-desktop-thumbnail.h',
'gnome-desktop-utils.h',
'gnome-installer.h',
'gnome-pnp-ids.h',
'gnome-rr-config.h',
'gnome-rr-labeler.h',
'gnome-rr.h',
'gnome-wall-clock.h',
'gnome-xkb-info.h',
]
libcinnamon_desktop = shared_library('cinnamon-desktop',
libcinnamon_desktop_sources,
include_directories: [ rootInclude ],
c_args: [
'-DG_LOG_DOMAIN="CinnamonDesktop"',
'-DPNP_IDS="@0@"'.format(pnp_ids_path),
'-DXKB_BASE="@0@"'.format(xkb_base),
],
dependencies: cinnamon_deps,
install: true,
version: LT_VERSION,
)
install_headers(
libcinnamon_desktop_headers + cdesktop_headers,
subdir: join_paths('cinnamon-desktop', 'libcinnamon-desktop')
)
pkgconfig.generate(
name: 'cinnamon-desktop',
description: 'Utility library for loading .desktop files',
version: meson.project_version(),
requires: [ 'gtk+-3.0', ],
requires_private: [ 'xkbfile', ],
libraries: libcinnamon_desktop,
subdirs: join_paths('cinnamon-desktop'),
variables: [ 'exec_prefix=${prefix}'],
)
if pnp_ids_install_internal
install_data('pnp.ids',
install_dir: pnp_ids_path,
)
endif
cdesktop_gir = gnome.generate_gir(libcinnamon_desktop,
sources: 'cdesktop-enums.h',
namespace: 'CDesktopEnums',
nsversion: '3.0',
identifier_prefix: 'CDesktop',
symbol_prefix: 'c_desktop',
extra_args: [
'-DGNOME_DESKTOP_USE_UNSTABLE_API',
],
install: true,
)
gnome.generate_gir(libcinnamon_desktop,
sources: libcinnamon_desktop_gir_sources + libcinnamon_desktop_headers,
namespace: 'CinnamonDesktop',
nsversion: '3.0',
export_packages: 'cinnamon-desktop',
identifier_prefix: 'Gnome',
symbol_prefix: 'gnome_',
includes: ['GObject-2.0', 'Gtk-3.0', cdesktop_gir[0], ],
extra_args: [
'-DGNOME_DESKTOP_USE_UNSTABLE_API',
],
install: true,
)
# FIXME
# https://github.com/mesonbuild/meson/issues/1687
custom_target('gsettings-enums',
input : libcinnamon_desktop_headers + libcinnamon_desktop_misc_headers + cdesktop_headers,
output: 'org.cinnamon.desktop.enums.xml',
capture: true,
command: ['glib-mkenums',
'--comments', '',
'--fhead', '',
'--vhead', ' <@type@ id=\'org.cinnamon.desktop.@EnumName@\'>',
'--vprod', ' ',
'--vtail', ' @type@>',
'--ftail', '',
'@INPUT@'
],
install: true,
install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas'),
)
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-desktop-thumbnail.c 0000664 0001750 0001750 00000145116 14167325242 024573 0 ustar fabio fabio /*
* gnome-thumbnail.c: Utilities for handling thumbnails
*
* Copyright (C) 2002 Red Hat, Inc.
* Copyright (C) 2010 Carlos Garcia Campos
*
* 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: Alexander Larsson
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GDK_PIXBUF_ENABLE_BACKEND
#include
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-desktop-thumbnail.h"
#include "gnome-desktop-utils.h"
#include
#define SECONDS_BETWEEN_STATS 10
struct _GnomeDesktopThumbnailFactoryPrivate {
GnomeDesktopThumbnailSize size;
GMutex lock;
GList *thumbnailers;
GHashTable *mime_types_map;
GList *monitors;
GSettings *settings;
gboolean loaded : 1;
gboolean disabled : 1;
gchar **disabled_types;
gboolean permissions_problem;
gboolean needs_chown;
uid_t real_uid;
gid_t real_gid;
};
static const char *appname = "gnome-thumbnail-factory";
static void gnome_desktop_thumbnail_factory_init (GnomeDesktopThumbnailFactory *factory);
static void gnome_desktop_thumbnail_factory_class_init (GnomeDesktopThumbnailFactoryClass *class);
G_DEFINE_TYPE (GnomeDesktopThumbnailFactory,
gnome_desktop_thumbnail_factory,
G_TYPE_OBJECT)
#define parent_class gnome_desktop_thumbnail_factory_parent_class
#define GNOME_DESKTOP_THUMBNAIL_FACTORY_GET_PRIVATE(object) \
(G_TYPE_INSTANCE_GET_PRIVATE ((object), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactoryPrivate))
typedef struct {
gint width;
gint height;
gint input_width;
gint input_height;
gboolean preserve_aspect_ratio;
} SizePrepareContext;
#define LOAD_BUFFER_SIZE 4096
#define THUMBNAILER_ENTRY_GROUP "Thumbnailer Entry"
#define THUMBNAILER_EXTENSION ".thumbnailer"
typedef struct {
volatile gint ref_count;
gchar *path;
gchar *try_exec;
gchar *command;
gchar **mime_types;
} Thumbnailer;
static Thumbnailer *
thumbnailer_ref (Thumbnailer *thumb)
{
g_return_val_if_fail (thumb != NULL, NULL);
g_return_val_if_fail (thumb->ref_count > 0, NULL);
g_atomic_int_inc (&thumb->ref_count);
return thumb;
}
static void
thumbnailer_unref (Thumbnailer *thumb)
{
g_return_if_fail (thumb != NULL);
g_return_if_fail (thumb->ref_count > 0);
if (g_atomic_int_dec_and_test (&thumb->ref_count))
{
g_free (thumb->path);
g_free (thumb->try_exec);
g_free (thumb->command);
g_strfreev (thumb->mime_types);
g_slice_free (Thumbnailer, thumb);
}
}
static Thumbnailer *
thumbnailer_load (Thumbnailer *thumb)
{
GKeyFile *key_file;
GError *error = NULL;
key_file = g_key_file_new ();
if (!g_key_file_load_from_file (key_file, thumb->path, 0, &error))
{
g_warning ("Failed to load thumbnailer from \"%s\": %s\n", thumb->path, error->message);
g_error_free (error);
thumbnailer_unref (thumb);
g_key_file_free (key_file);
return NULL;
}
if (!g_key_file_has_group (key_file, THUMBNAILER_ENTRY_GROUP))
{
g_warning ("Invalid thumbnailer: missing group \"%s\"\n", THUMBNAILER_ENTRY_GROUP);
thumbnailer_unref (thumb);
g_key_file_free (key_file);
return NULL;
}
thumb->command = g_key_file_get_string (key_file, THUMBNAILER_ENTRY_GROUP, "Exec", NULL);
if (!thumb->command)
{
g_warning ("Invalid thumbnailer: missing Exec key\n");
thumbnailer_unref (thumb);
g_key_file_free (key_file);
return NULL;
}
thumb->mime_types = g_key_file_get_string_list (key_file, THUMBNAILER_ENTRY_GROUP, "MimeType", NULL, NULL);
if (!thumb->mime_types)
{
g_warning ("Invalid thumbnailer: missing MimeType key\n");
thumbnailer_unref (thumb);
g_key_file_free (key_file);
return NULL;
}
thumb->try_exec = g_key_file_get_string (key_file, THUMBNAILER_ENTRY_GROUP, "TryExec", NULL);
if (thumb->try_exec != NULL)
{
gchar *path_to_exec = g_find_program_in_path (thumb->try_exec);
if (path_to_exec == NULL)
{
g_message ("Ignoring thumbnailer with missing binary: '%s'", thumb->try_exec);
thumbnailer_unref (thumb);
g_key_file_free (key_file);
return NULL;
}
g_free (path_to_exec);
}
g_key_file_free (key_file);
return thumb;
}
static Thumbnailer *
thumbnailer_reload (Thumbnailer *thumb)
{
g_return_val_if_fail (thumb != NULL, NULL);
g_free (thumb->command);
thumb->command = NULL;
g_strfreev (thumb->mime_types);
thumb->mime_types = NULL;
g_free (thumb->try_exec);
thumb->try_exec = NULL;
return thumbnailer_load (thumb);
}
static Thumbnailer *
thumbnailer_new (const gchar *path)
{
Thumbnailer *thumb;
thumb = g_slice_new0 (Thumbnailer);
thumb->ref_count = 1;
thumb->path = g_strdup (path);
return thumbnailer_load (thumb);
}
static gpointer
init_thumbnailers_dirs (gpointer data)
{
const gchar * const *data_dirs;
gchar **thumbs_dirs;
guint i, length;
data_dirs = g_get_system_data_dirs ();
length = g_strv_length ((char **) data_dirs);
thumbs_dirs = g_new (gchar *, length + 2);
thumbs_dirs[0] = g_build_filename (g_get_user_data_dir (), "thumbnailers", NULL);
for (i = 0; i < length; i++)
thumbs_dirs[i + 1] = g_build_filename (data_dirs[i], "thumbnailers", NULL);
thumbs_dirs[length + 1] = NULL;
return thumbs_dirs;
}
static const gchar * const *
get_thumbnailers_dirs (void)
{
static GOnce once_init = G_ONCE_INIT;
return g_once (&once_init, init_thumbnailers_dirs, NULL);
}
static void
size_prepared_cb (GdkPixbufLoader *loader,
int width,
int height,
gpointer data)
{
SizePrepareContext *info = data;
g_return_if_fail (width > 0 && height > 0);
info->input_width = width;
info->input_height = height;
if (width < info->width && height < info->height) return;
if (info->preserve_aspect_ratio &&
(info->width > 0 || info->height > 0)) {
if (info->width < 0)
{
width = width * (double)info->height/(double)height;
height = info->height;
}
else if (info->height < 0)
{
height = height * (double)info->width/(double)width;
width = info->width;
}
else if ((double)height * (double)info->width >
(double)width * (double)info->height) {
width = 0.5 + (double)width * (double)info->height / (double)height;
height = info->height;
} else {
height = 0.5 + (double)height * (double)info->width / (double)width;
width = info->width;
}
} else {
if (info->width > 0)
width = info->width;
if (info->height > 0)
height = info->height;
}
gdk_pixbuf_loader_set_size (loader, width, height);
}
static GdkPixbufLoader *
create_loader (GFile *file,
const guchar *data,
gsize size)
{
GdkPixbufLoader *loader;
GError *error = NULL;
char *mime_type;
char *filename;
loader = NULL;
/* need to specify the type here because the gdk_pixbuf_loader_write
doesn't have access to the filename in order to correct detect
the image type. */
filename = g_file_get_basename (file);
mime_type = g_content_type_guess (filename, data, size, NULL);
g_free (filename);
if (mime_type != NULL) {
loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error);
}
if (loader == NULL) {
g_warning ("Unable to create loader for mime type %s: %s", mime_type, error->message);
g_clear_error (&error);
loader = gdk_pixbuf_loader_new ();
}
g_free (mime_type);
return loader;
}
static GdkPixbuf *
_gdk_pixbuf_new_from_uri_at_scale (const char *uri,
gint width,
gint height,
gboolean preserve_aspect_ratio)
{
gboolean result;
guchar buffer[LOAD_BUFFER_SIZE];
gsize bytes_read;
GdkPixbufLoader *loader = NULL;
GdkPixbuf *pixbuf;
GdkPixbufAnimation *animation;
GdkPixbufAnimationIter *iter;
gboolean has_frame;
SizePrepareContext info;
GFile *file;
GFileInfo *file_info;
GInputStream *input_stream;
GError *error = NULL;
g_return_val_if_fail (uri != NULL, NULL);
input_stream = NULL;
file = g_file_new_for_uri (uri);
/* First see if we can get an input stream via preview::icon */
file_info = g_file_query_info (file,
G_FILE_ATTRIBUTE_PREVIEW_ICON,
G_FILE_QUERY_INFO_NONE,
NULL, /* GCancellable */
NULL); /* return location for GError */
if (file_info != NULL) {
GObject *object;
object = g_file_info_get_attribute_object (file_info,
G_FILE_ATTRIBUTE_PREVIEW_ICON);
if (object != NULL && G_IS_LOADABLE_ICON (object)) {
input_stream = g_loadable_icon_load (G_LOADABLE_ICON (object),
0, /* size */
NULL, /* return location for type */
NULL, /* GCancellable */
NULL); /* return location for GError */
}
g_object_unref (file_info);
}
if (input_stream == NULL) {
input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
if (input_stream == NULL) {
if (error != NULL) {
g_warning ("Unable to create an input stream for %s: %s", uri, error->message);
g_clear_error (&error);
}
g_object_unref (file);
return NULL;
}
}
has_frame = FALSE;
result = FALSE;
while (!has_frame) {
bytes_read = g_input_stream_read (input_stream,
buffer,
sizeof (buffer),
NULL,
&error);
if (error != NULL) {
g_warning ("Error reading from %s: %s", uri, error->message);
g_clear_error (&error);
}
if (bytes_read == -1) {
break;
}
result = TRUE;
if (bytes_read == 0) {
break;
}
if (loader == NULL) {
loader = create_loader (file, buffer, bytes_read);
if (1 <= width || 1 <= height) {
info.width = width;
info.height = height;
info.input_width = info.input_height = 0;
info.preserve_aspect_ratio = preserve_aspect_ratio;
g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
}
g_assert (loader != NULL);
}
if (!gdk_pixbuf_loader_write (loader,
(unsigned char *)buffer,
bytes_read,
&error)) {
g_warning ("Error creating thumbnail for %s: %s", uri, error->message);
g_clear_error (&error);
result = FALSE;
break;
}
animation = gdk_pixbuf_loader_get_animation (loader);
if (animation) {
iter = gdk_pixbuf_animation_get_iter (animation, NULL);
if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
has_frame = TRUE;
}
g_object_unref (iter);
}
}
if (!GDK_IS_PIXBUF_LOADER (loader)) {
g_input_stream_close (input_stream, NULL, NULL);
g_object_unref (input_stream);
g_object_unref (file);
return NULL;
}
gdk_pixbuf_loader_close (loader, NULL);
if (!result) {
g_object_unref (G_OBJECT (loader));
g_input_stream_close (input_stream, NULL, NULL);
g_object_unref (input_stream);
g_object_unref (file);
return NULL;
}
g_input_stream_close (input_stream, NULL, NULL);
g_object_unref (input_stream);
g_object_unref (file);
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
if (pixbuf != NULL) {
g_object_ref (G_OBJECT (pixbuf));
g_object_set_data (G_OBJECT (pixbuf), "gnome-original-width",
GINT_TO_POINTER (info.input_width));
g_object_set_data (G_OBJECT (pixbuf), "gnome-original-height",
GINT_TO_POINTER (info.input_height));
}
g_object_unref (G_OBJECT (loader));
return pixbuf;
}
static void
gnome_desktop_thumbnail_factory_finalize (GObject *object)
{
GnomeDesktopThumbnailFactory *factory;
GnomeDesktopThumbnailFactoryPrivate *priv;
factory = GNOME_DESKTOP_THUMBNAIL_FACTORY (object);
priv = factory->priv;
if (priv->thumbnailers)
{
g_list_free_full (priv->thumbnailers, (GDestroyNotify)thumbnailer_unref);
priv->thumbnailers = NULL;
}
g_clear_pointer (&priv->mime_types_map, g_hash_table_destroy);
if (priv->monitors)
{
g_list_free_full (priv->monitors, (GDestroyNotify)g_object_unref);
priv->monitors = NULL;
}
g_mutex_clear (&priv->lock);
g_clear_pointer (&priv->disabled_types, g_strfreev);
g_clear_object (&priv->settings);
if (G_OBJECT_CLASS (parent_class)->finalize)
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
/* These should be called with the lock held */
static void
gnome_desktop_thumbnail_factory_register_mime_types (GnomeDesktopThumbnailFactory *factory,
Thumbnailer *thumb)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
gint i;
for (i = 0; thumb->mime_types[i]; i++)
{
if (!g_hash_table_lookup (priv->mime_types_map, thumb->mime_types[i]))
g_hash_table_insert (priv->mime_types_map,
g_strdup (thumb->mime_types[i]),
thumbnailer_ref (thumb));
}
}
static void
gnome_desktop_thumbnail_factory_add_thumbnailer (GnomeDesktopThumbnailFactory *factory,
Thumbnailer *thumb)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
gnome_desktop_thumbnail_factory_register_mime_types (factory, thumb);
priv->thumbnailers = g_list_prepend (priv->thumbnailers, thumb);
}
static gboolean
gnome_desktop_thumbnail_factory_is_disabled (GnomeDesktopThumbnailFactory *factory,
const gchar *mime_type)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
guint i;
if (priv->disabled)
return TRUE;
if (!priv->disabled_types)
return FALSE;
for (i = 0; priv->disabled_types[i]; i++)
{
if (g_strcmp0 (priv->disabled_types[i], mime_type) == 0)
return TRUE;
}
return FALSE;
}
static gboolean
remove_thumbnailer_from_mime_type_map (gchar *key,
Thumbnailer *value,
gchar *path)
{
return (strcmp (value->path, path) == 0);
}
static void
update_or_create_thumbnailer (GnomeDesktopThumbnailFactory *factory,
const gchar *path)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
GList *l;
Thumbnailer *thumb;
gboolean found = FALSE;
g_mutex_lock (&priv->lock);
for (l = priv->thumbnailers; l && !found; l = g_list_next (l))
{
thumb = (Thumbnailer *)l->data;
if (strcmp (thumb->path, path) == 0)
{
found = TRUE;
/* First remove the mime_types associated to this thumbnailer */
g_hash_table_foreach_remove (priv->mime_types_map,
(GHRFunc)remove_thumbnailer_from_mime_type_map,
(gpointer)path);
if (!thumbnailer_reload (thumb))
priv->thumbnailers = g_list_delete_link (priv->thumbnailers, l);
else
gnome_desktop_thumbnail_factory_register_mime_types (factory, thumb);
}
}
if (!found)
{
thumb = thumbnailer_new (path);
if (thumb)
gnome_desktop_thumbnail_factory_add_thumbnailer (factory, thumb);
}
g_mutex_unlock (&priv->lock);
}
static void
remove_thumbnailer (GnomeDesktopThumbnailFactory *factory,
const gchar *path)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
GList *l;
Thumbnailer *thumb;
g_mutex_lock (&priv->lock);
for (l = priv->thumbnailers; l; l = g_list_next (l))
{
thumb = (Thumbnailer *)l->data;
if (strcmp (thumb->path, path) == 0)
{
priv->thumbnailers = g_list_delete_link (priv->thumbnailers, l);
g_hash_table_foreach_remove (priv->mime_types_map,
(GHRFunc)remove_thumbnailer_from_mime_type_map,
(gpointer)path);
thumbnailer_unref (thumb);
break;
}
}
g_mutex_unlock (&priv->lock);
}
static void
thumbnailers_directory_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
GnomeDesktopThumbnailFactory *factory)
{
gchar *path;
switch (event_type)
{
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGED:
case G_FILE_MONITOR_EVENT_DELETED:
path = g_file_get_path (file);
if (!g_str_has_suffix (path, THUMBNAILER_EXTENSION))
{
g_free (path);
return;
}
if (event_type == G_FILE_MONITOR_EVENT_DELETED)
remove_thumbnailer (factory, path);
else
update_or_create_thumbnailer (factory, path);
g_free (path);
break;
default:
break;
}
}
static void
gnome_desktop_thumbnail_factory_load_thumbnailers (GnomeDesktopThumbnailFactory *factory)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
const gchar * const *dirs;
guint i;
if (priv->loaded)
return;
dirs = get_thumbnailers_dirs ();
for (i = 0; dirs[i]; i++)
{
const gchar *path = dirs[i];
GDir *dir;
GFile *dir_file;
GFileMonitor *monitor;
const gchar *dirent;
dir = g_dir_open (path, 0, NULL);
if (!dir)
continue;
/* Monitor dir */
dir_file = g_file_new_for_path (path);
monitor = g_file_monitor_directory (dir_file,
G_FILE_MONITOR_NONE,
NULL, NULL);
if (monitor)
{
g_signal_connect (monitor, "changed",
G_CALLBACK (thumbnailers_directory_changed),
factory);
priv->monitors = g_list_prepend (priv->monitors, monitor);
}
g_object_unref (dir_file);
while ((dirent = g_dir_read_name (dir)))
{
Thumbnailer *thumb;
gchar *filename;
if (!g_str_has_suffix (dirent, THUMBNAILER_EXTENSION))
continue;
filename = g_build_filename (path, dirent, NULL);
thumb = thumbnailer_new (filename);
g_free (filename);
if (thumb)
gnome_desktop_thumbnail_factory_add_thumbnailer (factory, thumb);
}
g_dir_close (dir);
}
priv->loaded = TRUE;
}
static void
external_thumbnailers_disabled_all_changed_cb (GSettings *settings,
const gchar *key,
GnomeDesktopThumbnailFactory *factory)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
g_mutex_lock (&priv->lock);
priv->disabled = g_settings_get_boolean (priv->settings, "disable-all");
if (priv->disabled)
{
g_strfreev (priv->disabled_types);
priv->disabled_types = NULL;
}
else
{
priv->disabled_types = g_settings_get_strv (priv->settings, "disable");
gnome_desktop_thumbnail_factory_load_thumbnailers (factory);
}
g_mutex_unlock (&priv->lock);
}
static void
external_thumbnailers_disabled_changed_cb (GSettings *settings,
const gchar *key,
GnomeDesktopThumbnailFactory *factory)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
g_mutex_lock (&priv->lock);
if (!priv->disabled)
{
g_strfreev (priv->disabled_types);
priv->disabled_types = g_settings_get_strv (priv->settings, "disable");
}
g_mutex_unlock (&priv->lock);
}
/* There are various different behavior depending on whether the application
ran with sudo, pkexec, under the root user, and 'sudo su'...
- sudo (program) keeps the user's home folder (and their .cache folder)
- pkexec (program) uses root's .cache folder
- root terminal, running (program) uses root's .cache folder
- sudo su, then running (program), uses root's .cache folder
Using sudo, or sudo su, SUDO_UID and friends are set in the environment
Using pkexec, PKEXEC_UID is set
root terminal and pkexec cases don't need any extra work - they're thumbnailing
with the correct permissions (root-owned in root's .cache folder)
sudo and sudo su need help, and each in a different way:
- sudo su gives a false positive, since SUDO_UID is set, *but* the program
is using root's .cache folder, so we really don't want to fix these
- sudo (program) wants to use the user's cache folder, but will end up writing
them as root:root files, instead of user:user. So, in this case, we make sure
to chmod those files to be owned by the original user, and not root.
*/
static void
get_user_info (GnomeDesktopThumbnailFactory *factory,
gboolean *adjust,
uid_t *uid,
gid_t *gid)
{
struct passwd *pwent;
pwent = gnome_desktop_get_session_user_pwent ();
*uid = pwent->pw_uid;
*gid = pwent->pw_gid;
/* Only can (and need to) adjust if we're root, but
this process will be writing to the session user's
home folder */
*adjust = geteuid () == 0 &&
g_strcmp0 (pwent->pw_dir, g_get_home_dir ()) == 0;
}
static void
gnome_desktop_thumbnail_factory_init (GnomeDesktopThumbnailFactory *factory)
{
GnomeDesktopThumbnailFactoryPrivate *priv;
factory->priv = GNOME_DESKTOP_THUMBNAIL_FACTORY_GET_PRIVATE (factory);
priv = factory->priv;
priv->size = GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL;
priv->mime_types_map = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)thumbnailer_unref);
get_user_info (factory, &priv->needs_chown, &priv->real_uid, &priv->real_gid);
priv->permissions_problem = !gnome_desktop_thumbnail_cache_check_permissions (NULL, TRUE);
g_mutex_init (&priv->lock);
priv->settings = g_settings_new ("org.cinnamon.desktop.thumbnailers");
priv->disabled = g_settings_get_boolean (priv->settings, "disable-all");
if (!priv->disabled)
priv->disabled_types = g_settings_get_strv (priv->settings, "disable");
g_signal_connect (priv->settings, "changed::disable-all",
G_CALLBACK (external_thumbnailers_disabled_all_changed_cb),
factory);
g_signal_connect (priv->settings, "changed::disable",
G_CALLBACK (external_thumbnailers_disabled_changed_cb),
factory);
if (!priv->disabled)
gnome_desktop_thumbnail_factory_load_thumbnailers (factory);
}
static void
gnome_desktop_thumbnail_factory_class_init (GnomeDesktopThumbnailFactoryClass *class)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = gnome_desktop_thumbnail_factory_finalize;
g_type_class_add_private (class, sizeof (GnomeDesktopThumbnailFactoryPrivate));
}
/**
* gnome_desktop_thumbnail_factory_new:
* @size: The thumbnail size to use
*
* Creates a new #GnomeDesktopThumbnailFactory.
*
* This function must be called on the main thread.
*
* Return value: a new #GnomeDesktopThumbnailFactory
*
* Since: 2.2
**/
GnomeDesktopThumbnailFactory *
gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size)
{
GnomeDesktopThumbnailFactory *factory;
factory = g_object_new (GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, NULL);
factory->priv->size = size;
return factory;
}
/**
* gnome_desktop_thumbnail_factory_lookup:
* @factory: a #GnomeDesktopThumbnailFactory
* @uri: the uri of a file
* @mtime: the mtime of the file
*
* Tries to locate an existing thumbnail for the file specified.
*
* Usage of this function is threadsafe.
*
* Return value: The absolute path of the thumbnail, or %NULL if none exist.
*
* Since: 2.2
**/
char *
gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory,
const char *uri,
time_t mtime)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
char *path, *file;
GChecksum *checksum;
guint8 digest[16];
gsize digest_len = sizeof (digest);
GdkPixbuf *pixbuf;
gboolean res;
g_return_val_if_fail (uri != NULL, NULL);
res = FALSE;
checksum = g_checksum_new (G_CHECKSUM_MD5);
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
g_checksum_get_digest (checksum, digest, &digest_len);
g_assert (digest_len == 16);
file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
path = g_build_filename (g_get_user_cache_dir (),
"thumbnails",
(priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
file,
NULL);
g_free (file);
pixbuf = gdk_pixbuf_new_from_file (path, NULL);
if (pixbuf != NULL)
{
res = gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime);
g_object_unref (pixbuf);
}
g_checksum_free (checksum);
if (res)
return path;
g_free (path);
return FALSE;
}
/**
* gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail:
* @factory: a #GnomeDesktopThumbnailFactory
* @uri: the uri of a file
* @mtime: the mtime of the file
*
* Tries to locate an failed thumbnail for the file specified. Writing
* and looking for failed thumbnails is important to avoid to try to
* thumbnail e.g. broken images several times.
*
* Usage of this function is threadsafe.
*
* Return value: TRUE if there is a failed thumbnail for the file.
*
* Since: 2.2
**/
gboolean
gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
time_t mtime)
{
char *path, *file;
GdkPixbuf *pixbuf;
gboolean res;
GChecksum *checksum;
guint8 digest[16];
gsize digest_len = sizeof (digest);
checksum = g_checksum_new (G_CHECKSUM_MD5);
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
g_checksum_get_digest (checksum, digest, &digest_len);
g_assert (digest_len == 16);
res = FALSE;
file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
path = g_build_filename (g_get_user_cache_dir (),
"thumbnails/fail",
appname,
file,
NULL);
g_free (file);
pixbuf = gdk_pixbuf_new_from_file (path, NULL);
g_free (path);
if (pixbuf)
{
res = gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime);
g_object_unref (pixbuf);
}
g_checksum_free (checksum);
return res;
}
static gboolean
mimetype_supported_by_gdk_pixbuf (const char *mime_type)
{
guint i;
static gsize formats_hash = 0;
gchar *key;
gboolean result;
if (g_once_init_enter (&formats_hash)) {
GSList *formats, *list;
GHashTable *hash;
hash = g_hash_table_new_full (g_str_hash,
(GEqualFunc) g_content_type_equals,
g_free, NULL);
formats = gdk_pixbuf_get_formats ();
list = formats;
while (list) {
GdkPixbufFormat *format = list->data;
gchar **mime_types;
mime_types = gdk_pixbuf_format_get_mime_types (format);
for (i = 0; mime_types[i] != NULL; i++)
{
g_hash_table_insert (hash,
(gpointer) g_content_type_from_mime_type (mime_types[i]),
GUINT_TO_POINTER (1));
}
g_strfreev (mime_types);
list = list->next;
}
g_slist_free (formats);
g_once_init_leave (&formats_hash, (gsize) hash);
}
key = g_content_type_from_mime_type (mime_type);
if (g_hash_table_lookup ((void*)formats_hash, key))
result = TRUE;
else
result = FALSE;
g_free (key);
return result;
}
/**
* gnome_desktop_thumbnail_factory_can_thumbnail:
* @factory: a #GnomeDesktopThumbnailFactory
* @uri: the uri of a file
* @mime_type: the mime type of the file
* @mtime: the mtime of the file
*
* Returns TRUE if this GnomeIconFactory can (at least try) to thumbnail
* this file. Thumbnails or files with failed thumbnails won't be thumbnailed.
*
* Usage of this function is threadsafe.
*
* Return value: TRUE if the file can be thumbnailed.
*
* Since: 2.2
**/
gboolean
gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
const char *mime_type,
time_t mtime)
{
if (factory->priv->permissions_problem)
return FALSE;
/* Don't thumbnail thumbnails */
if (uri &&
strncmp (uri, "file:/", 6) == 0 &&
strstr (uri, "/thumbnails/") != NULL)
return FALSE;
if (!mime_type)
return FALSE;
if (gnome_desktop_thumbnail_factory_is_disabled (factory, mime_type))
{
return FALSE;
}
g_mutex_lock (&factory->priv->lock);
Thumbnailer *thumb;
thumb = g_hash_table_lookup (factory->priv->mime_types_map, mime_type);
g_mutex_unlock (&factory->priv->lock);
if (thumb || mimetype_supported_by_gdk_pixbuf (mime_type))
{
return !gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (factory,
uri,
mtime);
}
return FALSE;
}
static char *
expand_thumbnailing_script (const char *script,
const int size,
const char *inuri,
const char *outfile)
{
GString *str;
const char *p, *last;
char *localfile, *quoted;
gboolean got_in;
str = g_string_new (NULL);
got_in = FALSE;
last = script;
while ((p = strchr (last, '%')) != NULL)
{
g_string_append_len (str, last, p - last);
p++;
switch (*p) {
case 'u':
quoted = g_shell_quote (inuri);
g_string_append (str, quoted);
g_free (quoted);
got_in = TRUE;
p++;
break;
case 'i':
localfile = g_filename_from_uri (inuri, NULL, NULL);
if (localfile)
{
quoted = g_shell_quote (localfile);
g_string_append (str, quoted);
got_in = TRUE;
g_free (quoted);
g_free (localfile);
}
p++;
break;
case 'o':
quoted = g_shell_quote (outfile);
g_string_append (str, quoted);
g_free (quoted);
p++;
break;
case 's':
g_string_append_printf (str, "%d", size);
p++;
break;
case '%':
g_string_append_c (str, '%');
p++;
break;
case 0:
default:
break;
}
last = p;
}
g_string_append (str, last);
if (got_in)
return g_string_free (str, FALSE);
g_string_free (str, TRUE);
return NULL;
}
/**
* gnome_desktop_thumbnail_factory_generate_thumbnail:
* @factory: a #GnomeDesktopThumbnailFactory
* @uri: the uri of a file
* @mime_type: the mime type of the file
*
* Tries to generate a thumbnail for the specified file. If it succeeds
* it returns a pixbuf that can be used as a thumbnail.
*
* Usage of this function is threadsafe.
*
* Return value: (transfer full): thumbnail pixbuf if thumbnailing succeeded, %NULL otherwise.
*
* Since: 2.2
**/
GdkPixbuf *
gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
const char *mime_type)
{
GdkPixbuf *pixbuf, *scaled, *tmp_pixbuf;
char *script, *expanded_script;
int width, height, size;
int original_width = 0;
int original_height = 0;
char dimension[12];
double scale;
int exit_status;
char *tmpname;
gboolean disabled = FALSE;
g_return_val_if_fail (uri != NULL, NULL);
g_return_val_if_fail (mime_type != NULL, NULL);
/* Doesn't access any volatile fields in factory, so it's threadsafe */
size = 128;
if (factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE)
size = 256;
pixbuf = NULL;
script = NULL;
g_mutex_lock (&factory->priv->lock);
disabled = gnome_desktop_thumbnail_factory_is_disabled (factory, mime_type);
if (!disabled)
{
Thumbnailer *thumb;
thumb = g_hash_table_lookup (factory->priv->mime_types_map, mime_type);
if (thumb)
script = g_strdup (thumb->command);
}
g_mutex_unlock (&factory->priv->lock);
if (script)
{
int fd;
fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, NULL);
if (fd != -1)
{
close (fd);
expanded_script = expand_thumbnailing_script (script, size, uri, tmpname);
if (expanded_script != NULL &&
g_spawn_command_line_sync (expanded_script,
NULL, NULL, &exit_status, NULL) &&
exit_status == 0)
{
pixbuf = gdk_pixbuf_new_from_file (tmpname, NULL);
}
g_free (expanded_script);
g_unlink (tmpname);
g_free (tmpname);
}
g_free (script);
}
/* Fall back to gdk-pixbuf */
if (pixbuf == NULL && !disabled)
{
pixbuf = _gdk_pixbuf_new_from_uri_at_scale (uri, size, size, TRUE);
if (pixbuf != NULL)
{
original_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
"gnome-original-width"));
original_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
"gnome-original-height"));
}
}
if (pixbuf == NULL)
return NULL;
/* The pixbuf loader may attach an "orientation" option to the pixbuf,
if the tiff or exif jpeg file had an orientation tag. Rotate/flip
the pixbuf as specified by this tag, if present. */
tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
g_object_unref (pixbuf);
pixbuf = tmp_pixbuf;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
if (width > size || height > size)
{
const gchar *orig_width, *orig_height;
scale = (double)size / MAX (width, height);
scaled = gnome_desktop_thumbnail_scale_down_pixbuf (pixbuf,
floor (width * scale + 0.5),
floor (height * scale + 0.5));
orig_width = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
orig_height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
if (orig_width != NULL) {
gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Width", orig_width);
}
if (orig_height != NULL) {
gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Height", orig_height);
}
g_object_unref (pixbuf);
pixbuf = scaled;
}
if (original_width > 0) {
g_snprintf (dimension, sizeof (dimension), "%i", original_width);
gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Width", dimension);
}
if (original_height > 0) {
g_snprintf (dimension, sizeof (dimension), "%i", original_height);
gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Height", dimension);
}
return pixbuf;
}
static void
maybe_fix_ownership (GnomeDesktopThumbnailFactory *factory, const gchar *path)
{
if (factory->priv->needs_chown) {
G_GNUC_UNUSED int res;
res = chown (path,
factory->priv->real_uid,
factory->priv->real_gid);
}
}
static gboolean
make_thumbnail_dirs (GnomeDesktopThumbnailFactory *factory)
{
char *thumbnail_dir;
char *image_dir;
gboolean res;
res = FALSE;
thumbnail_dir = g_build_filename (g_get_user_cache_dir (),
"thumbnails",
NULL);
if (!g_file_test (thumbnail_dir, G_FILE_TEST_IS_DIR))
{
g_mkdir (thumbnail_dir, 0700);
maybe_fix_ownership (factory, thumbnail_dir);
res = TRUE;
}
image_dir = g_build_filename (thumbnail_dir,
(factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
NULL);
if (!g_file_test (image_dir, G_FILE_TEST_IS_DIR))
{
g_mkdir (image_dir, 0700);
maybe_fix_ownership (factory, image_dir);
res = TRUE;
}
g_free (thumbnail_dir);
g_free (image_dir);
return res;
}
static gboolean
make_thumbnail_fail_dirs (GnomeDesktopThumbnailFactory *factory)
{
char *thumbnail_dir;
char *fail_dir;
char *app_dir;
gboolean res;
res = FALSE;
thumbnail_dir = g_build_filename (g_get_user_cache_dir (),
"thumbnails",
NULL);
if (!g_file_test (thumbnail_dir, G_FILE_TEST_IS_DIR))
{
g_mkdir (thumbnail_dir, 0700);
maybe_fix_ownership (factory, thumbnail_dir);
res = TRUE;
}
fail_dir = g_build_filename (thumbnail_dir,
"fail",
NULL);
if (!g_file_test (fail_dir, G_FILE_TEST_IS_DIR))
{
g_mkdir (fail_dir, 0700);
maybe_fix_ownership (factory, fail_dir);
res = TRUE;
}
app_dir = g_build_filename (fail_dir,
appname,
NULL);
if (!g_file_test (app_dir, G_FILE_TEST_IS_DIR))
{
g_mkdir (app_dir, 0700);
maybe_fix_ownership (factory, app_dir);
res = TRUE;
}
g_free (thumbnail_dir);
g_free (fail_dir);
g_free (app_dir);
return res;
}
/**
* gnome_desktop_thumbnail_factory_save_thumbnail:
* @factory: a #GnomeDesktopThumbnailFactory
* @thumbnail: the thumbnail as a pixbuf
* @uri: the uri of a file
* @original_mtime: the modification time of the original file
*
* Saves @thumbnail at the right place. If the save fails a
* failed thumbnail is written.
*
* Usage of this function is threadsafe.
*
* Since: 2.2
**/
void
gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory,
GdkPixbuf *thumbnail,
const char *uri,
time_t original_mtime)
{
GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv;
char *path, *file;
char *tmp_path;
const char *width, *height;
int tmp_fd;
char mtime_str[21];
gboolean saved_ok;
GChecksum *checksum;
guint8 digest[16];
gsize digest_len = sizeof (digest);
GError *error;
checksum = g_checksum_new (G_CHECKSUM_MD5);
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
g_checksum_get_digest (checksum, digest, &digest_len);
g_assert (digest_len == 16);
file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
path = g_build_filename (g_get_user_cache_dir (),
"thumbnails",
(priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
file,
NULL);
g_free (file);
g_checksum_free (checksum);
tmp_path = g_strconcat (path, ".XXXXXX", NULL);
tmp_fd = g_mkstemp (tmp_path);
if (tmp_fd == -1 &&
make_thumbnail_dirs (factory))
{
g_free (tmp_path);
tmp_path = g_strconcat (path, ".XXXXXX", NULL);
tmp_fd = g_mkstemp (tmp_path);
}
if (tmp_fd == -1)
{
gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, original_mtime);
g_free (tmp_path);
g_free (path);
return;
}
close (tmp_fd);
g_snprintf (mtime_str, 21, "%ld", original_mtime);
width = gdk_pixbuf_get_option (thumbnail, "tEXt::Thumb::Image::Width");
height = gdk_pixbuf_get_option (thumbnail, "tEXt::Thumb::Image::Height");
error = NULL;
if (width != NULL && height != NULL)
saved_ok = gdk_pixbuf_save (thumbnail,
tmp_path,
"png", &error,
"tEXt::Thumb::Image::Width", width,
"tEXt::Thumb::Image::Height", height,
"tEXt::Thumb::URI", uri,
"tEXt::Thumb::MTime", mtime_str,
"tEXt::Software", "GNOME::ThumbnailFactory",
NULL);
else
saved_ok = gdk_pixbuf_save (thumbnail,
tmp_path,
"png", &error,
"tEXt::Thumb::URI", uri,
"tEXt::Thumb::MTime", mtime_str,
"tEXt::Software", "GNOME::ThumbnailFactory",
NULL);
if (saved_ok)
{
g_chmod (tmp_path, 0600);
g_rename (tmp_path, path);
maybe_fix_ownership (factory, path);
}
else
{
g_warning ("Failed to create thumbnail %s: %s", tmp_path, error->message);
gnome_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, original_mtime);
g_unlink (tmp_path);
g_clear_error (&error);
}
g_free (path);
g_free (tmp_path);
}
/**
* gnome_desktop_thumbnail_factory_create_failed_thumbnail:
* @factory: a #GnomeDesktopThumbnailFactory
* @uri: the uri of a file
* @mtime: the modification time of the file
*
* Creates a failed thumbnail for the file so that we don't try
* to re-thumbnail the file later.
*
* Usage of this function is threadsafe.
*
* Since: 2.2
**/
void
gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
time_t mtime)
{
char *path, *file;
char *tmp_path;
int tmp_fd;
char mtime_str[21];
gboolean saved_ok;
GdkPixbuf *pixbuf;
GChecksum *checksum;
guint8 digest[16];
gsize digest_len = sizeof (digest);
checksum = g_checksum_new (G_CHECKSUM_MD5);
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
g_checksum_get_digest (checksum, digest, &digest_len);
g_assert (digest_len == 16);
file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
path = g_build_filename (g_get_user_cache_dir (),
"thumbnails/fail",
appname,
file,
NULL);
g_free (file);
g_checksum_free (checksum);
tmp_path = g_strconcat (path, ".XXXXXX", NULL);
tmp_fd = g_mkstemp (tmp_path);
if (tmp_fd == -1 &&
make_thumbnail_fail_dirs (factory))
{
g_free (tmp_path);
tmp_path = g_strconcat (path, ".XXXXXX", NULL);
tmp_fd = g_mkstemp (tmp_path);
}
if (tmp_fd == -1)
{
g_free (tmp_path);
g_free (path);
return;
}
close (tmp_fd);
g_snprintf (mtime_str, 21, "%ld", mtime);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
saved_ok = gdk_pixbuf_save (pixbuf,
tmp_path,
"png", NULL,
"tEXt::Thumb::URI", uri,
"tEXt::Thumb::MTime", mtime_str,
"tEXt::Software", "GNOME::ThumbnailFactory",
NULL);
g_object_unref (pixbuf);
if (saved_ok)
{
g_chmod (tmp_path, 0600);
g_rename(tmp_path, path);
maybe_fix_ownership (factory, path);
}
g_free (path);
g_free (tmp_path);
}
/**
* gnome_desktop_thumbnail_md5:
* @uri: an uri
*
* Calculates the MD5 checksum of the uri. This can be useful
* if you want to manually handle thumbnail files.
*
* Return value: A string with the MD5 digest of the uri string.
*
* Since: 2.2
* Deprecated: 2.22: Use #GChecksum instead
**/
char *
gnome_desktop_thumbnail_md5 (const char *uri)
{
return g_compute_checksum_for_data (G_CHECKSUM_MD5,
(const guchar *) uri,
strlen (uri));
}
/**
* gnome_desktop_thumbnail_path_for_uri:
* @uri: an uri
* @size: a thumbnail size
*
* Returns the filename that a thumbnail of size @size for @uri would have.
*
* Return value: an absolute filename
*
* Since: 2.2
**/
char *
gnome_desktop_thumbnail_path_for_uri (const char *uri,
GnomeDesktopThumbnailSize size)
{
char *md5;
char *file;
char *path;
md5 = gnome_desktop_thumbnail_md5 (uri);
file = g_strconcat (md5, ".png", NULL);
g_free (md5);
path = g_build_filename (g_get_user_cache_dir (),
"thumbnails",
(size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
file,
NULL);
g_free (file);
return path;
}
/**
* gnome_desktop_thumbnail_has_uri:
* @pixbuf: an loaded thumbnail pixbuf
* @uri: a uri
*
* Returns whether the thumbnail has the correct uri embedded in the
* Thumb::URI option in the png.
*
* Return value: TRUE if the thumbnail is for @uri
*
* Since: 2.2
**/
gboolean
gnome_desktop_thumbnail_has_uri (GdkPixbuf *pixbuf,
const char *uri)
{
const char *thumb_uri;
thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
if (!thumb_uri)
return FALSE;
return strcmp (uri, thumb_uri) == 0;
}
/**
* gnome_desktop_thumbnail_is_valid:
* @pixbuf: an loaded thumbnail #GdkPixbuf
* @uri: a uri
* @mtime: the mtime
*
* Returns whether the thumbnail has the correct uri and mtime embedded in the
* png options.
*
* Return value: TRUE if the thumbnail has the right @uri and @mtime
*
* Since: 2.2
**/
gboolean
gnome_desktop_thumbnail_is_valid (GdkPixbuf *pixbuf,
const char *uri,
time_t mtime)
{
const char *thumb_uri, *thumb_mtime_str;
time_t thumb_mtime;
thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
if (!thumb_uri)
return FALSE;
if (strcmp (uri, thumb_uri) != 0)
return FALSE;
thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
if (!thumb_mtime_str)
return FALSE;
thumb_mtime = atol (thumb_mtime_str);
if (mtime != thumb_mtime)
return FALSE;
return TRUE;
}
static void
fix_owner (const gchar *path, uid_t uid, gid_t gid)
{
G_GNUC_UNUSED int res;
res = chown (path, uid, gid);
}
static gboolean
access_ok (const gchar *path, uid_t uid, gid_t gid)
{
/* user mode will always trip on this */
if (g_access (path, R_OK|W_OK) != 0) {
if (errno != ENOENT && errno != EFAULT)
return FALSE;
else
return TRUE;
}
/* root will need to check against the real user */
GStatBuf buf;
gint ret = g_stat (path, &buf);
if (ret == 0) {
if (buf.st_uid != uid || buf.st_gid != gid || (buf.st_mode & (S_IRUSR|S_IWUSR)) == 0)
return FALSE;
}
return TRUE;
}
static void
recursively_fix_file (const gchar *path, uid_t uid, gid_t gid)
{
if (!access_ok (path, uid, gid))
fix_owner (path, uid, gid);
if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
GDir *dir = g_dir_open (path, 0, NULL);
if (dir) {
const char *name;
while ((name = g_dir_read_name (dir))) {
gchar *filename;
filename = g_build_filename (path, name, NULL);
recursively_fix_file (filename, uid, gid);
g_free (filename);
}
g_dir_close (dir);
}
}
}
static gboolean
recursively_check_file (const gchar *path, uid_t uid, gid_t gid)
{
if (!access_ok (path, uid, gid))
return FALSE;
gboolean ret = TRUE;
if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
GDir *dir = g_dir_open (path, 0, NULL);
if (dir) {
const char *name;
while ((name = g_dir_read_name (dir))) {
gchar *filename;
filename = g_build_filename (path, name, NULL);
if (!recursively_check_file (filename, uid, gid)) {
ret = FALSE;
}
g_free (filename);
if (!ret)
break;
}
g_dir_close (dir);
}
}
return ret;
}
static gboolean
check_subfolder_permissions_only (const gchar *path, uid_t uid, gid_t gid)
{
gboolean ret = TRUE;
GDir *dir = g_dir_open (path, 0, NULL);
if (dir) {
const char *name;
while ((name = g_dir_read_name (dir))) {
gchar *filename;
filename = g_build_filename (path, name, NULL);
if (!access_ok (filename, uid, gid)) {
ret = FALSE;
}
g_free (filename);
if (!ret)
break;
}
g_dir_close (dir);
}
return ret;
}
/**
* gnome_desktop_cache_fix_permissions:
*
* Fixes any file or folder ownership issues for the *currently
* logged-in* user. Note - this may not be the same as the uid
* of the user running this operation.
*
**/
void
gnome_desktop_thumbnail_cache_fix_permissions (void)
{
struct passwd *pwent;
pwent = gnome_desktop_get_session_user_pwent ();
gchar *cache_dir = g_build_filename (pwent->pw_dir, ".cache", "thumbnails", NULL);
if (!access_ok (cache_dir, pwent->pw_uid, pwent->pw_gid))
fix_owner (cache_dir, pwent->pw_uid, pwent->pw_gid);
recursively_fix_file (cache_dir, pwent->pw_uid, pwent->pw_gid);
g_free (cache_dir);
}
/**
* gnome_desktop_cache_check_permissions:
* @factory: (allow-none): an optional GnomeDesktopThumbnailFactory
* @quick: if TRUE, only do a quick check of directory ownersip
* This is more serious than thumbnail ownership issues, and is faster.
*
* Returns whether there are any ownership issues with the thumbnail
* folders and existing thumbnails for the *currently logged-in* user.
* Note - this may not be the same as the uid of the user running this
* check.
*
* if factory is not NULL, factory->priv->permissions_problem will be
* set to the result of the check.
*
* Return value: TRUE if everything checks out in these folders for the
* logged in user.
*
**/
gboolean
gnome_desktop_thumbnail_cache_check_permissions (GnomeDesktopThumbnailFactory *factory, gboolean quick)
{
gboolean checks_out = TRUE;
struct passwd *pwent;
pwent = gnome_desktop_get_session_user_pwent ();
gchar *cache_dir = g_build_filename (pwent->pw_dir, ".cache", "thumbnails", NULL);
if (!access_ok (cache_dir, pwent->pw_uid, pwent->pw_gid)) {
checks_out = FALSE;
goto out;
}
if (quick) {
checks_out = check_subfolder_permissions_only (cache_dir, pwent->pw_uid, pwent->pw_gid);
} else {
checks_out = recursively_check_file (cache_dir, pwent->pw_uid, pwent->pw_gid);
}
out:
g_free (cache_dir);
if (factory)
factory->priv->permissions_problem = !checks_out;
return checks_out;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr-output-info.c 0000664 0001750 0001750 00000017751 14167325242 024056 0 ustar fabio fabio /* gnome-rr-output-info.c
* -*- c-basic-offset: 4 -*-
*
* Copyright 2010 Giovanni Campagna
*
* This file is part of the Gnome Desktop Library.
*
* The Gnome Desktop 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 Desktop 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.
*/
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include
#include "gnome-rr-config.h"
#include "edid.h"
#include "gnome-rr-private.h"
G_DEFINE_TYPE (GnomeRROutputInfo, gnome_rr_output_info, G_TYPE_OBJECT)
static void
gnome_rr_output_info_init (GnomeRROutputInfo *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfoPrivate);
self->priv->name = NULL;
self->priv->on = FALSE;
self->priv->display_name = NULL;
self->priv->scale = 1;
}
static void
gnome_rr_output_info_finalize (GObject *gobject)
{
GnomeRROutputInfo *self = GNOME_RR_OUTPUT_INFO (gobject);
g_free (self->priv->name);
g_free (self->priv->display_name);
G_OBJECT_CLASS (gnome_rr_output_info_parent_class)->finalize (gobject);
}
static void
gnome_rr_output_info_class_init (GnomeRROutputInfoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GnomeRROutputInfoPrivate));
gobject_class->finalize = gnome_rr_output_info_finalize;
}
/**
* gnome_rr_output_info_get_name:
*
* Returns: (transfer none): the output name
*/
const char *gnome_rr_output_info_get_name (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), NULL);
return self->priv->name;
}
/**
* gnome_rr_output_info_is_active:
*
* Returns: whether there is a CRTC assigned to this output (i.e. a signal is being sent to it)
*/
gboolean gnome_rr_output_info_is_active (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
return self->priv->on;
}
void gnome_rr_output_info_set_active (GnomeRROutputInfo *self, gboolean active)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->on = active;
}
/**
* gnome_rr_output_info_get_geometry:
* @self: a #GnomeRROutputInfo
* @x: (out) (allow-none):
* @y: (out) (allow-none):
* @width: (out) (allow-none):
* @height: (out) (allow-none):
*/
void gnome_rr_output_info_get_geometry (GnomeRROutputInfo *self, int *x, int *y, int *width, int *height)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
if (x)
*x = self->priv->x;
if (y)
*y = self->priv->y;
if (width)
*width = self->priv->width;
if (height)
*height = self->priv->height;
}
void gnome_rr_output_info_set_geometry (GnomeRROutputInfo *self, int x, int y, int width, int height)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->x = x;
self->priv->y = y;
self->priv->width = width;
self->priv->height = height;
}
float gnome_rr_output_info_get_scale (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), MINIMUM_LOGICAL_SCALE_FACTOR);
return self->priv->scale;
}
void gnome_rr_output_info_set_scale (GnomeRROutputInfo *self, float scale)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->scale = scale;
}
int gnome_rr_output_info_get_refresh_rate (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return (int) self->priv->rate;
}
void gnome_rr_output_info_set_refresh_rate (GnomeRROutputInfo *self, int rate)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->rate = rate * 1.0;
}
double gnome_rr_output_info_get_refresh_rate_f (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->rate;
}
void gnome_rr_output_info_set_refresh_rate_f (GnomeRROutputInfo *self, double rate)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->rate = rate;
}
GnomeRRRotation gnome_rr_output_info_get_rotation (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), GNOME_RR_ROTATION_0);
return self->priv->rotation;
}
void gnome_rr_output_info_set_rotation (GnomeRROutputInfo *self, GnomeRRRotation rotation)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->rotation = rotation;
}
void gnome_rr_output_info_get_flags (GnomeRROutputInfo *self,
gboolean *doublescan,
gboolean *interlaced,
gboolean *vsync)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
if (doublescan)
*doublescan = self->priv->doublescan;
if (interlaced)
*interlaced = self->priv->interlaced;
if (vsync)
*vsync = self->priv->vsync;
}
void gnome_rr_output_info_set_flags (GnomeRROutputInfo *self,
gboolean doublescan,
gboolean interlaced,
gboolean vsync)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->doublescan = doublescan;
self->priv->interlaced = interlaced;
self->priv->vsync = vsync;
}
/**
* gnome_rr_output_info_is_connected:
*
* Returns: whether the output is physically connected to a monitor
*/
gboolean gnome_rr_output_info_is_connected (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
return self->priv->connected;
}
/**
* gnome_rr_output_info_get_vendor:
* @self: a #GnomeRROutputInfo
* @vendor: (out caller-allocates) (array fixed-size=4):
*/
void gnome_rr_output_info_get_vendor (GnomeRROutputInfo *self, gchar* vendor)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
g_return_if_fail (vendor != NULL);
vendor[0] = self->priv->vendor[0];
vendor[1] = self->priv->vendor[1];
vendor[2] = self->priv->vendor[2];
vendor[3] = self->priv->vendor[3];
}
guint gnome_rr_output_info_get_product (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->product;
}
guint gnome_rr_output_info_get_serial (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->serial;
}
double gnome_rr_output_info_get_aspect_ratio (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->aspect;
}
/**
* gnome_rr_output_info_get_display_name:
*
* Returns: (transfer none): the display name of this output
*/
const char *gnome_rr_output_info_get_display_name (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), NULL);
return self->priv->display_name;
}
gboolean gnome_rr_output_info_get_primary (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), FALSE);
return self->priv->primary;
}
void gnome_rr_output_info_set_primary (GnomeRROutputInfo *self, gboolean primary)
{
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (self));
self->priv->primary = primary;
}
int gnome_rr_output_info_get_preferred_width (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->pref_width;
}
int gnome_rr_output_info_get_preferred_height (GnomeRROutputInfo *self)
{
g_return_val_if_fail (GNOME_IS_RR_OUTPUT_INFO (self), 0);
return self->priv->pref_height;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/private.h 0000664 0001750 0001750 00000002107 14167325242 021505 0 ustar fabio fabio /* private.h: various private functions
Copyright 2009, Novell, 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: Vincent Untz
*/
#ifndef __GNOME_DESKTOP_PRIVATE_H__
#define __GNOME_DESKTOP_PRIVATE_H__
G_BEGIN_DECLS
void _gnome_desktop_init_i18n (void);
G_END_DECLS
#endif
cinnamon-desktop-5.2.1/libcinnamon-desktop/edid.h 0000664 0001750 0001750 00000010031 14167325242 020733 0 ustar fabio fabio /* 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
*/
#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);
#endif
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr.h 0000664 0001750 0001750 00000030427 14167325242 021567 0 ustar fabio fabio /* gnome-rr.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
*/
#ifndef GNOME_RR_H
#define GNOME_RR_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error GnomeRR is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnomerr.h
#endif
#include
#include
typedef struct GnomeRRScreenPrivate GnomeRRScreenPrivate;
typedef struct GnomeRROutput GnomeRROutput;
typedef struct GnomeRRCrtc GnomeRRCrtc;
typedef struct GnomeRRMode GnomeRRMode;
typedef struct {
GObject parent;
GnomeRRScreenPrivate* priv;
} GnomeRRScreen;
typedef struct {
GObjectClass parent_class;
void (* changed) (void);
void (* output_connected) (GnomeRROutput *output);
void (* output_disconnected) (GnomeRROutput *output);
} GnomeRRScreenClass;
typedef enum
{
GNOME_RR_ROTATION_NEXT = 0,
GNOME_RR_ROTATION_0 = (1 << 0),
GNOME_RR_ROTATION_90 = (1 << 1),
GNOME_RR_ROTATION_180 = (1 << 2),
GNOME_RR_ROTATION_270 = (1 << 3),
GNOME_RR_REFLECT_X = (1 << 4),
GNOME_RR_REFLECT_Y = (1 << 5)
} GnomeRRRotation;
typedef enum {
GNOME_RR_DPMS_ON,
GNOME_RR_DPMS_STANDBY,
GNOME_RR_DPMS_SUSPEND,
GNOME_RR_DPMS_OFF,
GNOME_RR_DPMS_DISABLED,
GNOME_RR_DPMS_UNKNOWN
} GnomeRRDpmsMode;
/* Error codes */
#define GNOME_RR_ERROR (gnome_rr_error_quark ())
GQuark gnome_rr_error_quark (void);
typedef enum {
GNOME_RR_ERROR_UNKNOWN, /* generic "fail" */
GNOME_RR_ERROR_NO_RANDR_EXTENSION, /* RANDR extension is not present */
GNOME_RR_ERROR_RANDR_ERROR, /* generic/undescribed error from the underlying XRR API */
GNOME_RR_ERROR_BOUNDS_ERROR, /* requested bounds of a CRTC are outside the maximum size */
GNOME_RR_ERROR_CRTC_ASSIGNMENT, /* could not assign CRTCs to outputs */
GNOME_RR_ERROR_NO_MATCHING_CONFIG, /* none of the saved configurations matched the current configuration */
GNOME_RR_ERROR_NO_DPMS_EXTENSION /* DPMS extension is not present */
} GnomeRRError;
#define GNOME_RR_CONNECTOR_TYPE_PANEL "Panel" /* This is a laptop's built-in LCD */
#define GNOME_TYPE_RR_SCREEN (gnome_rr_screen_get_type())
#define GNOME_RR_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_SCREEN, GnomeRRScreen))
#define GNOME_IS_RR_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_SCREEN))
#define GNOME_RR_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_SCREEN, GnomeRRScreenClass))
#define GNOME_IS_RR_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_SCREEN))
#define GNOME_RR_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_SCREEN, GnomeRRScreenClass))
#define GNOME_TYPE_RR_OUTPUT (gnome_rr_output_get_type())
#define GNOME_TYPE_RR_CRTC (gnome_rr_crtc_get_type())
#define GNOME_TYPE_RR_MODE (gnome_rr_mode_get_type())
GType gnome_rr_screen_get_type (void);
GType gnome_rr_output_get_type (void);
GType gnome_rr_crtc_get_type (void);
GType gnome_rr_mode_get_type (void);
/* GnomeRRScreen */
GnomeRRScreen * gnome_rr_screen_new (GdkScreen *screen,
GError **error);
GnomeRROutput **gnome_rr_screen_list_outputs (GnomeRRScreen *screen);
GnomeRRCrtc ** gnome_rr_screen_list_crtcs (GnomeRRScreen *screen);
GnomeRRMode ** gnome_rr_screen_list_modes (GnomeRRScreen *screen);
GnomeRRMode ** gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen);
void gnome_rr_screen_set_size (GnomeRRScreen *screen,
int width,
int height,
int mm_width,
int mm_height);
GnomeRRCrtc * gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen,
guint32 id);
gboolean gnome_rr_screen_refresh (GnomeRRScreen *screen,
GError **error);
GnomeRROutput * gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen,
guint32 id);
GnomeRROutput * gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen,
const char *name);
void gnome_rr_screen_get_ranges (GnomeRRScreen *screen,
int *min_width,
int *max_width,
int *min_height,
int *max_height);
void gnome_rr_screen_get_timestamps (GnomeRRScreen *screen,
guint32 *change_timestamp_ret,
guint32 *config_timestamp_ret);
void gnome_rr_screen_set_primary_output (GnomeRRScreen *screen,
GnomeRROutput *output);
GnomeRRMode **gnome_rr_screen_create_clone_modes (GnomeRRScreen *screen);
gboolean gnome_rr_screen_get_dpms_mode (GnomeRRScreen *screen,
GnomeRRDpmsMode *mode,
GError **error);
gboolean gnome_rr_screen_set_dpms_mode (GnomeRRScreen *screen,
GnomeRRDpmsMode mode,
GError **error);
guint gnome_rr_screen_get_global_scale (GnomeRRScreen *screen);
guint gnome_rr_screen_get_global_scale_setting (GnomeRRScreen *screen);
void gnome_rr_screen_set_global_scale_setting (GnomeRRScreen *screen,
guint scale_factor);
gboolean gnome_rr_screen_get_use_upscaling (GnomeRRScreen *screen);
float * gnome_rr_screen_calculate_supported_scales (GnomeRRScreen *screen,
int width,
int height,
int *n_supported_scales);
/* screen class method, used in csd-xsettings and here */
guint gnome_rr_screen_calculate_best_global_scale (GnomeRRScreen *screen, gint index);
/* GnomeRROutput */
guint32 gnome_rr_output_get_id (GnomeRROutput *output);
const char * gnome_rr_output_get_name (GnomeRROutput *output);
gboolean gnome_rr_output_is_connected (GnomeRROutput *output);
int gnome_rr_output_get_size_inches (GnomeRROutput *output);
int gnome_rr_output_get_width_mm (GnomeRROutput *outout);
int gnome_rr_output_get_height_mm (GnomeRROutput *output);
const guint8 * gnome_rr_output_get_edid_data (GnomeRROutput *output,
gsize *size);
gboolean gnome_rr_output_get_ids_from_edid (GnomeRROutput *output,
char **vendor,
int *product,
int *serial);
gint gnome_rr_output_get_backlight_min (GnomeRROutput *output);
gint gnome_rr_output_get_backlight_max (GnomeRROutput *output);
gint gnome_rr_output_get_backlight (GnomeRROutput *output,
GError **error);
gboolean gnome_rr_output_set_backlight (GnomeRROutput *output,
gint value,
GError **error);
GnomeRRCrtc ** gnome_rr_output_get_possible_crtcs (GnomeRROutput *output);
GnomeRRMode * gnome_rr_output_get_current_mode (GnomeRROutput *output);
GnomeRRCrtc * gnome_rr_output_get_crtc (GnomeRROutput *output);
const char * gnome_rr_output_get_connector_type (GnomeRROutput *output);
gboolean gnome_rr_output_is_laptop (GnomeRROutput *output);
void gnome_rr_output_get_position (GnomeRROutput *output,
int *x,
int *y);
gboolean gnome_rr_output_can_clone (GnomeRROutput *output,
GnomeRROutput *clone);
GnomeRRMode ** gnome_rr_output_list_modes (GnomeRROutput *output);
GnomeRRMode * gnome_rr_output_get_preferred_mode (GnomeRROutput *output);
gboolean gnome_rr_output_supports_mode (GnomeRROutput *output,
GnomeRRMode *mode);
gboolean gnome_rr_output_get_is_primary (GnomeRROutput *output);
/* GnomeRRMode */
guint32 gnome_rr_mode_get_id (GnomeRRMode *mode);
guint gnome_rr_mode_get_width (GnomeRRMode *mode);
guint gnome_rr_mode_get_height (GnomeRRMode *mode);
int gnome_rr_mode_get_freq (GnomeRRMode *mode);
double gnome_rr_mode_get_freq_f (GnomeRRMode *mode);
void gnome_rr_mode_get_flags (GnomeRRMode *mode,
gboolean *doublescan,
gboolean *interlaced,
gboolean *vsync);
/* GnomeRRCrtc */
guint32 gnome_rr_crtc_get_id (GnomeRRCrtc *crtc);
gboolean gnome_rr_crtc_set_config_with_time (GnomeRRCrtc *crtc,
guint32 timestamp,
int x,
int y,
GnomeRRMode *mode,
GnomeRRRotation rotation,
GnomeRROutput **outputs,
int n_outputs,
float scale,
guint global_scale,
GError **error);
gboolean gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc,
GnomeRROutput *output);
GnomeRRMode * gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc);
void gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
int *x,
int *y);
float gnome_rr_crtc_get_scale (GnomeRRCrtc *crtc);
GnomeRRRotation gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc);
GnomeRRRotation gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc);
gboolean gnome_rr_crtc_supports_rotation (GnomeRRCrtc *crtc,
GnomeRRRotation rotation);
gboolean gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc,
int *size,
unsigned short **red,
unsigned short **green,
unsigned short **blue);
void gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc,
int size,
unsigned short *red,
unsigned short *green,
unsigned short *blue);
#endif /* GNOME_RR_H */
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-xkb-info.c 0000664 0001750 0001750 00000071402 14167325242 022652 0 ustar fabio fabio /*
* Copyright (C) 2012 Red Hat, Inc.
*
* Written by: Rui Matos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define XKEYBOARD_CONFIG_(String) ((char *) g_dgettext ("xkeyboard-config", String))
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-xkb-info.h"
#ifndef XKB_RULES_FILE
#define XKB_RULES_FILE "evdev"
#endif
#ifndef XKB_LAYOUT
#define XKB_LAYOUT "us"
#endif
#ifndef XKB_MODEL
#define XKB_MODEL "pc105+inet"
#endif
typedef struct _Layout Layout;
struct _Layout
{
gchar *id;
gchar *xkb_name;
gchar *short_desc;
gchar *description;
gboolean is_variant;
const Layout *main_layout;
};
typedef struct _XkbOption XkbOption;
struct _XkbOption
{
gchar *id;
gchar *description;
};
typedef struct _XkbOptionGroup XkbOptionGroup;
struct _XkbOptionGroup
{
gchar *id;
gchar *description;
gboolean allow_multiple_selection;
GHashTable *options_table;
};
struct _GnomeXkbInfoPrivate
{
GHashTable *option_groups_table;
GHashTable *layouts_by_short_desc;
GHashTable *layouts_by_iso639;
GHashTable *layouts_table;
/* Only used while parsing */
XkbOptionGroup *current_parser_group;
XkbOption *current_parser_option;
Layout *current_parser_layout;
Layout *current_parser_variant;
gchar *current_parser_iso639Id;
gchar **current_parser_text;
};
G_DEFINE_TYPE (GnomeXkbInfo, gnome_xkb_info, G_TYPE_OBJECT);
static void
free_layout (gpointer data)
{
Layout *layout = data;
g_return_if_fail (layout != NULL);
g_free (layout->id);
g_free (layout->xkb_name);
g_free (layout->short_desc);
g_free (layout->description);
g_slice_free (Layout, layout);
}
static void
free_option (gpointer data)
{
XkbOption *option = data;
g_return_if_fail (option != NULL);
g_free (option->id);
g_free (option->description);
g_slice_free (XkbOption, option);
}
static void
free_option_group (gpointer data)
{
XkbOptionGroup *group = data;
g_return_if_fail (group != NULL);
g_free (group->id);
g_free (group->description);
g_hash_table_destroy (group->options_table);
g_slice_free (XkbOptionGroup, group);
}
/**
* gnome_xkb_info_get_var_defs: (skip)
* @rules: (out) (transfer full): location to store the rules file
* path. Use g_free() when it's no longer needed
* @var_defs: (out) (transfer full): location to store a
* #XkbRF_VarDefsRec pointer. Use gnome_xkb_info_free_var_defs() to
* free it
*
* Gets both the XKB rules file path and the current XKB parameters in
* use by the X server.
*
* Since: 3.6
*/
void
gnome_xkb_info_get_var_defs (gchar **rules,
XkbRF_VarDefsRec **var_defs)
{
Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
char *tmp;
g_return_if_fail (rules != NULL);
g_return_if_fail (var_defs != NULL);
*rules = NULL;
*var_defs = g_new0 (XkbRF_VarDefsRec, 1);
gdk_error_trap_push ();
/* Get it from the X property or fallback on defaults */
if (!XkbRF_GetNamesProp (display, rules, *var_defs) || !*rules)
{
*rules = strdup (XKB_RULES_FILE);
(*var_defs)->model = strdup (XKB_MODEL);
(*var_defs)->layout = strdup (XKB_LAYOUT);
(*var_defs)->variant = NULL;
(*var_defs)->options = NULL;
}
gdk_error_trap_pop_ignored ();
tmp = *rules;
if (*rules[0] == '/')
*rules = g_strdup (*rules);
else
*rules = g_build_filename (XKB_BASE, "rules", *rules, NULL);
free (tmp);
}
/**
* gnome_xkb_info_free_var_defs: (skip)
* @var_defs: #XkbRF_VarDefsRec instance to free
*
* Frees an #XkbRF_VarDefsRec instance allocated by
* gnome_xkb_info_get_var_defs().
*
* Since: 3.6
*/
void
gnome_xkb_info_free_var_defs (XkbRF_VarDefsRec *var_defs)
{
g_return_if_fail (var_defs != NULL);
free (var_defs->model);
free (var_defs->layout);
free (var_defs->variant);
free (var_defs->options);
g_free (var_defs);
}
static gchar *
get_xml_rules_file_path (const gchar *suffix)
{
XkbRF_VarDefsRec *xkb_var_defs;
gchar *rules_file;
gchar *xml_rules_file;
gnome_xkb_info_get_var_defs (&rules_file, &xkb_var_defs);
gnome_xkb_info_free_var_defs (xkb_var_defs);
xml_rules_file = g_strdup_printf ("%s%s", rules_file, suffix);
g_free (rules_file);
return xml_rules_file;
}
static void
parse_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer data,
GError **error)
{
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
if (priv->current_parser_text)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"Expected character data but got element '%s'", element_name);
return;
}
if (strcmp (element_name, "name") == 0)
{
if (priv->current_parser_variant)
priv->current_parser_text = &priv->current_parser_variant->xkb_name;
else if (priv->current_parser_layout)
priv->current_parser_text = &priv->current_parser_layout->xkb_name;
else if (priv->current_parser_option)
priv->current_parser_text = &priv->current_parser_option->id;
else if (priv->current_parser_group)
priv->current_parser_text = &priv->current_parser_group->id;
}
else if (strcmp (element_name, "description") == 0)
{
if (priv->current_parser_variant)
priv->current_parser_text = &priv->current_parser_variant->description;
else if (priv->current_parser_layout)
priv->current_parser_text = &priv->current_parser_layout->description;
else if (priv->current_parser_option)
priv->current_parser_text = &priv->current_parser_option->description;
else if (priv->current_parser_group)
priv->current_parser_text = &priv->current_parser_group->description;
}
else if (strcmp (element_name, "shortDescription") == 0)
{
if (priv->current_parser_variant)
priv->current_parser_text = &priv->current_parser_variant->short_desc;
else if (priv->current_parser_layout)
priv->current_parser_text = &priv->current_parser_layout->short_desc;
}
else if (strcmp (element_name, "iso639Id") == 0)
{
priv->current_parser_text = &priv->current_parser_iso639Id;
}
else if (strcmp (element_name, "layout") == 0)
{
if (priv->current_parser_layout)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'layout' elements can't be nested");
return;
}
priv->current_parser_layout = g_slice_new0 (Layout);
}
else if (strcmp (element_name, "variant") == 0)
{
Layout *layout;
if (priv->current_parser_variant)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements can't be nested");
return;
}
if (!priv->current_parser_layout)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements must be inside 'layout' elements");
return;
}
if (!priv->current_parser_layout->xkb_name)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements must be inside named 'layout' elements");
return;
}
layout = g_hash_table_lookup (priv->layouts_table, priv->current_parser_layout->xkb_name);
if (!layout)
layout = priv->current_parser_layout;
priv->current_parser_variant = g_slice_new0 (Layout);
priv->current_parser_variant->is_variant = TRUE;
priv->current_parser_variant->main_layout = layout;
}
else if (strcmp (element_name, "group") == 0)
{
if (priv->current_parser_group)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'group' elements can't be nested");
return;
}
priv->current_parser_group = g_slice_new0 (XkbOptionGroup);
/* Maps option ids to XkbOption structs. Owns the XkbOption structs. */
priv->current_parser_group->options_table = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, free_option);
g_markup_collect_attributes (element_name,
attribute_names,
attribute_values,
error,
G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL,
"allowMultipleSelection",
&priv->current_parser_group->allow_multiple_selection,
G_MARKUP_COLLECT_INVALID);
}
else if (strcmp (element_name, "option") == 0)
{
if (priv->current_parser_option)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'option' elements can't be nested");
return;
}
if (!priv->current_parser_group)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'option' elements must be inside 'group' elements");
return;
}
priv->current_parser_option = g_slice_new0 (XkbOption);
}
}
static gboolean
maybe_replace (GHashTable *table,
gchar *key,
Layout *new_layout)
{
/* There might be multiple layouts for the same language. In that
* case considering the "canonical" layout to be the one with the
* shorter description seems to be good enough. */
Layout *layout;
gboolean exists;
gboolean replace = TRUE;
exists = g_hash_table_lookup_extended (table, key, NULL, (gpointer *)&layout);
if (exists)
replace = strlen (new_layout->description) < strlen (layout->description);
if (replace)
g_hash_table_replace (table, key, new_layout);
return replace;
}
static void
parse_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer data,
GError **error)
{
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
if (strcmp (element_name, "layout") == 0)
{
if (!priv->current_parser_layout->description || !priv->current_parser_layout->xkb_name)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'layout' elements must enclose 'description' and 'name' elements");
return;
}
priv->current_parser_layout->id = g_strdup (priv->current_parser_layout->xkb_name);
if (g_hash_table_contains (priv->layouts_table, priv->current_parser_layout->id))
{
if (priv->current_parser_layout != NULL) {
free_layout (priv->current_parser_layout);
priv->current_parser_layout = NULL;
}
return;
}
if (priv->current_parser_layout->short_desc)
maybe_replace (priv->layouts_by_short_desc,
priv->current_parser_layout->short_desc, priv->current_parser_layout);
g_hash_table_replace (priv->layouts_table,
priv->current_parser_layout->id,
priv->current_parser_layout);
priv->current_parser_layout = NULL;
}
else if (strcmp (element_name, "variant") == 0)
{
if (!priv->current_parser_variant->description || !priv->current_parser_variant->xkb_name)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements must enclose 'description' and 'name' elements");
return;
}
priv->current_parser_variant->id = g_strjoin ("+",
priv->current_parser_layout->xkb_name,
priv->current_parser_variant->xkb_name,
NULL);
if (priv->current_parser_variant->short_desc)
maybe_replace (priv->layouts_by_short_desc,
priv->current_parser_variant->short_desc, priv->current_parser_variant);
g_hash_table_replace (priv->layouts_table,
priv->current_parser_variant->id,
priv->current_parser_variant);
priv->current_parser_variant = NULL;
}
else if (strcmp (element_name, "iso639Id") == 0)
{
gboolean replaced = FALSE;
if (!priv->current_parser_iso639Id)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'iso639Id' elements must enclose text");
return;
}
if (priv->current_parser_layout)
replaced = maybe_replace (priv->layouts_by_iso639,
priv->current_parser_iso639Id, priv->current_parser_layout);
else if (priv->current_parser_variant)
replaced = maybe_replace (priv->layouts_by_iso639,
priv->current_parser_iso639Id, priv->current_parser_variant);
if (!replaced)
g_free (priv->current_parser_iso639Id);
priv->current_parser_iso639Id = NULL;
}
else if (strcmp (element_name, "group") == 0)
{
if (!priv->current_parser_group->description || !priv->current_parser_group->id)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'group' elements must enclose 'description' and 'name' elements");
return;
}
g_hash_table_replace (priv->option_groups_table,
priv->current_parser_group->id,
priv->current_parser_group);
priv->current_parser_group = NULL;
}
else if (strcmp (element_name, "option") == 0)
{
if (!priv->current_parser_option->description || !priv->current_parser_option->id)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'option' elements must enclose 'description' and 'name' elements");
return;
}
g_hash_table_replace (priv->current_parser_group->options_table,
priv->current_parser_option->id,
priv->current_parser_option);
priv->current_parser_option = NULL;
}
}
static void
parse_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer data,
GError **error)
{
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
if (priv->current_parser_text)
{
*priv->current_parser_text = g_strndup (text, text_len);
priv->current_parser_text = NULL;
}
}
static void
parse_error (GMarkupParseContext *context,
GError *error,
gpointer data)
{
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
free_option_group (priv->current_parser_group);
free_option (priv->current_parser_option);
free_layout (priv->current_parser_layout);
free_layout (priv->current_parser_variant);
g_free (priv->current_parser_iso639Id);
}
static const GMarkupParser markup_parser = {
parse_start_element,
parse_end_element,
parse_text,
NULL,
parse_error
};
static void
parse_rules_file (GnomeXkbInfo *self,
const gchar *path,
GError **error)
{
gchar *buffer;
gsize length;
GMarkupParseContext *context;
GError *sub_error = NULL;
g_file_get_contents (path, &buffer, &length, &sub_error);
if (sub_error)
{
g_propagate_error (error, sub_error);
return;
}
context = g_markup_parse_context_new (&markup_parser, 0, self, NULL);
g_markup_parse_context_parse (context, buffer, length, &sub_error);
g_markup_parse_context_free (context);
g_free (buffer);
if (sub_error)
g_propagate_error (error, sub_error);
}
static void
parse_rules (GnomeXkbInfo *self)
{
GnomeXkbInfoPrivate *priv = self->priv;
GSettings *settings;
gboolean show_all_sources;
gchar *file_path;
GError *error = NULL;
/* Maps option group ids to XkbOptionGroup structs. Owns the
XkbOptionGroup structs. */
priv->option_groups_table = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, free_option_group);
priv->layouts_by_short_desc = g_hash_table_new (g_str_hash, g_str_equal);
priv->layouts_by_iso639 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
/* Maps layout ids to Layout structs. Owns the Layout structs. */
priv->layouts_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_layout);
file_path = get_xml_rules_file_path (".xml");
parse_rules_file (self, file_path, &error);
if (error)
goto cleanup;
g_free (file_path);
settings = g_settings_new ("org.gnome.desktop.input-sources");
show_all_sources = g_settings_get_boolean (settings, "show-all-sources");
g_object_unref (settings);
if (!show_all_sources)
return;
file_path = get_xml_rules_file_path (".extras.xml");
parse_rules_file (self, file_path, &error);
if (error)
goto cleanup;
g_free (file_path);
return;
cleanup:
if (error != NULL) {
g_warning ("Failed to load XKB rules file %s: %s", file_path, error->message);
g_error_free (error);
error = NULL;
}
if (file_path != NULL) {
g_free (file_path);
file_path = NULL;
}
if (priv->option_groups_table != NULL) {
g_hash_table_destroy (priv->option_groups_table);
priv->option_groups_table = NULL;
}
if (priv->layouts_by_short_desc != NULL) {
g_hash_table_destroy (priv->layouts_by_short_desc);
priv->layouts_by_short_desc = NULL;
}
if (priv->layouts_by_iso639 != NULL) {
g_hash_table_destroy (priv->layouts_by_iso639);
priv->layouts_by_iso639 = NULL;
}
if (priv->layouts_table != NULL) {
g_hash_table_destroy (priv->layouts_table);
priv->layouts_table = NULL;
}
}
static gboolean
ensure_rules_are_parsed (GnomeXkbInfo *self)
{
GnomeXkbInfoPrivate *priv = self->priv;
if (!priv->layouts_table)
parse_rules (self);
return !!priv->layouts_table;
}
static void
gnome_xkb_info_init (GnomeXkbInfo *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_XKB_INFO, GnomeXkbInfoPrivate);
}
static void
gnome_xkb_info_finalize (GObject *self)
{
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (self)->priv;
if (priv->option_groups_table)
g_hash_table_destroy (priv->option_groups_table);
if (priv->layouts_by_short_desc)
g_hash_table_destroy (priv->layouts_by_short_desc);
if (priv->layouts_by_iso639)
g_hash_table_destroy (priv->layouts_by_iso639);
if (priv->layouts_table)
g_hash_table_destroy (priv->layouts_table);
G_OBJECT_CLASS (gnome_xkb_info_parent_class)->finalize (self);
}
static void
gnome_xkb_info_class_init (GnomeXkbInfoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gnome_xkb_info_finalize;
g_type_class_add_private (gobject_class, sizeof (GnomeXkbInfoPrivate));
}
/**
* gnome_xkb_info_new:
*
* Returns: (transfer full): a new #GnomeXkbInfo instance.
*/
GnomeXkbInfo *
gnome_xkb_info_new (void)
{
return g_object_new (GNOME_TYPE_XKB_INFO, NULL);
}
/**
* gnome_xkb_info_get_all_layouts:
* @self: a #GnomeXkbInfo
*
* Returns a list of all layout identifiers we know about.
*
* Return value: (transfer container) (element-type utf8): the list
* of layout names. The caller takes ownership of the #GList but not
* of the strings themselves, those are internally allocated and must
* not be modified.
*
* Since: 3.6
*/
GList *
gnome_xkb_info_get_all_layouts (GnomeXkbInfo *self)
{
GnomeXkbInfoPrivate *priv;
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
priv = self->priv;
if (!ensure_rules_are_parsed (self))
return NULL;
return g_hash_table_get_keys (priv->layouts_table);
}
/**
* gnome_xkb_info_get_all_option_groups:
* @self: a #GnomeXkbInfo
*
* Returns a list of all option group identifiers we know about.
*
* Return value: (transfer container) (element-type utf8): the list
* of option group ids. The caller takes ownership of the #GList but
* not of the strings themselves, those are internally allocated and
* must not be modified.
*
* Since: 3.6
*/
GList *
gnome_xkb_info_get_all_option_groups (GnomeXkbInfo *self)
{
GnomeXkbInfoPrivate *priv;
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
priv = self->priv;
if (!ensure_rules_are_parsed (self))
return NULL;
return g_hash_table_get_keys (priv->option_groups_table);
}
/**
* gnome_xkb_info_get_options_for_group:
* @self: a #GnomeXkbInfo
* @group_id: group's identifier about which to retrieve the options
*
* Returns a list of all option identifiers we know about for group
* @group_id.
*
* Return value: (transfer container) (element-type utf8): the list
* of option ids. The caller takes ownership of the #GList but not of
* the strings themselves, those are internally allocated and must not
* be modified.
*
* Since: 3.6
*/
GList *
gnome_xkb_info_get_options_for_group (GnomeXkbInfo *self,
const gchar *group_id)
{
GnomeXkbInfoPrivate *priv;
const XkbOptionGroup *group;
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
priv = self->priv;
if (!ensure_rules_are_parsed (self))
return NULL;
group = g_hash_table_lookup (priv->option_groups_table, group_id);
if (!group)
return NULL;
return g_hash_table_get_keys (group->options_table);
}
/**
* gnome_xkb_info_description_for_option:
* @self: a #GnomeXkbInfo
* @group_id: identifier for group containing the option
* @id: option identifier
*
* Return value: the translated description for the option @id.
*
* Since: 3.6
*/
const gchar *
gnome_xkb_info_description_for_option (GnomeXkbInfo *self,
const gchar *group_id,
const gchar *id)
{
GnomeXkbInfoPrivate *priv;
const XkbOptionGroup *group;
const XkbOption *option;
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
priv = self->priv;
if (!ensure_rules_are_parsed (self))
return NULL;
group = g_hash_table_lookup (priv->option_groups_table, group_id);
if (!group)
return NULL;
option = g_hash_table_lookup (group->options_table, id);
if (!option)
return NULL;
return XKEYBOARD_CONFIG_(option->description);
}
/**
* gnome_xkb_info_get_layout_info:
* @self: a #GnomeXkbInfo
* @id: layout's identifier about which to retrieve the info
* @display_name: (out) (allow-none) (transfer none): location to store
* the layout's display name, or %NULL
* @short_name: (out) (allow-none) (transfer none): location to store
* the layout's short name, or %NULL
* @xkb_layout: (out) (allow-none) (transfer none): location to store
* the layout's XKB name, or %NULL
* @xkb_variant: (out) (allow-none) (transfer none): location to store
* the layout's XKB variant, or %NULL
*
* Retrieves information about a layout. Both @display_name and
* @short_name are suitable to show in UIs and might be localized if
* translations are available.
*
* Some layouts don't provide a short name (2 or 3 letters) or don't
* specify a XKB variant, in those cases @short_name or @xkb_variant
* are empty strings, i.e. "".
*
* If the given layout doesn't exist the return value is %FALSE and
* all the (out) parameters are set to %NULL.
*
* Return value: %TRUE if the layout exists or %FALSE otherwise.
*
* Since: 3.6
*/
gboolean
gnome_xkb_info_get_layout_info (GnomeXkbInfo *self,
const gchar *id,
const gchar **display_name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant)
{
GnomeXkbInfoPrivate *priv;
const Layout *layout;
if (display_name)
*display_name = NULL;
if (short_name)
*short_name = NULL;
if (xkb_layout)
*xkb_layout = NULL;
if (xkb_variant)
*xkb_variant = NULL;
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), FALSE);
priv = self->priv;
if (!ensure_rules_are_parsed (self))
return FALSE;
if (!g_hash_table_lookup_extended (priv->layouts_table, id, NULL, (gpointer *)&layout))
return FALSE;
if (display_name)
*display_name = XKEYBOARD_CONFIG_(layout->description);
if (!layout->is_variant)
{
if (short_name)
*short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc : "");
if (xkb_layout)
*xkb_layout = layout->xkb_name;
if (xkb_variant)
*xkb_variant = "";
}
else
{
if (short_name)
*short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc :
layout->main_layout->short_desc ? layout->main_layout->short_desc : "");
if (xkb_layout)
*xkb_layout = layout->main_layout->xkb_name;
if (xkb_variant)
*xkb_variant = layout->xkb_name;
}
return TRUE;
}
/**
* gnome_xkb_info_get_layout_info_for_language:
* @self: a #GnomeXkbInfo
* @language: an ISO 639 code
* @id: (out) (allow-none) (transfer none): location to store the
* layout's indentifier, or %NULL
* @display_name: (out) (allow-none) (transfer none): location to store
* the layout's display name, or %NULL
* @short_name: (out) (allow-none) (transfer none): location to store
* the layout's short name, or %NULL
* @xkb_layout: (out) (allow-none) (transfer none): location to store
* the layout's XKB name, or %NULL
* @xkb_variant: (out) (allow-none) (transfer none): location to store
* the layout's XKB variant, or %NULL
*
* Retrieves the layout that better fits @language. It also fetches
* information about that layout like gnome_xkb_info_get_layout_info().
*
* If a layout can't be found the return value is %FALSE and all the
* (out) parameters are set to %NULL.
*
* Return value: %TRUE if a layout exists or %FALSE otherwise.
*
* Since: 3.6
*/
gboolean
gnome_xkb_info_get_layout_info_for_language (GnomeXkbInfo *self,
const gchar *language,
const gchar **id,
const gchar **display_name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant)
{
GnomeXkbInfoPrivate *priv;
const Layout *layout;
if (id)
*id = NULL;
if (display_name)
*display_name = NULL;
if (short_name)
*short_name = NULL;
if (xkb_layout)
*xkb_layout = NULL;
if (xkb_variant)
*xkb_variant = NULL;
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), FALSE);
priv = self->priv;
if (!ensure_rules_are_parsed (self))
return FALSE;
/* First look in the proper language codes index, if we can't find
* it there try again on the (untranslated) short descriptions since
* sometimes those will give us a good match. */
if (!g_hash_table_lookup_extended (priv->layouts_by_iso639, language, NULL, (gpointer *)&layout))
if (!g_hash_table_lookup_extended (priv->layouts_by_short_desc, language, NULL, (gpointer *)&layout))
return FALSE;
if (id)
*id = layout->id;
if (display_name)
*display_name = XKEYBOARD_CONFIG_(layout->description);
if (!layout->is_variant)
{
if (short_name)
*short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc : "");
if (xkb_layout)
*xkb_layout = layout->xkb_name;
if (xkb_variant)
*xkb_variant = "";
}
else
{
if (short_name)
*short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc :
layout->main_layout->short_desc ? layout->main_layout->short_desc : "");
if (xkb_layout)
*xkb_layout = layout->main_layout->xkb_name;
if (xkb_variant)
*xkb_variant = layout->xkb_name;
}
return TRUE;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-pnp-ids.c 0000664 0001750 0001750 00000023055 14167325242 022510 0 ustar fabio fabio /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2009-2011 Richard Hughes
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include
#include "gnome-pnp-ids.h"
static void gnome_pnp_ids_finalize (GObject *object);
#define GNOME_PNP_IDS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_PNP_IDSS, GnomePnpIdsPrivate))
struct _GnomePnpIdsPrivate
{
gchar *table_data;
GHashTable *pnp_table;
};
static gpointer gnome_pnp_ids_object = NULL;
G_DEFINE_TYPE (GnomePnpIds, gnome_pnp_ids, G_TYPE_OBJECT)
typedef struct Vendor Vendor;
struct Vendor
{
const char vendor_id[4];
const char vendor_name[28];
};
/* This list of vendor codes derived from lshw
*
* http://ezix.org/project/wiki/HardwareLiSter
*
* Note: we now prefer to use data coming from hwdata (and shipped with
* gnome-desktop). See
* http://git.fedorahosted.org/git/?p=hwdata.git;a=blob_plain;f=pnp.ids;hb=HEAD
* All contributions to the list of vendors should go there.
*/
static const struct Vendor vendors[] =
{
{ "AIC", "AG Neovo" },
{ "ACR", "Acer" },
{ "DEL", "DELL" },
{ "SAM", "SAMSUNG" },
{ "SNY", "SONY" },
{ "SEC", "Epson" },
{ "WAC", "Wacom" },
{ "NEC", "NEC" },
{ "CMO", "CMO" }, /* Chi Mei */
{ "BNQ", "BenQ" },
{ "ABP", "Advansys" },
{ "ACC", "Accton" },
{ "ACE", "Accton" },
{ "ADP", "Adaptec" },
{ "ADV", "AMD" },
{ "AIR", "AIR" },
{ "AMI", "AMI" },
{ "ASU", "ASUS" },
{ "ATI", "ATI" },
{ "ATK", "Allied Telesyn" },
{ "AZT", "Aztech" },
{ "BAN", "Banya" },
{ "BRI", "Boca Research" },
{ "BUS", "Buslogic" },
{ "CCI", "Cache Computers Inc." },
{ "CHA", "Chase" },
{ "CMD", "CMD Technology, Inc." },
{ "COG", "Cogent" },
{ "CPQ", "Compaq" },
{ "CRS", "Crescendo" },
{ "CSC", "Crystal" },
{ "CSI", "CSI" },
{ "CTL", "Creative Labs" },
{ "DBI", "Digi" },
{ "DEC", "Digital Equipment" },
{ "DBK", "Databook" },
{ "EGL", "Eagle Technology" },
{ "ELS", "ELSA" },
{ "ESS", "ESS" },
{ "FAR", "Farallon" },
{ "FDC", "Future Domain" },
{ "HWP", "Hewlett-Packard" },
{ "IBM", "IBM" },
{ "INT", "Intel" },
{ "ISA", "Iomega" },
{ "LEN", "Lenovo" },
{ "MDG", "Madge" },
{ "MDY", "Microdyne" },
{ "MET", "Metheus" },
{ "MIC", "Micronics" },
{ "MLX", "Mylex" },
{ "NVL", "Novell" },
{ "OLC", "Olicom" },
{ "PRO", "Proteon" },
{ "RII", "Racal" },
{ "RTL", "Realtek" },
{ "SCM", "SCM" },
{ "SKD", "SysKonnect" },
{ "SGI", "SGI" },
{ "SMC", "SMC" },
{ "SNI", "Siemens Nixdorf" },
{ "STL", "Stallion Technologies" },
{ "SUN", "Sun" },
{ "SUP", "SupraExpress" },
{ "SVE", "SVEC" },
{ "TCC", "Thomas-Conrad" },
{ "TCI", "Tulip" },
{ "TCM", "3Com" },
{ "TCO", "Thomas-Conrad" },
{ "TEC", "Tecmar" },
{ "TRU", "Truevision" },
{ "TOS", "Toshiba" },
{ "TYN", "Tyan" },
{ "UBI", "Ungermann-Bass" },
{ "USC", "UltraStor" },
{ "VDM", "Vadem" },
{ "VMI", "Vermont" },
{ "WDC", "Western Digital" },
{ "ZDS", "Zeos" },
/* From http://faydoc.tripod.com/structures/01/0136.htm */
{ "ACT", "Targa" },
{ "ADI", "ADI" },
{ "AOC", "AOC Intl" },
{ "API", "Acer America" },
{ "APP", "Apple Computer" },
{ "ART", "ArtMedia" },
{ "AST", "AST Research" },
{ "CPL", "Compal" },
{ "CTX", "Chuntex Electronic Co." },
{ "DPC", "Delta Electronics" },
{ "DWE", "Daewoo" },
{ "ECS", "ELITEGROUP" },
{ "EIZ", "EIZO" },
{ "FCM", "Funai" },
{ "GSM", "LG Electronics" },
{ "GWY", "Gateway 2000" },
{ "HEI", "Hyundai" },
{ "HIT", "Hitachi" },
{ "HSL", "Hansol" },
{ "HTC", "Hitachi" },
{ "ICL", "Fujitsu ICL" },
{ "IVM", "Idek Iiyama" },
{ "KFC", "KFC Computek" },
{ "LKM", "ADLAS" },
{ "LNK", "LINK Tech" },
{ "LTN", "Lite-On" },
{ "MAG", "MAG InnoVision" },
{ "MAX", "Maxdata" },
{ "MEI", "Panasonic" },
{ "MEL", "Mitsubishi" },
{ "MIR", "miro" },
{ "MTC", "MITAC" },
{ "NAN", "NANAO" },
{ "NEC", "NEC Tech" },
{ "NOK", "Nokia" },
{ "OQI", "OPTIQUEST" },
{ "PBN", "Packard Bell" },
{ "PGS", "Princeton" },
{ "PHL", "Philips" },
{ "REL", "Relisys" },
{ "SDI", "Samtron" },
{ "SMI", "Smile" },
{ "SPT", "Sceptre" },
{ "SRC", "Shamrock Technology" },
{ "STP", "Sceptre" },
{ "TAT", "Tatung" },
{ "TRL", "Royal Information Company" },
{ "TSB", "Toshiba, Inc." },
{ "UNM", "Unisys" },
{ "VSC", "ViewSonic" },
{ "WTC", "Wen Tech" },
{ "ZCM", "Zenith Data Systems" },
{ "???", "Unknown" },
};
static gboolean
gnome_pnp_ids_load (GnomePnpIds *pnp_ids, GError **error)
{
gchar *retval = NULL;
GnomePnpIdsPrivate *priv = pnp_ids->priv;
guint i;
/* load the contents */
g_debug ("loading: %s", PNP_IDS);
if (g_file_get_contents (PNP_IDS, &priv->table_data, NULL, error) == FALSE)
return FALSE;
/* parse into lines */
retval = priv->table_data;
for (i = 0; priv->table_data[i] != '\0'; i++) {
/* ignore */
if (priv->table_data[i] != '\n')
continue;
/* convert newline to NULL */
priv->table_data[i] = '\0';
/* the ID to text is a fixed offset */
if (retval[0] && retval[1] && retval[2] && retval[3] == '\t' && retval[4]) {
retval[3] = '\0';
g_hash_table_insert (priv->pnp_table,
retval,
retval+4);
retval = &priv->table_data[i+1];
}
}
return TRUE;
}
static const char *
find_vendor (const char *pnp_id)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (vendors); i++) {
if (g_strcmp0 (vendors[i].vendor_id, pnp_id) == 0)
return vendors[i].vendor_name;
}
return NULL;
}
/**
* gnome_pnp_ids_get_pnp_id:
* @pnp_ids: a #GnomePnpIds object
* @pnp_id: the PNP ID to look for
*
* Find the full manufacturer name for the given PNP ID.
*
* Returns: (transfer full): a new string representing the manufacturer name,
* or %NULL when not found.
*/
gchar *
gnome_pnp_ids_get_pnp_id (GnomePnpIds *pnp_ids, const gchar *pnp_id)
{
GnomePnpIdsPrivate *priv = pnp_ids->priv;
const char *found;
guint size;
g_return_val_if_fail (GNOME_IS_PNP_IDSS (pnp_ids), NULL);
g_return_val_if_fail (pnp_id != NULL, NULL);
/* if table is empty, try to load it */
size = g_hash_table_size (priv->pnp_table);
if (size == 0) {
if (gnome_pnp_ids_load (pnp_ids, NULL) == FALSE)
return NULL;
}
/* look this up in the table */
found = g_hash_table_lookup (priv->pnp_table, pnp_id);
if (found == NULL) {
found = find_vendor (pnp_id);
if (found == NULL)
return NULL;
}
return g_strdup (found);
}
static void
gnome_pnp_ids_class_init (GnomePnpIdsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gnome_pnp_ids_finalize;
g_type_class_add_private (klass, sizeof (GnomePnpIdsPrivate));
}
static void
gnome_pnp_ids_init (GnomePnpIds *pnp_ids)
{
pnp_ids->priv = GNOME_PNP_IDS_GET_PRIVATE (pnp_ids);
/* we don't keep malloc'd data in the hash; instead we read it
* out into priv->table_data and then link to it in the hash */
pnp_ids->priv->pnp_table = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
NULL);
}
static void
gnome_pnp_ids_finalize (GObject *object)
{
GnomePnpIds *pnp_ids = GNOME_PNP_IDS (object);
GnomePnpIdsPrivate *priv = pnp_ids->priv;
g_free (priv->table_data);
g_hash_table_unref (priv->pnp_table);
G_OBJECT_CLASS (gnome_pnp_ids_parent_class)->finalize (object);
}
/**
* gnome_pnp_ids_new:
*
* Returns a reference to a #GnomePnpIds object, or creates
* a new one if none have been created.
*
* Returns: (transfer full): a #GnomePnpIds object.
*/
GnomePnpIds *
gnome_pnp_ids_new (void)
{
if (gnome_pnp_ids_object != NULL) {
g_object_ref (gnome_pnp_ids_object);
} else {
gnome_pnp_ids_object = g_object_new (GNOME_TYPE_PNP_IDSS, NULL);
g_object_add_weak_pointer (gnome_pnp_ids_object, &gnome_pnp_ids_object);
}
return GNOME_PNP_IDS (gnome_pnp_ids_object);
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-installer.c 0000664 0001750 0001750 00000022731 14167325242 023133 0 ustar fabio fabio /*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "gnome-installer.h"
#define INSTALL_DBUS_PATH "org.freedesktop.PackageKit.Modify"
#define CHECK_DBUS_PATH "org.freedesktop.PackageKit.Query"
typedef enum
{
OP_TYPE_INSTALL,
OP_TYPE_CHECK
} OpType;
typedef struct
{
OpType type;
gchar **packages;
gchar *options;
GSimpleAsyncResult *result;
} ClientCtx;
typedef struct
{
GnomeInstallerClientCallback client_callback;
gpointer client_data;
} ClientCallbackData;
static ClientCtx *
ctx_new (OpType type,
const gchar **packages,
const gchar *options,
GSimpleAsyncResult *result)
{
ClientCtx *ctx = g_slice_new (ClientCtx);
ctx->type = type;
ctx->packages = g_strdupv ((gchar **) packages);
ctx->options = g_strdup (options);
ctx->result = g_object_ref (result);
return ctx;
}
static void
ctx_free (ClientCtx *ctx)
{
g_free (ctx->packages);
g_free (ctx->options);
g_object_unref (ctx->result);
g_slice_free (ClientCtx, ctx);
}
static void
ctx_complete (ClientCtx *ctx)
{
g_simple_async_result_complete (ctx->result);
ctx_free (ctx);
}
static void
ctx_failed (ClientCtx *ctx,
GError *error)
{
g_simple_async_result_take_error (ctx->result, error);
ctx_complete (ctx);
}
static void
install_package_names_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
ClientCtx *ctx = user_data;
GError *error = NULL;
GVariant *res;
res = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
if (res == NULL)
{
ctx_failed (ctx, error);
return;
}
ctx_complete (ctx);
g_variant_unref (res);
}
static void
check_for_packages_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
ClientCtx *ctx = g_task_get_task_data (G_TASK (result));
GError *error = NULL;
G_GNUC_UNUSED gboolean success = g_task_propagate_boolean (G_TASK (result), &error);
if (error != NULL) {
ctx_failed (ctx, error);
return;
}
ctx_complete (ctx);
}
static void
check_for_packages_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GDBusProxy *proxy = G_DBUS_PROXY (source_object);
ClientCtx *ctx = (ClientCtx *) task_data;
gboolean satisfied = TRUE;
gint i = 0;
GError *error = NULL;
for (i = 0; i < g_strv_length (ctx->packages); i++) {
GVariant *res = g_dbus_proxy_call_sync (proxy,
"IsInstalled",
g_variant_new ("(ss)", ctx->packages[i], ctx->options),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT, NULL, &error);
if (error != NULL) {
satisfied = FALSE;
break;
}
gboolean is_installed = FALSE;
g_variant_get (res, "(b)", &is_installed);
g_variant_unref (res);
if (!is_installed) {
satisfied = FALSE;
break;
}
}
if (error != NULL) {
g_task_return_error (task, error);
return;
}
if (!satisfied) {
g_task_return_error (task,
g_error_new (g_quark_from_static_string ("GnomeInstaller"),
1,
"%s", ctx->packages[i]));
return;
}
g_task_return_boolean (task, TRUE);
}
static void
check_for_packages (GDBusProxy *proxy, ClientCtx *ctx)
{
GTask *task;
task = g_task_new (proxy, NULL,
check_for_packages_cb,
NULL);
g_task_set_task_data (task, ctx, NULL);
g_task_run_in_thread (task, check_for_packages_thread);
g_object_unref (task);
}
static void
pkg_kit_proxy_new_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
ClientCtx *ctx = user_data;
GError *error = NULL;
GDBusProxy *proxy;
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if (proxy == NULL)
{
ctx_failed (ctx, error);
return;
}
if (ctx->type == OP_TYPE_INSTALL)
g_dbus_proxy_call (proxy, "InstallPackageNames",
g_variant_new ("(u^a&ss)", 0, ctx->packages, ctx->options),
G_DBUS_CALL_FLAGS_NONE, G_MAXINT, NULL, install_package_names_cb, ctx);
else
check_for_packages (proxy, ctx);
g_object_unref (proxy);
}
static void
gnome_installer_run_op_async (const gchar **packages,
const gchar *options,
OpType type,
GAsyncReadyCallback callback,
gpointer user_data)
{
ClientCtx *ctx;
GSimpleAsyncResult *result;
result = g_simple_async_result_new (NULL, callback, user_data,
gnome_installer_run_op_async);
ctx = ctx_new (type, packages, options != NULL ? options : "", result);
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE, NULL,
"org.freedesktop.PackageKit",
"/org/freedesktop/PackageKit",
type == OP_TYPE_INSTALL ? INSTALL_DBUS_PATH : CHECK_DBUS_PATH,
NULL, pkg_kit_proxy_new_cb, ctx);
g_object_unref (result);
}
static gboolean
gnome_installer_async_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
gnome_installer_run_op_async), FALSE);
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
error))
return FALSE;
return TRUE;
}
static void
install_operation_async_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
ClientCallbackData *data = (ClientCallbackData *) user_data;
GError *error = NULL;
if (!gnome_installer_async_finish (result, &error))
{
g_printerr ("Failed to install packages: %s\n", error->message);
g_error_free (error);
if (data->client_callback)
(* data->client_callback) (FALSE, data->client_data);
goto out;
}
if (data->client_callback)
(* data->client_callback) (TRUE, data->client_data);
out:
g_slice_free (ClientCallbackData, data);
}
static void
check_operation_async_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
ClientCallbackData *data = (ClientCallbackData *) user_data;
GError *error = NULL;
if (!gnome_installer_async_finish (result, &error))
{
g_printerr ("Package missing: %s\n", error->message);
g_error_free (error);
if (data->client_callback)
(* data->client_callback) (FALSE, data->client_data);
goto out;
}
if (data->client_callback)
(* data->client_callback) (TRUE, data->client_data);
out:
g_slice_free (ClientCallbackData, data);
}
/**************************************************************/
/* Public API */
/**************************************************************/
/**
* gnome_installer_install_packages:
* @packages: (array zero-terminated=1): a null-terminated array of package names
* @callback: (scope async): the callback to run for the result
* @user_data: (closure): extra data to be sent to the callback
*
* Uses packagekit to install the provided list of packages.
**/
void gnome_installer_install_packages (const gchar **packages,
GnomeInstallerClientCallback callback,
gpointer user_data)
{
ClientCallbackData *data = g_slice_new (ClientCallbackData);
data->client_callback = callback;
data->client_data = user_data;
gnome_installer_run_op_async (packages, NULL, OP_TYPE_INSTALL, install_operation_async_cb, data);
}
/**
* gnome_installer_check_for_packages:
* @packages: (array zero-terminated=1): a null-terminated array of package names
* @callback: (scope async): the callback to run for the result
* @user_data: (closure): extra data to be sent to the callback
*
* Uses packagekit to check if provided package names are installed.
**/
void gnome_installer_check_for_packages (const gchar **packages,
GnomeInstallerClientCallback callback,
gpointer user_data)
{
ClientCallbackData *data = g_slice_new (ClientCallbackData);
data->client_callback = callback;
data->client_data = user_data;
gnome_installer_run_op_async (packages, NULL, OP_TYPE_CHECK, check_operation_async_cb, data);
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/test-wall-clock.c 0000664 0001750 0001750 00000001255 14167325242 023036 0 ustar fabio fabio #define GNOME_DESKTOP_USE_UNSTABLE_API
#include
static void
clock_changed (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
const char *txt;
txt = gnome_wall_clock_get_clock (GNOME_WALL_CLOCK (object));
g_print ("%s\n", txt);
}
int main (int argc, char **argv)
{
GMainLoop *loop;
GnomeWallClock *clock;
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
loop = g_main_loop_new (NULL, FALSE);
clock = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL);
g_signal_connect (G_OBJECT (clock), "notify::clock",
G_CALLBACK (clock_changed), NULL);
g_main_loop_run (loop);
g_main_loop_unref (loop);
return 0;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-xkb-info.h 0000664 0001750 0001750 00000010277 14167325242 022662 0 ustar fabio fabio /*
* Copyright (C) 2012 Red Hat, Inc.
*
* Written by: Rui Matos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef __GNOME_XKB_INFO_H__
#define __GNOME_XKB_INFO_H__
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error This is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-xkb-info.h
#endif
#include
#include
#include
#include
G_BEGIN_DECLS
#define GNOME_TYPE_XKB_INFO (gnome_xkb_info_get_type ())
#define GNOME_XKB_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_XKB_INFO, GnomeXkbInfo))
#define GNOME_XKB_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_XKB_INFO, GnomeXkbInfoClass))
#define GNOME_IS_XKB_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_XKB_INFO))
#define GNOME_IS_XKB_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_XKB_INFO))
#define GNOME_XKB_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_XKB_INFO, GnomeXkbInfoClass))
typedef struct _GnomeXkbInfoPrivate GnomeXkbInfoPrivate;
typedef struct _GnomeXkbInfo GnomeXkbInfo;
typedef struct _GnomeXkbInfoClass GnomeXkbInfoClass;
struct _GnomeXkbInfo
{
GObject parent_object;
GnomeXkbInfoPrivate *priv;
};
struct _GnomeXkbInfoClass
{
GObjectClass parent_class;
};
GType gnome_xkb_info_get_type (void);
GnomeXkbInfo *gnome_xkb_info_new (void);
GList *gnome_xkb_info_get_all_layouts (GnomeXkbInfo *self);
gboolean gnome_xkb_info_get_layout_info (GnomeXkbInfo *self,
const gchar *id,
const gchar **display_name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant);
gboolean gnome_xkb_info_get_layout_info_for_language (GnomeXkbInfo *self,
const gchar *language,
const gchar **id,
const gchar **display_name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant);
GList *gnome_xkb_info_get_all_option_groups (GnomeXkbInfo *self);
GList *gnome_xkb_info_get_options_for_group (GnomeXkbInfo *self,
const gchar *group_id);
const gchar *gnome_xkb_info_description_for_option (GnomeXkbInfo *self,
const gchar *group_id,
const gchar *id);
void gnome_xkb_info_get_var_defs (gchar **rules,
XkbRF_VarDefsRec **var_defs);
void gnome_xkb_info_free_var_defs (XkbRF_VarDefsRec *var_defs);
G_END_DECLS
#endif /* __GNOME_XKB_INFO_H__ */
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-datetime-source.c 0000664 0001750 0001750 00000020503 14167325242 024223 0 ustar fabio fabio /* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
* gdatetime-source.c - copy&paste from https://bugzilla.gnome.org/show_bug.cgi?id=655129
*
* Copyright (C) 2011 Red Hat, Inc.
*
* This program 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.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Author: Colin Walters
*/
#include "config.h"
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-datetime-source.h"
#ifdef HAVE_TIMERFD
#include
#include
#include
#endif
typedef struct _GDateTimeSource GDateTimeSource;
struct _GDateTimeSource
{
GSource source;
gint64 real_expiration;
gint64 wakeup_expiration;
gboolean cancel_on_set : 1;
gboolean initially_expired : 1;
GPollFD pollfd;
};
static inline void
g_datetime_source_reschedule (GDateTimeSource *datetime_source,
gint64 from_monotonic)
{
datetime_source->wakeup_expiration = from_monotonic + G_TIME_SPAN_SECOND;
}
static gboolean
g_datetime_source_is_expired (GDateTimeSource *datetime_source)
{
gint64 real_now;
gint64 monotonic_now;
real_now = g_get_real_time ();
monotonic_now = g_source_get_time ((GSource*)datetime_source);
if (datetime_source->initially_expired)
return TRUE;
if (datetime_source->real_expiration <= real_now)
return TRUE;
/* We can't really detect without system support when things
* change; so just trigger every second (i.e. our wakeup
* expiration)
*/
if (datetime_source->cancel_on_set && monotonic_now >= datetime_source->wakeup_expiration)
return TRUE;
return FALSE;
}
/* In prepare, we're just checking the monotonic time against
* our projected wakeup.
*/
static gboolean
g_datetime_source_prepare (GSource *source,
gint *timeout)
{
GDateTimeSource *datetime_source = (GDateTimeSource*)source;
gint64 monotonic_now;
#ifdef HAVE_TIMERFD
if (datetime_source->pollfd.fd != -1) {
*timeout = -1;
return datetime_source->initially_expired; /* Should be TRUE at most one time, FALSE forever after */
}
#endif
monotonic_now = g_source_get_time (source);
if (monotonic_now < datetime_source->wakeup_expiration) {
/* Round up to ensure that we don't try again too early */
*timeout = (datetime_source->wakeup_expiration - monotonic_now + 999) / 1000;
return FALSE;
}
*timeout = 0;
return g_datetime_source_is_expired (datetime_source);
}
/* In check, we're looking at the wall clock.
*/
static gboolean
g_datetime_source_check (GSource *source)
{
GDateTimeSource *datetime_source = (GDateTimeSource*)source;
#ifdef HAVE_TIMERFD
if (datetime_source->pollfd.fd != -1)
return datetime_source->pollfd.revents != 0;
#endif
if (g_datetime_source_is_expired (datetime_source))
return TRUE;
g_datetime_source_reschedule (datetime_source, g_source_get_time (source));
return FALSE;
}
static gboolean
g_datetime_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GDateTimeSource *datetime_source = (GDateTimeSource*)source;
datetime_source->initially_expired = FALSE;
if (!callback) {
g_warning ("Timeout source dispatched without callback\n"
"You must call g_source_set_callback().");
return FALSE;
}
(callback) (user_data);
/* Always false as this source is documented to run once */
return FALSE;
}
static void
g_datetime_source_finalize (GSource *source)
{
#ifdef HAVE_TIMERFD
GDateTimeSource *datetime_source = (GDateTimeSource*)source;
if (datetime_source->pollfd.fd != -1)
close (datetime_source->pollfd.fd);
#endif
}
static GSourceFuncs g_datetime_source_funcs = {
g_datetime_source_prepare,
g_datetime_source_check,
g_datetime_source_dispatch,
g_datetime_source_finalize
};
#ifdef HAVE_TIMERFD
static gboolean
g_datetime_source_init_timerfd (GDateTimeSource *datetime_source,
gint64 expected_now_seconds,
gint64 unix_seconds)
{
struct itimerspec its;
int settime_flags;
datetime_source->pollfd.fd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC);
if (datetime_source->pollfd.fd == -1)
return FALSE;
memset (&its, 0, sizeof (its));
its.it_value.tv_sec = (time_t) unix_seconds;
/* http://article.gmane.org/gmane.linux.kernel/1132138 */
#ifndef TFD_TIMER_CANCEL_ON_SET
#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
#endif
settime_flags = TFD_TIMER_ABSTIME;
if (datetime_source->cancel_on_set)
settime_flags |= TFD_TIMER_CANCEL_ON_SET;
if (timerfd_settime (datetime_source->pollfd.fd, settime_flags, &its, NULL) < 0) {
close (datetime_source->pollfd.fd);
datetime_source->pollfd.fd = -1;
return FALSE;
}
/* Now we need to check that the clock didn't go backwards before we
* had the timerfd set up. See
* https://bugzilla.gnome.org/show_bug.cgi?id=655129
*/
clock_gettime (CLOCK_REALTIME, &its.it_value);
if (its.it_value.tv_sec < expected_now_seconds)
datetime_source->initially_expired = TRUE;
datetime_source->pollfd.events = G_IO_IN;
g_source_add_poll ((GSource*) datetime_source, &datetime_source->pollfd);
return TRUE;
}
#endif
/**
* _gnome_date_time_source_new:
* @now: The expected current time
* @expiry: Time to await
* @cancel_on_set: Also invoke callback if the system clock changes discontiguously
*
* This function is designed for programs that want to schedule an
* event based on real (wall clock) time, as returned by
* g_get_real_time(). For example, HOUR:MINUTE wall-clock displays
* and calendaring software. The callback will be invoked when the
* specified wall clock time @expiry is reached. This includes
* events such as the system clock being set past the given time.
*
* Compare versus g_timeout_source_new() which is defined to use
* monotonic time as returned by g_get_monotonic_time().
*
* The parameter @now is necessary to avoid a race condition in
* between getting the current time and calling this function.
*
* If @cancel_on_set is given, the callback will also be invoked at
* most a second after the system clock is changed. This includes
* being set backwards or forwards, and system
* resume from suspend. Not all operating systems allow detecting all
* relevant events efficiently - this function may cause the process
* to wake up once a second in those cases.
*
* A wall clock display should use @cancel_on_set; a calendaring
* program shouldn't need to.
*
* Note that the return value from the associated callback will be
* ignored; this is a one time watch.
*
* This function currently does not detect time zone
* changes. On Linux, your program should also monitor the
* /etc/timezone file using
* #GFileMonitor.
*
* Clock exampleFIXME: MISSING XINCLUDE CONTENT
*
* Return value: A newly-constructed #GSource
*
* Since: 2.30
**/
GSource *
_gnome_datetime_source_new (GDateTime *now,
GDateTime *expiry,
gboolean cancel_on_set)
{
GDateTimeSource *datetime_source;
gint64 unix_seconds;
unix_seconds = g_date_time_to_unix (expiry);
datetime_source = (GDateTimeSource*) g_source_new (&g_datetime_source_funcs, sizeof (GDateTimeSource));
datetime_source->cancel_on_set = cancel_on_set;
#ifdef HAVE_TIMERFD
{
gint64 expected_now_seconds = g_date_time_to_unix (now);
if (g_datetime_source_init_timerfd (datetime_source, expected_now_seconds, unix_seconds))
return (GSource*)datetime_source;
/* Fall through to non-timerfd code */
}
#endif
datetime_source->real_expiration = unix_seconds * 1000000;
g_datetime_source_reschedule (datetime_source, g_get_monotonic_time ());
return (GSource*)datetime_source;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-installer.h 0000664 0001750 0001750 00000002672 14167325242 023142 0 ustar fabio fabio /*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __GNOME_INSTALLER__
#define __GNOME_INSTALLER__
#include
#include
typedef void (* GnomeInstallerClientCallback) (gboolean success,
gpointer user_data);
void gnome_installer_install_packages (const gchar **packages,
GnomeInstallerClientCallback callback,
gpointer user_data);
void gnome_installer_check_for_packages (const gchar **packages,
GnomeInstallerClientCallback callback,
gpointer user_data);
#endif cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-desktop-utils.c 0000664 0001750 0001750 00000014645 14167325242 023752 0 ustar fabio fabio /* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gnome-desktop-utils.c - Utilities for the GNOME Desktop
Copyright (C) 1998 Tom Tromey
All rights reserved.
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. */
/*
@NOTATION@
*/
#include
#include
#include
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-desktop-utils.h"
#include "cdesktop-enums.h"
#include "private.h"
/**
* gnome_desktop_prepend_terminal_to_vector:
* @argc: a pointer to the vector size
* @argv: a pointer to the vector
*
* Prepends a terminal (either the one configured as default in
* the user's GNOME setup, or one of the common xterm emulators) to the passed
* in vector, modifying it in the process. The vector should be allocated with
* #g_malloc, as this will #g_free the original vector. Also all elements must
* have been allocated separately. That is the standard glib/GNOME way of
* doing vectors however. If the integer that @argc points to is negative, the
* size will first be computed. Also note that passing in pointers to a vector
* that is empty, will just create a new vector for you.
**/
void
gnome_desktop_prepend_terminal_to_vector (int *argc, char ***argv)
{
#ifndef G_OS_WIN32
char **real_argv;
int real_argc;
int i, j;
char **term_argv = NULL;
int term_argc = 0;
GSettings *settings;
gchar *terminal = NULL;
char **the_argv;
g_return_if_fail (argc != NULL);
g_return_if_fail (argv != NULL);
_gnome_desktop_init_i18n ();
/* sanity */
if(*argv == NULL)
*argc = 0;
the_argv = *argv;
/* compute size if not given */
if (*argc < 0) {
for (i = 0; the_argv[i] != NULL; i++)
;
*argc = i;
}
settings = g_settings_new ("org.cinnamon.desktop.default-applications.terminal");
terminal = g_settings_get_string (settings, "exec");
if (terminal) {
gchar *command_line;
gchar *exec_flag;
exec_flag = g_settings_get_string (settings, "exec-arg");
if (exec_flag == NULL)
command_line = g_strdup (terminal);
else
command_line = g_strdup_printf ("%s %s", terminal,
exec_flag);
g_shell_parse_argv (command_line,
&term_argc,
&term_argv,
NULL /* error */);
g_free (command_line);
g_free (exec_flag);
g_free (terminal);
}
g_object_unref (settings);
if (term_argv == NULL) {
char *check;
term_argc = 2;
term_argv = g_new0 (char *, 3);
check = g_find_program_in_path ("gnome-terminal");
if (check != NULL) {
term_argv[0] = check;
/* Note that gnome-terminal takes -x and
* as -e in gnome-terminal is broken we use that. */
term_argv[1] = g_strdup ("-x");
} else {
if (check == NULL)
check = g_find_program_in_path ("nxterm");
if (check == NULL)
check = g_find_program_in_path ("color-xterm");
if (check == NULL)
check = g_find_program_in_path ("rxvt");
if (check == NULL)
check = g_find_program_in_path ("xterm");
if (check == NULL)
check = g_find_program_in_path ("dtterm");
if (check == NULL) {
g_warning (_("Cannot find a terminal, using "
"xterm, even if it may not work"));
check = g_strdup ("xterm");
}
term_argv[0] = check;
term_argv[1] = g_strdup ("-e");
}
}
real_argc = term_argc + *argc;
real_argv = g_new (char *, real_argc + 1);
for (i = 0; i < term_argc; i++)
real_argv[i] = term_argv[i];
for (j = 0; j < *argc; j++, i++)
real_argv[i] = (char *)the_argv[j];
real_argv[i] = NULL;
g_free (*argv);
*argv = real_argv;
*argc = real_argc;
/* we use g_free here as we sucked all the inner strings
* out from it into real_argv */
g_free (term_argv);
#else
/* FIXME: Implement when needed */
g_warning ("gnome_prepend_terminal_to_vector: Not implemented");
#endif
}
void
_gnome_desktop_init_i18n (void) {
static gboolean initialized = FALSE;
if (!initialized) {
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
initialized = TRUE;
}
}
/**
* gnome_desktop_get_media_key_string:
* @type: The CDesktopMediaKeyType
*
* Returns the GSettings key string of the
* given media key type.
*
* Returns: (transfer none): the string corresponding to the
* provided media key type or %NULL
**/
const gchar *
gnome_desktop_get_media_key_string (gint type)
{
g_return_val_if_fail (type >= 0 && type < G_N_ELEMENTS (media_keys), NULL);
return media_keys[type];
}
/**
* gnome_desktop_get_session_user_pwent: (skip)
*
* Makes a best effort to retrieve the currently logged-in user's passwd
* struct (containing uid, gid, home, etc...) based on the process uid
* and various environment variables.
*
* Returns: (transfer none): the passwd struct corresponding to the
* session user (or, as a last resort, the user returned by getuid())
**/
struct passwd *
gnome_desktop_get_session_user_pwent (void)
{
struct passwd *pwent = NULL;
if (getuid () != geteuid ()) {
gint uid = getuid ();
pwent = getpwuid (uid);
} else if (g_getenv ("SUDO_UID") != NULL) {
gint uid = (int) g_ascii_strtoll (g_getenv ("SUDO_UID"), NULL, 10);
pwent = getpwuid (uid);
} else if (g_getenv ("PKEXEC_UID") != NULL) {
gint uid = (int) g_ascii_strtoll (g_getenv ("PKEXEC_UID"), NULL, 10);
pwent = getpwuid (uid);
} else if (g_getenv ("USERNAME") != NULL) {
pwent = getpwnam (g_getenv ("USERNAME"));
} else if (g_getenv ("USER") != NULL) {
pwent = getpwnam (g_getenv ("USER"));
}
if (!pwent) {
return getpwuid (getuid ());
}
return pwent;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr-labeler.c 0000664 0001750 0001750 00000041216 14167325242 023164 0 ustar fabio fabio /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* gnome-rr-labeler.c - Utility to label monitors to identify them
* while they are being configured.
*
* Copyright 2008, Novell, 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: Federico Mena-Quintero
*/
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include
#include
#include
#include
#include
#include
#include
#include
#include "gnome-rr-labeler.h"
struct _GnomeRRLabelerPrivate {
GnomeRRConfig *config;
int num_outputs;
GdkRGBA *palette;
GtkWidget **windows;
GdkScreen *screen;
Atom workarea_atom;
};
enum {
PROP_0,
PROP_CONFIG,
PROP_LAST
};
G_DEFINE_TYPE (GnomeRRLabeler, gnome_rr_labeler, G_TYPE_OBJECT);
static void gnome_rr_labeler_finalize (GObject *object);
static void setup_from_config (GnomeRRLabeler *labeler);
static GdkFilterReturn
screen_xevent_filter (GdkXEvent *xevent,
GdkEvent *event,
GnomeRRLabeler *labeler)
{
XEvent *xev;
xev = (XEvent *) xevent;
if (xev->type == PropertyNotify &&
xev->xproperty.atom == labeler->priv->workarea_atom) {
/* update label positions */
if (labeler->priv->windows != NULL) {
gnome_rr_labeler_hide (labeler);
gnome_rr_labeler_show (labeler);
}
}
return GDK_FILTER_CONTINUE;
}
static void
gnome_rr_labeler_init (GnomeRRLabeler *labeler)
{
GdkWindow *gdkwindow;
labeler->priv = G_TYPE_INSTANCE_GET_PRIVATE (labeler, GNOME_TYPE_RR_LABELER, GnomeRRLabelerPrivate);
labeler->priv->workarea_atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
"_NET_WORKAREA",
True);
labeler->priv->screen = gdk_screen_get_default ();
/* code is not really designed to handle multiple screens so *shrug* */
gdkwindow = gdk_screen_get_root_window (labeler->priv->screen);
gdk_window_add_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler);
gdk_window_set_events (gdkwindow, gdk_window_get_events (gdkwindow) | GDK_PROPERTY_CHANGE_MASK);
}
static void
gnome_rr_labeler_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *param_spec)
{
GnomeRRLabeler *self = GNOME_RR_LABELER (gobject);
switch (property_id) {
case PROP_CONFIG:
self->priv->config = GNOME_RR_CONFIG (g_value_dup_object (value));
return;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, param_spec);
}
}
static GObject *
gnome_rr_labeler_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties)
{
GnomeRRLabeler *self = (GnomeRRLabeler*) G_OBJECT_CLASS (gnome_rr_labeler_parent_class)->constructor (type, n_construct_properties, construct_properties);
setup_from_config (self);
return (GObject*) self;
}
static void
gnome_rr_labeler_class_init (GnomeRRLabelerClass *klass)
{
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (GnomeRRLabelerPrivate));
object_class = (GObjectClass *) klass;
object_class->set_property = gnome_rr_labeler_set_property;
object_class->finalize = gnome_rr_labeler_finalize;
object_class->constructor = gnome_rr_labeler_constructor;
g_object_class_install_property (object_class, PROP_CONFIG, g_param_spec_object ("config",
"Configuration",
"RandR configuration to label",
GNOME_TYPE_RR_CONFIG,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
}
static void
gnome_rr_labeler_finalize (GObject *object)
{
GnomeRRLabeler *labeler;
GdkWindow *gdkwindow;
labeler = GNOME_RR_LABELER (object);
gdkwindow = gdk_screen_get_root_window (labeler->priv->screen);
gdk_window_remove_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler);
if (labeler->priv->config != NULL) {
g_object_unref (labeler->priv->config);
}
if (labeler->priv->windows != NULL) {
gnome_rr_labeler_hide (labeler);
g_free (labeler->priv->windows);
}
g_free (labeler->priv->palette);
G_OBJECT_CLASS (gnome_rr_labeler_parent_class)->finalize (object);
}
static int
count_outputs (GnomeRRConfig *config)
{
int i;
GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config);
for (i = 0; outputs[i] != NULL; i++)
;
return i;
}
static void
make_palette (GnomeRRLabeler *labeler)
{
/* The idea is that we go around an hue color wheel. We want to start
* at red, go around to green/etc. and stop at blue --- because magenta
* is evil. Eeeeek, no magenta, please!
*
* Purple would be nice, though. Remember that we are watered down
* (i.e. low saturation), so that would be like Like berries with cream.
* Mmmmm, berries.
*/
double start_hue;
double end_hue;
int i;
g_assert (labeler->priv->num_outputs > 0);
labeler->priv->palette = g_new (GdkRGBA, labeler->priv->num_outputs);
start_hue = 0.0; /* red */
end_hue = 2.0/3; /* blue */
for (i = 0; i < labeler->priv->num_outputs; i++) {
double h, s, v;
double r, g, b;
h = start_hue + (end_hue - start_hue) / labeler->priv->num_outputs * i;
s = 1.0 / 3;
v = 1.0;
gtk_hsv_to_rgb (h, s, v, &r, &g, &b);
labeler->priv->palette[i].red = r;
labeler->priv->palette[i].green = g;
labeler->priv->palette[i].blue = b;
labeler->priv->palette[i].alpha = 1.0;
}
}
static void
rounded_rectangle (cairo_t *cr,
gint x,
gint y,
gint width,
gint height,
gint x_radius,
gint y_radius)
{
gint x1, x2;
gint y1, y2;
gint xr1, xr2;
gint yr1, yr2;
x1 = x;
x2 = x1 + width;
y1 = y;
y2 = y1 + height;
x_radius = MIN (x_radius, width / 2.0);
y_radius = MIN (y_radius, width / 2.0);
xr1 = x_radius;
xr2 = x_radius / 2.0;
yr1 = y_radius;
yr2 = y_radius / 2.0;
cairo_move_to (cr, x1 + xr1, y1);
cairo_line_to (cr, x2 - xr1, y1);
cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
cairo_line_to (cr, x2, y2 - yr1);
cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
cairo_line_to (cr, x1 + xr1, y2);
cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
cairo_line_to (cr, x1, y1 + yr1);
cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
cairo_close_path (cr);
}
#define LABEL_WINDOW_EDGE_THICKNESS 2
#define LABEL_WINDOW_PADDING 12
/* Look for panel-corner in:
* http://git.gnome.org/browse/gnome-shell/tree/data/theme/gnome-shell.css
* to match the corner radius */
#define LABEL_CORNER_RADIUS 6 + LABEL_WINDOW_EDGE_THICKNESS
static void
label_draw_background_and_frame (GtkWidget *widget, cairo_t *cr, gboolean for_shape)
{
GdkRGBA shape_color = { 0, 0, 0, 1 };
GdkRGBA *rgba;
GtkAllocation allocation;
rgba = g_object_get_data (G_OBJECT (widget), "rgba");
gtk_widget_get_allocation (widget, &allocation);
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
/* edge outline */
if (for_shape)
gdk_cairo_set_source_rgba (cr, &shape_color);
else
cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
rounded_rectangle (cr,
LABEL_WINDOW_EDGE_THICKNESS / 2.0,
LABEL_WINDOW_EDGE_THICKNESS / 2.0,
allocation.width - LABEL_WINDOW_EDGE_THICKNESS,
allocation.height - LABEL_WINDOW_EDGE_THICKNESS,
LABEL_CORNER_RADIUS, LABEL_CORNER_RADIUS);
cairo_set_line_width (cr, LABEL_WINDOW_EDGE_THICKNESS);
cairo_stroke (cr);
/* fill */
if (for_shape) {
gdk_cairo_set_source_rgba (cr, &shape_color);
} else {
rgba->alpha = 0.75;
gdk_cairo_set_source_rgba (cr, rgba);
}
rounded_rectangle (cr,
LABEL_WINDOW_EDGE_THICKNESS,
LABEL_WINDOW_EDGE_THICKNESS,
allocation.width - LABEL_WINDOW_EDGE_THICKNESS * 2,
allocation.height - LABEL_WINDOW_EDGE_THICKNESS * 2,
LABEL_CORNER_RADIUS - LABEL_WINDOW_EDGE_THICKNESS / 2.0,
LABEL_CORNER_RADIUS - LABEL_WINDOW_EDGE_THICKNESS / 2.0);
cairo_fill (cr);
cairo_restore (cr);
}
static void
maybe_update_shape (GtkWidget *widget)
{
cairo_t *cr;
cairo_surface_t *surface;
cairo_region_t *region;
/* fallback to XShape only for non-composited clients */
if (gtk_widget_is_composited (widget)) {
gtk_widget_shape_combine_region (widget, NULL);
return;
}
surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
CAIRO_CONTENT_COLOR_ALPHA,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
cr = cairo_create (surface);
label_draw_background_and_frame (widget, cr, TRUE);
cairo_destroy (cr);
region = gdk_cairo_region_create_from_surface (surface);
gtk_widget_shape_combine_region (widget, region);
cairo_surface_destroy (surface);
cairo_region_destroy (region);
}
static gboolean
label_window_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
{
if (gtk_widget_is_composited (widget)) {
/* clear any content */
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_paint (cr);
cairo_restore (cr);
}
maybe_update_shape (widget);
label_draw_background_and_frame (widget, cr, FALSE);
return FALSE;
}
static void
position_window (GnomeRRLabeler *labeler,
GtkWidget *window,
int x,
int y)
{
GdkRectangle workarea;
GdkRectangle monitor;
int monitor_num;
monitor_num = gdk_screen_get_monitor_at_point (labeler->priv->screen, x, y);
gdk_screen_get_monitor_workarea (labeler->priv->screen, monitor_num, &workarea);
gdk_screen_get_monitor_geometry (labeler->priv->screen,
monitor_num,
&monitor);
gdk_rectangle_intersect (&monitor, &workarea, &workarea);
gtk_window_move (GTK_WINDOW (window), workarea.x, workarea.y);
}
static void
label_window_realize_cb (GtkWidget *widget)
{
cairo_region_t *region;
/* make the whole window ignore events */
region = cairo_region_create ();
gtk_widget_input_shape_combine_region (widget, region);
cairo_region_destroy (region);
maybe_update_shape (widget);
}
static void
label_window_composited_changed_cb (GtkWidget *widget, GnomeRRLabeler *labeler)
{
if (gtk_widget_get_realized (widget))
maybe_update_shape (widget);
}
static GtkWidget *
create_label_window (GnomeRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba)
{
GtkWidget *window;
GtkWidget *widget;
char *str;
const char *display_name;
GdkRGBA black = { 0, 0, 0, 1.0 };
int x, y;
GdkScreen *screen;
GdkVisual *visual;
window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_widget_set_app_paintable (window, TRUE);
screen = gtk_widget_get_screen (window);
visual = gdk_screen_get_rgba_visual (screen);
if (visual != NULL)
gtk_widget_set_visual (window, visual);
gtk_container_set_border_width (GTK_CONTAINER (window), LABEL_WINDOW_PADDING + LABEL_WINDOW_EDGE_THICKNESS);
/* This is semi-dangerous. The color is part of the labeler->palette
* array. Note that in gnome_rr_labeler_finalize(), we are careful to
* free the palette only after we free the windows.
*/
g_object_set_data (G_OBJECT (window), "rgba", rgba);
g_signal_connect (window, "draw",
G_CALLBACK (label_window_draw_event_cb), labeler);
g_signal_connect (window, "realize",
G_CALLBACK (label_window_realize_cb), labeler);
g_signal_connect (window, "composited-changed",
G_CALLBACK (label_window_composited_changed_cb), labeler);
if (gnome_rr_config_get_clone (labeler->priv->config)) {
/* Keep this string in sync with gnome-control-center/capplets/display/xrandr-capplet.c:get_display_name() */
/* Translators: this is the feature where what you see on your
* laptop's screen is the same as your external projector.
* Here, "Mirrored" is being used as an adjective. For example,
* the Spanish translation could be "Pantallas en Espejo".
*/
display_name = _("Mirrored Displays");
} else
display_name = gnome_rr_output_info_get_display_name (output);
str = g_strdup_printf ("%s", display_name);
widget = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (widget), str);
g_free (str);
/* Make the label explicitly black. We don't want it to follow the
* theme's colors, since the label is always shown against a light
* pastel background. See bgo#556050
*/
gtk_widget_override_color (widget,
gtk_widget_get_state_flags (widget),
&black);
gtk_container_add (GTK_CONTAINER (window), widget);
/* Should we center this at the top edge of the monitor, instead of using the upper-left corner? */
gnome_rr_output_info_get_geometry (output, &x, &y, NULL, NULL);
position_window (labeler, window, x, y);
gtk_widget_show_all (window);
return window;
}
static void
setup_from_config (GnomeRRLabeler *labeler)
{
labeler->priv->num_outputs = count_outputs (labeler->priv->config);
make_palette (labeler);
gnome_rr_labeler_show (labeler);
}
/**
* gnome_rr_labeler_new:
* @config: Configuration of the screens to label
*
* Create a GUI element that will display colored labels on each connected monitor.
* This is useful when users are required to identify which monitor is which, e.g. for
* for configuring multiple monitors.
* The labels will be shown by default, use gnome_rr_labeler_hide to hide them.
*
* Returns: A new #GnomeRRLabeler
*/
GnomeRRLabeler *
gnome_rr_labeler_new (GnomeRRConfig *config)
{
g_return_val_if_fail (GNOME_IS_RR_CONFIG (config), NULL);
return g_object_new (GNOME_TYPE_RR_LABELER, "config", config, NULL);
}
/**
* gnome_rr_labeler_show:
* @labeler: A #GnomeRRLabeler
*
* Show the labels.
*/
void
gnome_rr_labeler_show (GnomeRRLabeler *labeler)
{
int i;
gboolean created_window_for_clone;
GnomeRROutputInfo **outputs;
g_return_if_fail (GNOME_IS_RR_LABELER (labeler));
if (labeler->priv->windows != NULL)
return;
labeler->priv->windows = g_new (GtkWidget *, labeler->priv->num_outputs);
created_window_for_clone = FALSE;
outputs = gnome_rr_config_get_outputs (labeler->priv->config);
for (i = 0; i < labeler->priv->num_outputs; i++) {
if (!created_window_for_clone && gnome_rr_output_info_is_active (outputs[i])) {
labeler->priv->windows[i] = create_label_window (labeler, outputs[i], labeler->priv->palette + i);
if (gnome_rr_config_get_clone (labeler->priv->config))
created_window_for_clone = TRUE;
} else
labeler->priv->windows[i] = NULL;
}
}
/**
* gnome_rr_labeler_hide:
* @labeler: A #GnomeRRLabeler
*
* Hide ouput labels.
*/
void
gnome_rr_labeler_hide (GnomeRRLabeler *labeler)
{
int i;
GnomeRRLabelerPrivate *priv;
g_return_if_fail (GNOME_IS_RR_LABELER (labeler));
priv = labeler->priv;
if (priv->windows == NULL)
return;
for (i = 0; i < priv->num_outputs; i++)
if (priv->windows[i] != NULL) {
gtk_widget_destroy (priv->windows[i]);
priv->windows[i] = NULL;
}
g_free (priv->windows);
priv->windows = NULL;
}
/**
* gnome_rr_labeler_get_rgba_for_output:
* @labeler: A #GnomeRRLabeler
* @output: Output device (i.e. monitor) to query
* @rgba_out: (out): Color of selected monitor.
*
* Get the color used for the label on a given output (monitor).
*/
void
gnome_rr_labeler_get_rgba_for_output (GnomeRRLabeler *labeler, GnomeRROutputInfo *output, GdkRGBA *rgba_out)
{
int i;
GnomeRROutputInfo **outputs;
g_return_if_fail (GNOME_IS_RR_LABELER (labeler));
g_return_if_fail (GNOME_IS_RR_OUTPUT_INFO (output));
g_return_if_fail (rgba_out != NULL);
outputs = gnome_rr_config_get_outputs (labeler->priv->config);
for (i = 0; i < labeler->priv->num_outputs; i++)
if (outputs[i] == output) {
*rgba_out = labeler->priv->palette[i];
return;
}
g_warning ("trying to get the color for unknown GnomeOutputInfo %p; returning magenta!", output);
rgba_out->red = 1.0;
rgba_out->green = 0;
rgba_out->blue = 1.0;
rgba_out->alpha = 1.0;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-thumbnail-pixbuf-utils.c 0000664 0001750 0001750 00000010345 14167325242 025550 0 ustar fabio fabio /*
* gnome-thumbnail-pixbuf-utils.c: Utilities for handling pixbufs when thumbnailing
*
* Copyright (C) 2002 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: Alexander Larsson
*/
#include
#include
#include
#include
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-desktop-thumbnail.h"
#define LOAD_BUFFER_SIZE 65536
/**
* gnome_desktop_thumbnail_scale_down_pixbuf:
* @pixbuf: a #GdkPixbuf
* @dest_width: the desired new width
* @dest_height: the desired new height
*
* Scales the pixbuf to the desired size. This function
* is a lot faster than gdk-pixbuf when scaling down by
* large amounts.
*
* Return value: (transfer full): a scaled pixbuf
*
* Since: 2.2
**/
GdkPixbuf *
gnome_desktop_thumbnail_scale_down_pixbuf (GdkPixbuf *pixbuf,
int dest_width,
int dest_height)
{
int source_width, source_height;
int s_x1, s_y1, s_x2, s_y2;
int s_xfrac, s_yfrac;
int dx, dx_frac, dy, dy_frac;
div_t ddx, ddy;
int x, y;
int r, g, b, a;
int n_pixels;
gboolean has_alpha;
guchar *dest, *src, *xsrc, *src_pixels;
GdkPixbuf *dest_pixbuf;
int pixel_stride;
int source_rowstride, dest_rowstride;
if (dest_width == 0 || dest_height == 0) {
return NULL;
}
source_width = gdk_pixbuf_get_width (pixbuf);
source_height = gdk_pixbuf_get_height (pixbuf);
g_assert (source_width >= dest_width);
g_assert (source_height >= dest_height);
ddx = div (source_width, dest_width);
dx = ddx.quot;
dx_frac = ddx.rem;
ddy = div (source_height, dest_height);
dy = ddy.quot;
dy_frac = ddy.rem;
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
source_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
src_pixels = gdk_pixbuf_get_pixels (pixbuf);
dest_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8,
dest_width, dest_height);
dest = gdk_pixbuf_get_pixels (dest_pixbuf);
dest_rowstride = gdk_pixbuf_get_rowstride (dest_pixbuf);
pixel_stride = (has_alpha)?4:3;
s_y1 = 0;
s_yfrac = -dest_height/2;
while (s_y1 < source_height) {
s_y2 = s_y1 + dy;
s_yfrac += dy_frac;
if (s_yfrac > 0) {
s_y2++;
s_yfrac -= dest_height;
}
s_x1 = 0;
s_xfrac = -dest_width/2;
while (s_x1 < source_width) {
s_x2 = s_x1 + dx;
s_xfrac += dx_frac;
if (s_xfrac > 0) {
s_x2++;
s_xfrac -= dest_width;
}
/* Average block of [x1,x2[ x [y1,y2[ and store in dest */
r = g = b = a = 0;
n_pixels = 0;
src = src_pixels + s_y1 * source_rowstride + s_x1 * pixel_stride;
for (y = s_y1; y < s_y2; y++) {
xsrc = src;
if (has_alpha) {
for (x = 0; x < s_x2-s_x1; x++) {
n_pixels++;
r += xsrc[3] * xsrc[0];
g += xsrc[3] * xsrc[1];
b += xsrc[3] * xsrc[2];
a += xsrc[3];
xsrc += 4;
}
} else {
for (x = 0; x < s_x2-s_x1; x++) {
n_pixels++;
r += *xsrc++;
g += *xsrc++;
b += *xsrc++;
}
}
src += source_rowstride;
}
if (n_pixels != 0) /* avoid any possible divide by zero */
{
if (has_alpha) {
if (a != 0) {
*dest++ = r / a;
*dest++ = g / a;
*dest++ = b / a;
*dest++ = a / n_pixels;
} else {
*dest++ = 0;
*dest++ = 0;
*dest++ = 0;
*dest++ = 0;
}
} else {
*dest++ = r / n_pixels;
*dest++ = g / n_pixels;
*dest++ = b / n_pixels;
}
}
s_x1 = s_x2;
}
s_y1 = s_y2;
dest += dest_rowstride - dest_width * pixel_stride;
}
return dest_pixbuf;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-desktop-thumbnail.h 0000664 0001750 0001750 00000011660 14167325242 024574 0 ustar fabio fabio /*
* gnome-thumbnail.h: Utilities for handling thumbnails
*
* Copyright (C) 2002 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: Alexander Larsson
*/
#ifndef GNOME_DESKTOP_THUMBNAIL_H
#define GNOME_DESKTOP_THUMBNAIL_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error GnomeDesktopThumbnail is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-desktop-thumbnail.h
#endif
#include
#include
#include
#include
G_BEGIN_DECLS
typedef enum {
GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL,
GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE
} GnomeDesktopThumbnailSize;
#define GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY (gnome_desktop_thumbnail_factory_get_type ())
#define GNOME_DESKTOP_THUMBNAIL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactory))
#define GNOME_DESKTOP_THUMBNAIL_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactoryClass))
#define GNOME_DESKTOP_IS_THUMBNAIL_FACTORY(obj) (G_TYPE_INSTANCE_CHECK_TYPE ((obj), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY))
#define GNOME_DESKTOP_IS_THUMBNAIL_FACTORY_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY))
typedef struct _GnomeDesktopThumbnailFactory GnomeDesktopThumbnailFactory;
typedef struct _GnomeDesktopThumbnailFactoryClass GnomeDesktopThumbnailFactoryClass;
typedef struct _GnomeDesktopThumbnailFactoryPrivate GnomeDesktopThumbnailFactoryPrivate;
struct _GnomeDesktopThumbnailFactory {
GObject parent;
GnomeDesktopThumbnailFactoryPrivate *priv;
};
struct _GnomeDesktopThumbnailFactoryClass {
GObjectClass parent;
};
GType gnome_desktop_thumbnail_factory_get_type (void);
GnomeDesktopThumbnailFactory *gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size);
char * gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory,
const char *uri,
time_t mtime);
gboolean gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
time_t mtime);
gboolean gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
const char *mime_type,
time_t mtime);
GdkPixbuf * gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
const char *mime_type);
void gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory,
GdkPixbuf *thumbnail,
const char *uri,
time_t original_mtime);
void gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFactory *factory,
const char *uri,
time_t mtime);
/* Thumbnailing utils: */
gboolean gnome_desktop_thumbnail_has_uri (GdkPixbuf *pixbuf,
const char *uri);
gboolean gnome_desktop_thumbnail_is_valid (GdkPixbuf *pixbuf,
const char *uri,
time_t mtime);
char * gnome_desktop_thumbnail_md5 (const char *uri);
char * gnome_desktop_thumbnail_path_for_uri (const char *uri,
GnomeDesktopThumbnailSize size);
/* Pixbuf utils */
GdkPixbuf *gnome_desktop_thumbnail_scale_down_pixbuf (GdkPixbuf *pixbuf,
int dest_width,
int dest_height);
/* Thumbnail folder checking and fixing utils */
void gnome_desktop_thumbnail_cache_fix_permissions (void);
gboolean gnome_desktop_thumbnail_cache_check_permissions (GnomeDesktopThumbnailFactory *factory, gboolean quick);
G_END_DECLS
#endif /* GNOME_DESKTOP_THUMBNAIL_H */
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-desktop-utils.h 0000664 0001750 0001750 00000003251 14167325242 023746 0 ustar fabio fabio /* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gnome-ditem.h - Utilities for the GNOME Desktop
Copyright (C) 1998 Tom Tromey
All rights reserved.
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. */
/*
@NOTATION@
*/
#ifndef GNOME_DESKTOP_UTILS_H
#define GNOME_DESKTOP_UTILS_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error gnome-desktop-utils is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-desktop-utils.h
#endif
#include
#include
#include
#include
#include
G_BEGIN_DECLS
/* prepend the terminal command to a vector */
void gnome_desktop_prepend_terminal_to_vector (int *argc, char ***argv);
const char *gnome_desktop_get_media_key_string (gint type);
struct passwd *gnome_desktop_get_session_user_pwent (void);
G_END_DECLS
#endif /* GNOME_DITEM_H */
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr.c 0000664 0001750 0001750 00000234646 14167325242 021573 0 ustar fabio fabio /* gnome-rr.c
*
* 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
*/
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#undef GNOME_DISABLE_DEPRECATED
#include "gnome-rr.h"
#include "gnome-rr-config.h"
#include "private.h"
#include "edid.h"
#include "gnome-rr-private.h"
#define DISPLAY(o) ((o)->info->screen->priv->xdisplay)
#define SERVERS_RANDR_IS_AT_LEAST_1_3(priv) (priv->rr_major_version > 1 || (priv->rr_major_version == 1 && priv->rr_minor_version >= 3))
#define INTERFACE_SETTINGS "org.cinnamon.desktop.interface"
#define GLOBAL_SCALE_FACTOR_KEY "scaling-factor"
#define USE_UPSCALING_KEY "upscale-fractional-scaling"
enum {
SCREEN_PROP_0,
SCREEN_PROP_GDK_SCREEN,
SCREEN_PROP_LAST,
};
enum {
SCREEN_CHANGED,
SCREEN_OUTPUT_CONNECTED,
SCREEN_OUTPUT_DISCONNECTED,
SCREEN_SIGNAL_LAST,
};
static guint screen_signals[SCREEN_SIGNAL_LAST] = { 0 };
struct GnomeRROutput
{
ScreenInfo * info;
RROutput id;
char * name;
GnomeRRCrtc * current_crtc;
gboolean connected;
gulong width_mm;
gulong height_mm;
GnomeRRCrtc ** possible_crtcs;
GnomeRROutput ** clones;
GnomeRRMode ** modes;
int n_preferred;
guint8 * edid_data;
gsize edid_size;
char * connector_type;
gint backlight_min;
gint backlight_max;
};
struct GnomeRROutputWrap
{
RROutput id;
};
struct GnomeRRCrtc
{
ScreenInfo * info;
RRCrtc id;
GnomeRRMode * current_mode;
GnomeRROutput ** current_outputs;
GnomeRROutput ** possible_outputs;
int x;
int y;
float scale;
GnomeRRRotation current_rotation;
GnomeRRRotation rotations;
int gamma_size;
};
struct GnomeRRMode
{
ScreenInfo * info;
RRMode id;
char * name;
int width;
int height;
int freq; /* in mHz */
gboolean doublescan;
gboolean interlaced;
gboolean vsync;
};
/* GnomeRRCrtc */
static GnomeRRCrtc * crtc_new (ScreenInfo *info,
RRCrtc id);
static GnomeRRCrtc * crtc_copy (const GnomeRRCrtc *from);
static void crtc_free (GnomeRRCrtc *crtc);
static gboolean crtc_initialize (GnomeRRCrtc *crtc,
XRRScreenResources *res,
GError **error);
/* GnomeRROutput */
static GnomeRROutput *output_new (ScreenInfo *info,
RROutput id);
static gboolean output_initialize (GnomeRROutput *output,
XRRScreenResources *res,
GError **error);
static GnomeRROutput *output_copy (const GnomeRROutput *from);
static void output_free (GnomeRROutput *output);
/* GnomeRRMode */
static GnomeRRMode * mode_new (ScreenInfo *info,
RRMode id);
static void mode_initialize (GnomeRRMode *mode,
XRRModeInfo *info);
static GnomeRRMode * mode_copy (const GnomeRRMode *from);
static void mode_free (GnomeRRMode *mode);
static void gnome_rr_screen_finalize (GObject*);
static void gnome_rr_screen_set_property (GObject*, guint, const GValue*, GParamSpec*);
static void gnome_rr_screen_get_property (GObject*, guint, GValue*, GParamSpec*);
static gboolean gnome_rr_screen_initable_init (GInitable*, GCancellable*, GError**);
static void gnome_rr_screen_initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GnomeRRScreen, gnome_rr_screen, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gnome_rr_screen_initable_iface_init))
G_DEFINE_BOXED_TYPE (GnomeRRCrtc, gnome_rr_crtc, crtc_copy, crtc_free)
G_DEFINE_BOXED_TYPE (GnomeRROutput, gnome_rr_output, output_copy, output_free)
G_DEFINE_BOXED_TYPE (GnomeRRMode, gnome_rr_mode, mode_copy, mode_free)
/* Errors */
/**
* gnome_rr_error_quark:
*
* Returns the #GQuark that will be used for #GError values returned by the
* GnomeRR API.
*
* Return value: a #GQuark used to identify errors coming from the GnomeRR API.
*/
GQuark
gnome_rr_error_quark (void)
{
return g_quark_from_static_string ("gnome-rr-error-quark");
}
/* Screen */
static GnomeRROutput *
gnome_rr_output_by_id (ScreenInfo *info, RROutput id)
{
GnomeRROutput **output;
g_assert (info != NULL);
for (output = info->outputs; *output; ++output)
{
if ((*output)->id == id)
return *output;
}
return NULL;
}
static GnomeRRCrtc *
crtc_by_id (ScreenInfo *info, RRCrtc id)
{
GnomeRRCrtc **crtc;
if (!info)
return NULL;
for (crtc = info->crtcs; *crtc; ++crtc)
{
if ((*crtc)->id == id)
return *crtc;
}
return NULL;
}
static GnomeRRMode *
mode_by_id (ScreenInfo *info, RRMode id)
{
GnomeRRMode **mode;
g_assert (info != NULL);
for (mode = info->modes; *mode; ++mode)
{
if ((*mode)->id == id)
return *mode;
}
return NULL;
}
static void
screen_info_free (ScreenInfo *info)
{
GnomeRROutput **output;
GnomeRRCrtc **crtc;
GnomeRRMode **mode;
g_assert (info != NULL);
if (info->resources)
{
XRRFreeScreenResources (info->resources);
info->resources = NULL;
}
if (info->outputs)
{
for (output = info->outputs; *output; ++output)
output_free (*output);
g_free (info->outputs);
}
if (info->crtcs)
{
for (crtc = info->crtcs; *crtc; ++crtc)
crtc_free (*crtc);
g_free (info->crtcs);
}
if (info->modes)
{
for (mode = info->modes; *mode; ++mode)
mode_free (*mode);
g_free (info->modes);
}
if (info->clone_modes)
{
/* The modes themselves were freed above */
g_free (info->clone_modes);
}
g_free (info);
}
static gboolean
has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
{
int i;
GnomeRRMode **modes = gnome_rr_output_list_modes (output);
int width = gnome_rr_mode_get_width (mode);
int height = gnome_rr_mode_get_height (mode);
for (i = 0; modes[i] != NULL; ++i)
{
GnomeRRMode *m = modes[i];
if (gnome_rr_mode_get_width (m) == width &&
gnome_rr_mode_get_height (m) == height)
{
return TRUE;
}
}
return FALSE;
}
static void
gather_clone_modes (ScreenInfo *info)
{
int i;
GPtrArray *result = g_ptr_array_new ();
for (i = 0; info->outputs[i] != NULL; ++i)
{
int j;
GnomeRROutput *output1, *output2;
output1 = info->outputs[i];
if (!output1->connected)
continue;
for (j = 0; output1->modes[j] != NULL; ++j)
{
GnomeRRMode *mode = output1->modes[j];
gboolean valid;
int k;
valid = TRUE;
for (k = 0; info->outputs[k] != NULL; ++k)
{
output2 = info->outputs[k];
if (!output2->connected)
continue;
if (!has_similar_mode (output2, mode))
{
valid = FALSE;
break;
}
}
if (valid)
g_ptr_array_add (result, mode);
}
}
g_ptr_array_add (result, NULL);
info->clone_modes = (GnomeRRMode **)g_ptr_array_free (result, FALSE);
}
static gboolean
fill_screen_info_from_resources (ScreenInfo *info,
XRRScreenResources *resources,
GError **error)
{
int i;
GPtrArray *a;
GnomeRRCrtc **crtc;
GnomeRROutput **output;
info->resources = resources;
/* We create all the structures before initializing them, so
* that they can refer to each other.
*/
a = g_ptr_array_new ();
for (i = 0; i < resources->ncrtc; ++i)
{
GnomeRRCrtc *crtc = crtc_new (info, resources->crtcs[i]);
g_ptr_array_add (a, crtc);
}
g_ptr_array_add (a, NULL);
info->crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
a = g_ptr_array_new ();
for (i = 0; i < resources->noutput; ++i)
{
GnomeRROutput *output = output_new (info, resources->outputs[i]);
g_ptr_array_add (a, output);
}
g_ptr_array_add (a, NULL);
info->outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
a = g_ptr_array_new ();
for (i = 0; i < resources->nmode; ++i)
{
GnomeRRMode *mode = mode_new (info, resources->modes[i].id);
g_ptr_array_add (a, mode);
}
g_ptr_array_add (a, NULL);
info->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
/* Initialize */
for (crtc = info->crtcs; *crtc; ++crtc)
{
if (!crtc_initialize (*crtc, resources, error))
return FALSE;
}
for (output = info->outputs; *output; ++output)
{
if (!output_initialize (*output, resources, error))
return FALSE;
}
for (i = 0; i < resources->nmode; ++i)
{
GnomeRRMode *mode = mode_by_id (info, resources->modes[i].id);
mode_initialize (mode, &(resources->modes[i]));
}
gather_clone_modes (info);
return TRUE;
}
static gboolean
fill_out_screen_info (Display *xdisplay,
Window xroot,
ScreenInfo *info,
gboolean needs_reprobe,
GError **error)
{
XRRScreenResources *resources;
GnomeRRScreenPrivate *priv;
g_assert (xdisplay != NULL);
g_assert (info != NULL);
priv = info->screen->priv;
/* First update the screen resources */
if (needs_reprobe)
resources = XRRGetScreenResources (xdisplay, xroot);
else
{
/* XRRGetScreenResourcesCurrent is less expensive than
* XRRGetScreenResources, however it is available only
* in RandR 1.3 or higher
*/
if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv))
resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
else
resources = XRRGetScreenResources (xdisplay, xroot);
}
if (resources)
{
if (!fill_screen_info_from_resources (info, resources, error))
return FALSE;
}
else
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
/* Translators: a CRTC is a CRT Controller (this is X terminology). */
_("could not get the screen resources (CRTCs, outputs, modes)"));
return FALSE;
}
/* Then update the screen size range. We do this after XRRGetScreenResources() so that
* the X server will already have an updated view of the outputs.
*/
if (needs_reprobe) {
gboolean success;
gdk_error_trap_push ();
success = XRRGetScreenSizeRange (xdisplay, xroot,
&(info->min_width),
&(info->min_height),
&(info->max_width),
&(info->max_height));
gdk_flush ();
if (gdk_error_trap_pop ()) {
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_UNKNOWN,
_("unhandled X error while getting the range of screen sizes"));
return FALSE;
}
if (!success) {
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
_("could not get the range of screen sizes"));
return FALSE;
}
}
else
{
gnome_rr_screen_get_ranges (info->screen,
&(info->min_width),
&(info->max_width),
&(info->min_height),
&(info->max_height));
}
info->primary = None;
if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv)) {
gdk_error_trap_push ();
info->primary = XRRGetOutputPrimary (xdisplay, xroot);
gdk_error_trap_pop_ignored ();
}
/* can the screen do DPMS? */
gdk_error_trap_push ();
priv->dpms_capable = DPMSCapable (priv->xdisplay);
gdk_error_trap_pop_ignored ();
return TRUE;
}
static ScreenInfo *
screen_info_new (GnomeRRScreen *screen, gboolean needs_reprobe, GError **error)
{
ScreenInfo *info = g_new0 (ScreenInfo, 1);
GnomeRRScreenPrivate *priv;
g_assert (screen != NULL);
priv = screen->priv;
info->outputs = NULL;
info->crtcs = NULL;
info->modes = NULL;
info->screen = screen;
if (fill_out_screen_info (priv->xdisplay, priv->xroot, info, needs_reprobe, error))
{
return info;
}
else
{
screen_info_free (info);
return NULL;
}
}
static GnomeRROutput *
find_output_by_id (GnomeRROutput **haystack, guint32 id)
{
guint i;
for (i = 0; haystack[i] != NULL; i++)
{
if (gnome_rr_output_get_id (haystack[i]) == id)
return haystack[i];
}
return NULL;
}
static void
diff_outputs_and_emit_signals (ScreenInfo *old, ScreenInfo *new)
{
guint i;
guint32 id_old, id_new;
GnomeRROutput *output_old;
GnomeRROutput *output_new;
/* have any outputs been removed or disconnected */
for (i = 0; old->outputs[i] != NULL; i++)
{
id_old = gnome_rr_output_get_id (old->outputs[i]);
output_new = find_output_by_id (new->outputs, id_old);
if (output_new == NULL)
{
/* output removed (and disconnected) */
if (gnome_rr_output_is_connected (old->outputs[i]))
{
g_signal_emit (G_OBJECT (new->screen),
screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
old->outputs[i]);
}
continue;
}
if (gnome_rr_output_is_connected (old->outputs[i]) &&
!gnome_rr_output_is_connected (output_new))
{
/* output disconnected */
g_signal_emit (G_OBJECT (new->screen),
screen_signals[SCREEN_OUTPUT_DISCONNECTED], 0,
old->outputs[i]);
}
}
/* have any outputs been created or connected */
for (i = 0; new->outputs[i] != NULL; i++)
{
id_new = gnome_rr_output_get_id (new->outputs[i]);
output_old = find_output_by_id (old->outputs, id_new);
if (output_old == NULL)
{
/* output created */
if (gnome_rr_output_is_connected (new->outputs[i]))
{
g_signal_emit (G_OBJECT (new->screen),
screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
new->outputs[i]);
}
continue;
}
if (!gnome_rr_output_is_connected (output_old) &&
gnome_rr_output_is_connected (new->outputs[i]))
{
/* output connected */
g_signal_emit (G_OBJECT (new->screen),
screen_signals[SCREEN_OUTPUT_CONNECTED], 0,
new->outputs[i]);
}
}
}
static gboolean
screen_update (GnomeRRScreen *screen, gboolean force_callback, gboolean needs_reprobe, GError **error)
{
ScreenInfo *info;
gboolean changed = FALSE;
g_assert (screen != NULL);
info = screen_info_new (screen, needs_reprobe, error);
if (!info)
return FALSE;
if (info->resources->configTimestamp != screen->priv->info->resources->configTimestamp)
changed = TRUE;
/* work out if any outputs have changed connected state */
diff_outputs_and_emit_signals (screen->priv->info, info);
screen_info_free (screen->priv->info);
screen->priv->info = info;
if (changed || force_callback)
g_signal_emit (G_OBJECT (screen), screen_signals[SCREEN_CHANGED], 0);
return changed;
}
static GdkFilterReturn
screen_on_event (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
GnomeRRScreen *screen = data;
GnomeRRScreenPrivate *priv = screen->priv;
XEvent *e = xevent;
int event_num;
if (!e)
return GDK_FILTER_CONTINUE;
event_num = e->type - priv->randr_event_base;
if (event_num == RRScreenChangeNotify) {
/* We don't reprobe the hardware; we just fetch the X server's latest
* state. The server already knows the new state of the outputs; that's
* why it sent us an event!
*/
screen_update (screen, TRUE, FALSE, NULL); /* NULL-GError */
#if 0
/* Enable this code to get a dialog showing the RANDR timestamps, for debugging purposes */
{
GtkWidget *dialog;
XRRScreenChangeNotifyEvent *rr_event;
static int dialog_num;
rr_event = (XRRScreenChangeNotifyEvent *) e;
dialog = gtk_message_dialog_new (NULL,
0,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
"RRScreenChangeNotify timestamps (%d):\n"
"event change: %u\n"
"event config: %u\n"
"event serial: %lu\n"
"----------------------"
"screen change: %u\n"
"screen config: %u\n",
dialog_num++,
(guint32) rr_event->timestamp,
(guint32) rr_event->config_timestamp,
rr_event->serial,
(guint32) priv->info->resources->timestamp,
(guint32) priv->info->resources->configTimestamp);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
#endif
}
#if 0
/* WHY THIS CODE IS DISABLED:
*
* Note that in gnome_rr_screen_new(), we only select for
* RRScreenChangeNotifyMask. We used to select for other values in
* RR*NotifyMask, but we weren't really doing anything useful with those
* events. We only care about "the screens changed in some way or another"
* for now.
*
* If we ever run into a situtation that could benefit from processing more
* detailed events, we can enable this code again.
*
* Note that the X server sends RRScreenChangeNotify in conjunction with the
* more detailed events from RANDR 1.2 - see xserver/randr/randr.c:TellChanged().
*/
else if (event_num == RRNotify)
{
/* Other RandR events */
XRRNotifyEvent *event = (XRRNotifyEvent *)e;
/* Here we can distinguish between RRNotify events supported
* since RandR 1.2 such as RRNotify_OutputProperty. For now, we
* don't have anything special to do for particular subevent types, so
* we leave this as an empty switch().
*/
switch (event->subtype)
{
default:
break;
}
/* No need to reprobe hardware here */
screen_update (screen, TRUE, FALSE, NULL); /* NULL-GError */
}
#endif
/* Pass the event on to GTK+ */
return GDK_FILTER_CONTINUE;
}
static gboolean
gnome_rr_screen_initable_init (GInitable *initable, GCancellable *canc, GError **error)
{
GnomeRRScreen *self = GNOME_RR_SCREEN (initable);
GnomeRRScreenPrivate *priv = self->priv;
Display *dpy = GDK_SCREEN_XDISPLAY (self->priv->gdk_screen);
int event_base;
int ignore;
priv->interface_settings = g_settings_new ("org.cinnamon.desktop.interface");
priv->connector_type_atom = XInternAtom (dpy, "ConnectorType", FALSE);
if (XRRQueryExtension (dpy, &event_base, &ignore))
{
priv->randr_event_base = event_base;
XRRQueryVersion (dpy, &priv->rr_major_version, &priv->rr_minor_version);
if (priv->rr_major_version < 1 || (priv->rr_major_version == 1 && priv->rr_minor_version < 2)) {
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_RANDR_EXTENSION,
"RANDR extension is too old (must be at least 1.2)");
return FALSE;
}
priv->info = screen_info_new (self, TRUE, error);
if (!priv->info) {
return FALSE;
}
XRRSelectInput (priv->xdisplay,
priv->xroot,
RRScreenChangeNotifyMask);
gdk_x11_register_standard_event_type (gdk_screen_get_display (priv->gdk_screen),
event_base,
RRNotify + 1);
gdk_window_add_filter (priv->gdk_root, screen_on_event, self);
return TRUE;
}
else
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_RANDR_EXTENSION,
_("RANDR extension is not present"));
return FALSE;
}
}
void
gnome_rr_screen_initable_iface_init (GInitableIface *iface)
{
iface->init = gnome_rr_screen_initable_init;
}
void
gnome_rr_screen_finalize (GObject *gobject)
{
GnomeRRScreen *screen = GNOME_RR_SCREEN (gobject);
gdk_window_remove_filter (screen->priv->gdk_root, screen_on_event, screen);
if (screen->priv->info)
screen_info_free (screen->priv->info);
g_clear_object (&screen->priv->interface_settings);
G_OBJECT_CLASS (gnome_rr_screen_parent_class)->finalize (gobject);
}
void
gnome_rr_screen_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
{
GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
GnomeRRScreenPrivate *priv = self->priv;
switch (property_id)
{
case SCREEN_PROP_GDK_SCREEN:
priv->gdk_screen = g_value_get_object (value);
priv->gdk_root = gdk_screen_get_root_window (priv->gdk_screen);
priv->xroot = gdk_x11_window_get_xid (priv->gdk_root);
priv->xdisplay = GDK_SCREEN_XDISPLAY (priv->gdk_screen);
priv->xscreen = gdk_x11_screen_get_xscreen (priv->gdk_screen);
return;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
return;
}
}
void
gnome_rr_screen_get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *property)
{
GnomeRRScreen *self = GNOME_RR_SCREEN (gobject);
GnomeRRScreenPrivate *priv = self->priv;
switch (property_id)
{
case SCREEN_PROP_GDK_SCREEN:
g_value_set_object (value, priv->gdk_screen);
return;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
return;
}
}
void
gnome_rr_screen_class_init (GnomeRRScreenClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GnomeRRScreenPrivate));
gobject_class->set_property = gnome_rr_screen_set_property;
gobject_class->get_property = gnome_rr_screen_get_property;
gobject_class->finalize = gnome_rr_screen_finalize;
g_object_class_install_property(
gobject_class,
SCREEN_PROP_GDK_SCREEN,
g_param_spec_object (
"gdk-screen",
"GDK Screen",
"The GDK Screen represented by this GnomeRRScreen",
GDK_TYPE_SCREEN,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)
);
screen_signals[SCREEN_CHANGED] = g_signal_new("changed",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (GnomeRRScreenClass, changed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* GnomeRRScreen::output-connected:
* @screen: the #GnomeRRScreen that emitted the signal
* @output: the #GnomeRROutput that was connected
*
* This signal is emitted when a display device is connected to a
* port, or a port is hotplugged with an active output. The latter
* can happen if a laptop is docked, and the dock provides a new
* active output.
*
* The @output value is not a #GObject. The returned @output value can
* only assume to be valid during the emission of the signal (i.e. within
* your signal handler only), as it may change later when the @screen
* is modified due to an event from the X server, or due to another
* place in the application modifying the @screen and the @output.
* Therefore, deal with changes to the @output right in your signal
* handler, instead of keeping the @output reference for an async or
* idle function.
**/
screen_signals[SCREEN_OUTPUT_CONNECTED] = g_signal_new("output-connected",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (GnomeRRScreenClass, output_connected),
NULL,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1, G_TYPE_POINTER);
/**
* GnomeRRScreen::output-disconnected:
* @screen: the #GnomeRRScreen that emitted the signal
* @output: the #GnomeRROutput that was disconnected
*
* This signal is emitted when a display device is disconnected from
* a port, or a port output is hot-unplugged. The latter can happen
* if a laptop is undocked, and the dock provided the output.
*
* The @output value is not a #GObject. The returned @output value can
* only assume to be valid during the emission of the signal (i.e. within
* your signal handler only), as it may change later when the @screen
* is modified due to an event from the X server, or due to another
* place in the application modifying the @screen and the @output.
* Therefore, deal with changes to the @output right in your signal
* handler, instead of keeping the @output reference for an async or
* idle function.
**/
screen_signals[SCREEN_OUTPUT_DISCONNECTED] = g_signal_new("output-disconnected",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (GnomeRRScreenClass, output_disconnected),
NULL,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1, G_TYPE_POINTER);
}
void
gnome_rr_screen_init (GnomeRRScreen *self)
{
GnomeRRScreenPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_RR_SCREEN, GnomeRRScreenPrivate);
self->priv = priv;
priv->gdk_screen = NULL;
priv->gdk_root = NULL;
priv->xdisplay = NULL;
priv->xroot = None;
priv->xscreen = NULL;
priv->info = NULL;
priv->rr_major_version = 0;
priv->rr_minor_version = 0;
}
/* Weak reference callback set in gnome_rr_screen_new(); we remove the GObject data from the GdkScreen. */
static void
rr_screen_weak_notify_cb (gpointer data, GObject *where_the_object_was)
{
GdkScreen *screen = GDK_SCREEN (data);
g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", NULL);
}
/**
* gnome_rr_screen_new:
* @screen: the #GdkScreen on which to operate
* @error: will be set if XRandR is not supported
*
* Creates a unique #GnomeRRScreen instance for the specified @screen.
*
* Returns: a unique #GnomeRRScreen instance, specific to the @screen, or NULL
* if this could not be created, for instance if the driver does not support
* Xrandr 1.2. Each #GdkScreen thus has a single instance of #GnomeRRScreen.
*/
GnomeRRScreen *
gnome_rr_screen_new (GdkScreen *screen,
GError **error)
{
GnomeRRScreen *rr_screen;
g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
rr_screen = g_object_get_data (G_OBJECT (screen), "GnomeRRScreen");
if (rr_screen)
g_object_ref (rr_screen);
else {
_gnome_desktop_init_i18n ();
rr_screen = g_initable_new (GNOME_TYPE_RR_SCREEN, NULL, error, "gdk-screen", screen, NULL);
if (rr_screen) {
g_object_set_data (G_OBJECT (screen), "GnomeRRScreen", rr_screen);
g_object_weak_ref (G_OBJECT (rr_screen), rr_screen_weak_notify_cb, screen);
}
}
return rr_screen;
}
void
gnome_rr_screen_set_size (GnomeRRScreen *screen,
int width,
int height,
int mm_width,
int mm_height)
{
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
g_debug ("Setting screen size: %d x %d, %dmm x %dmm", width, height, mm_width, mm_height);
gdk_error_trap_push ();
XRRSetScreenSize (screen->priv->xdisplay, screen->priv->xroot,
width, height, mm_width, mm_height);
gdk_error_trap_pop_ignored ();
}
/**
* gnome_rr_screen_get_ranges:
* @screen: a #GnomeRRScreen
* @min_width: (out): the minimum width
* @max_width: (out): the maximum width
* @min_height: (out): the minimum height
* @max_height: (out): the maximum height
*
* Get the ranges of the screen
*/
void
gnome_rr_screen_get_ranges (GnomeRRScreen *screen,
int *min_width,
int *max_width,
int *min_height,
int *max_height)
{
GnomeRRScreenPrivate *priv;
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
priv = screen->priv;
if (min_width)
*min_width = priv->info->min_width;
if (max_width)
*max_width = priv->info->max_width;
if (min_height)
*min_height = priv->info->min_height;
if (max_height)
*max_height = priv->info->max_height;
}
/**
* gnome_rr_screen_get_timestamps:
* @screen: a #GnomeRRScreen
* @change_timestamp_ret: (out): Location in which to store the timestamp at which the RANDR configuration was last changed
* @config_timestamp_ret: (out): Location in which to store the timestamp at which the RANDR configuration was last obtained
*
* Queries the two timestamps that the X RANDR extension maintains. The X
* server will prevent change requests for stale configurations, those whose
* timestamp is not equal to that of the latest request for configuration. The
* X server will also prevent change requests that have an older timestamp to
* the latest change request.
*/
void
gnome_rr_screen_get_timestamps (GnomeRRScreen *screen,
guint32 *change_timestamp_ret,
guint32 *config_timestamp_ret)
{
GnomeRRScreenPrivate *priv;
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
priv = screen->priv;
if (change_timestamp_ret)
*change_timestamp_ret = priv->info->resources->timestamp;
if (config_timestamp_ret)
*config_timestamp_ret = priv->info->resources->configTimestamp;
}
static gboolean
force_timestamp_update (GnomeRRScreen *screen)
{
GnomeRRScreenPrivate *priv = screen->priv;
GnomeRRCrtc *crtc;
XRRCrtcInfo *current_info;
Status status;
gboolean timestamp_updated;
timestamp_updated = FALSE;
crtc = priv->info->crtcs[0];
if (crtc == NULL)
goto out;
current_info = XRRGetCrtcInfo (priv->xdisplay,
priv->info->resources,
crtc->id);
if (current_info == NULL)
goto out;
gdk_error_trap_push ();
status = XRRSetCrtcConfig (priv->xdisplay,
priv->info->resources,
crtc->id,
current_info->timestamp,
current_info->x,
current_info->y,
current_info->mode,
current_info->rotation,
current_info->outputs,
current_info->noutput);
XRRFreeCrtcInfo (current_info);
gdk_flush ();
if (gdk_error_trap_pop ())
goto out;
if (status == RRSetConfigSuccess)
timestamp_updated = TRUE;
out:
return timestamp_updated;
}
/**
* gnome_rr_screen_refresh:
* @screen: a #GnomeRRScreen
* @error: location to store error, or %NULL
*
* Refreshes the screen configuration, and calls the screen's callback if it
* exists and if the screen's configuration changed.
*
* Return value: TRUE if the screen's configuration changed; otherwise, the
* function returns FALSE and a NULL error if the configuration didn't change,
* or FALSE and a non-NULL error if there was an error while refreshing the
* configuration.
*/
gboolean
gnome_rr_screen_refresh (GnomeRRScreen *screen,
GError **error)
{
gboolean refreshed;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
gdk_x11_display_grab (gdk_screen_get_display (screen->priv->gdk_screen));
refreshed = screen_update (screen, FALSE, TRUE, error);
force_timestamp_update (screen); /* this is to keep other clients from thinking that the X server re-detected things by itself - bgo#621046 */
gdk_x11_display_ungrab (gdk_screen_get_display (screen->priv->gdk_screen));
return refreshed;
}
/**
* gnome_rr_screen_get_dpms_mode:
**/
gboolean
gnome_rr_screen_get_dpms_mode (GnomeRRScreen *screen,
GnomeRRDpmsMode *mode,
GError **error)
{
BOOL enabled = FALSE;
CARD16 state;
gboolean ret = FALSE;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_return_val_if_fail (mode != NULL, FALSE);
if (!screen->priv->dpms_capable) {
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_NO_DPMS_EXTENSION,
"Display is not DPMS capable");
goto out;
}
if (!DPMSInfo (screen->priv->xdisplay,
&state,
&enabled)) {
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_UNKNOWN,
"Unable to get DPMS state");
goto out;
}
/* DPMS not enabled is a valid mode */
if (!enabled) {
*mode = GNOME_RR_DPMS_DISABLED;
ret = TRUE;
goto out;
}
switch (state) {
case DPMSModeOn:
*mode = GNOME_RR_DPMS_ON;
break;
case DPMSModeStandby:
*mode = GNOME_RR_DPMS_STANDBY;
break;
case DPMSModeSuspend:
*mode = GNOME_RR_DPMS_SUSPEND;
break;
case DPMSModeOff:
*mode = GNOME_RR_DPMS_OFF;
break;
default:
g_assert_not_reached ();
break;
}
ret = TRUE;
out:
return ret;
}
/**
* gnome_rr_screen_clear_dpms_timeouts:
**/
static gboolean
gnome_rr_screen_clear_dpms_timeouts (GnomeRRScreen *screen,
GError **error)
{
gdk_error_trap_push ();
/* DPMSSetTimeouts() return value is often a lie, so ignore it */
DPMSSetTimeouts (screen->priv->xdisplay, 0, 0, 0);
if (gdk_error_trap_pop ()) {
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_UNKNOWN,
"Could not set DPMS timeouts");
return FALSE;
}
return TRUE;
}
/**
* gnome_rr_screen_set_dpms_mode:
*
* This method also disables the DPMS timeouts.
**/
gboolean
gnome_rr_screen_set_dpms_mode (GnomeRRScreen *screen,
GnomeRRDpmsMode mode,
GError **error)
{
CARD16 state = 0;
gboolean ret;
GnomeRRDpmsMode current_mode;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
/* set, if the new mode is different */
ret = gnome_rr_screen_get_dpms_mode (screen, ¤t_mode, error);
if (!ret)
goto out;
if (current_mode == mode) {
ret = gnome_rr_screen_clear_dpms_timeouts (screen, error);
goto out;
}
switch (mode) {
case GNOME_RR_DPMS_ON:
state = DPMSModeOn;
break;
case GNOME_RR_DPMS_STANDBY:
state = DPMSModeStandby;
break;
case GNOME_RR_DPMS_SUSPEND:
state = DPMSModeSuspend;
break;
case GNOME_RR_DPMS_OFF:
state = DPMSModeOff;
break;
default:
g_assert_not_reached ();
break;
}
gdk_error_trap_push ();
/* DPMSForceLevel() return value is often a lie, so ignore it */
DPMSForceLevel (screen->priv->xdisplay, state);
if (gdk_error_trap_pop ()) {
ret = FALSE;
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_UNKNOWN,
"Could not change DPMS mode");
goto out;
}
ret = gnome_rr_screen_clear_dpms_timeouts (screen, error);
if (!ret)
goto out;
out:
return ret;
}
/**
* gnome_rr_screen_list_modes:
*
* List available XRandR modes
*
* Returns: (array zero-terminated=1) (transfer none):
*/
GnomeRRMode **
gnome_rr_screen_list_modes (GnomeRRScreen *screen)
{
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
return screen->priv->info->modes;
}
/**
* gnome_rr_screen_list_clone_modes:
*
* List available XRandR clone modes
*
* Returns: (array zero-terminated=1) (transfer none):
*/
GnomeRRMode **
gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen)
{
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
return screen->priv->info->clone_modes;
}
/**
* gnome_rr_screen_list_crtcs:
*
* List all CRTCs
*
* Returns: (array zero-terminated=1) (transfer none):
*/
GnomeRRCrtc **
gnome_rr_screen_list_crtcs (GnomeRRScreen *screen)
{
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
return screen->priv->info->crtcs;
}
/**
* gnome_rr_screen_list_outputs:
*
* List all outputs
*
* Returns: (array zero-terminated=1) (transfer none):
*/
GnomeRROutput **
gnome_rr_screen_list_outputs (GnomeRRScreen *screen)
{
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
return screen->priv->info->outputs;
}
/**
* gnome_rr_screen_get_crtc_by_id:
*
* Returns: (transfer none): the CRTC identified by @id
*/
GnomeRRCrtc *
gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen,
guint32 id)
{
GnomeRRCrtc **crtcs;
int i;
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
crtcs = screen->priv->info->crtcs;
for (i = 0; crtcs[i] != NULL; ++i)
{
if (crtcs[i]->id == id)
return crtcs[i];
}
return NULL;
}
/**
* gnome_rr_screen_get_output_by_id:
*
* Returns: (transfer none): the output identified by @id
*/
GnomeRROutput *
gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen,
guint32 id)
{
GnomeRROutput **outputs;
int i;
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
outputs = screen->priv->info->outputs;
for (i = 0; outputs[i] != NULL; ++i)
{
if (outputs[i]->id == id)
return outputs[i];
}
return NULL;
}
/* GnomeRROutput */
static GnomeRROutput *
output_new (ScreenInfo *info, RROutput id)
{
GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
output->id = id;
output->info = info;
return output;
}
static guint8 *
get_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 guint8 *
read_edid_data (GnomeRROutput *output, gsize *len)
{
Atom edid_atom;
guint8 *result;
edid_atom = XInternAtom (DISPLAY (output), "EDID", FALSE);
result = get_property (DISPLAY (output),
output->id, edid_atom, len);
if (!result)
{
edid_atom = XInternAtom (DISPLAY (output), "EDID_DATA", FALSE);
result = get_property (DISPLAY (output),
output->id, edid_atom, len);
}
if (!result)
{
edid_atom = XInternAtom (DISPLAY (output), "XFree86_DDC_EDID1_RAWDATA", FALSE);
result = get_property (DISPLAY (output),
output->id, edid_atom, len);
}
if (result)
{
if (*len % 128 == 0)
return result;
else
g_free (result);
}
return NULL;
}
static char *
get_connector_type_string (GnomeRROutput *output)
{
char *result;
unsigned char *prop;
int actual_format;
unsigned long nitems, bytes_after;
Atom actual_type;
Atom connector_type;
char *connector_type_str;
result = NULL;
if (XRRGetOutputProperty (DISPLAY (output), output->id, output->info->screen->priv->connector_type_atom,
0, 100, False, False,
AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &prop) != Success)
return NULL;
if (!(actual_type == XA_ATOM && actual_format == 32 && nitems == 1))
goto out;
connector_type = *((Atom *) prop);
connector_type_str = XGetAtomName (DISPLAY (output), connector_type);
if (connector_type_str) {
result = g_strdup (connector_type_str); /* so the caller can g_free() it */
XFree (connector_type_str);
}
out:
XFree (prop);
return result;
}
static void
update_brightness_limits (GnomeRROutput *output)
{
gint rc;
Atom atom;
XRRPropertyInfo *info;
gdk_error_trap_push ();
atom = XInternAtom (DISPLAY (output), "BACKLIGHT", FALSE);
info = XRRQueryOutputProperty (DISPLAY (output), output->id, atom);
rc = gdk_error_trap_pop ();
if (rc != Success)
{
if (rc != BadName)
g_warning ("could not get output property for %s, rc: %i",
output->name, rc);
goto out;
}
if (info == NULL)
{
g_warning ("could not get output property for %s",
output->name);
goto out;
}
if (!info->range || info->num_values != 2)
{
g_debug ("backlight %s was not range", output->name);
goto out;
}
output->backlight_min = info->values[0];
output->backlight_max = info->values[1];
out:
if (info != NULL)
{
XFree (info);
}
}
static gboolean
output_initialize (GnomeRROutput *output, XRRScreenResources *res, GError **error)
{
XRROutputInfo *info = XRRGetOutputInfo (DISPLAY (output),
res,
output->id);
GPtrArray *a;
int i;
#if 0
g_print ("Output %lx Timestamp: %u\n", output->id, (guint32)info->timestamp);
#endif
if (!info || !output->info)
{
/* FIXME: see the comment in crtc_initialize() */
/* Translators: here, an "output" is a video output */
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
_("could not get information about output %d"),
(int) output->id);
return FALSE;
}
output->name = g_strdup (info->name); /* FIXME: what is nameLen used for? */
output->current_crtc = crtc_by_id (output->info, info->crtc);
output->width_mm = info->mm_width;
output->height_mm = info->mm_height;
output->connected = (info->connection == RR_Connected);
output->connector_type = get_connector_type_string (output);
/* Possible crtcs */
a = g_ptr_array_new ();
for (i = 0; i < info->ncrtc; ++i)
{
GnomeRRCrtc *crtc = crtc_by_id (output->info, info->crtcs[i]);
if (crtc)
g_ptr_array_add (a, crtc);
}
g_ptr_array_add (a, NULL);
output->possible_crtcs = (GnomeRRCrtc **)g_ptr_array_free (a, FALSE);
/* Clones */
a = g_ptr_array_new ();
for (i = 0; i < info->nclone; ++i)
{
GnomeRROutput *gnome_rr_output = gnome_rr_output_by_id (output->info, info->clones[i]);
if (gnome_rr_output)
g_ptr_array_add (a, gnome_rr_output);
}
g_ptr_array_add (a, NULL);
output->clones = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
/* Modes */
a = g_ptr_array_new ();
for (i = 0; i < info->nmode; ++i)
{
GnomeRRMode *mode = mode_by_id (output->info, info->modes[i]);
if (mode)
g_ptr_array_add (a, mode);
}
g_ptr_array_add (a, NULL);
output->modes = (GnomeRRMode **)g_ptr_array_free (a, FALSE);
output->n_preferred = info->npreferred;
/* Edid data */
output->edid_data = read_edid_data (output, &output->edid_size);
/* brightness data */
if (output->connected)
update_brightness_limits (output);
XRRFreeOutputInfo (info);
return TRUE;
}
static GnomeRROutput*
output_copy (const GnomeRROutput *from)
{
GPtrArray *array;
GnomeRRCrtc **p_crtc;
GnomeRROutput **p_output;
GnomeRRMode **p_mode;
GnomeRROutput *output = g_slice_new0 (GnomeRROutput);
output->id = from->id;
output->info = from->info;
output->name = g_strdup (from->name);
output->current_crtc = from->current_crtc;
output->width_mm = from->width_mm;
output->height_mm = from->height_mm;
output->connected = from->connected;
output->n_preferred = from->n_preferred;
output->connector_type = g_strdup (from->connector_type);
output->backlight_min = -1;
output->backlight_max = -1;
array = g_ptr_array_new ();
for (p_crtc = from->possible_crtcs; *p_crtc != NULL; p_crtc++)
{
g_ptr_array_add (array, *p_crtc);
}
output->possible_crtcs = (GnomeRRCrtc**) g_ptr_array_free (array, FALSE);
array = g_ptr_array_new ();
for (p_output = from->clones; *p_output != NULL; p_output++)
{
g_ptr_array_add (array, *p_output);
}
output->clones = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
array = g_ptr_array_new ();
for (p_mode = from->modes; *p_mode != NULL; p_mode++)
{
g_ptr_array_add (array, *p_mode);
}
output->modes = (GnomeRRMode**) g_ptr_array_free (array, FALSE);
output->edid_size = from->edid_size;
output->edid_data = g_memdup (from->edid_data, from->edid_size);
return output;
}
static void
output_free (GnomeRROutput *output)
{
g_free (output->clones);
g_free (output->modes);
g_free (output->possible_crtcs);
g_free (output->edid_data);
g_free (output->name);
g_free (output->connector_type);
g_slice_free (GnomeRROutput, output);
}
guint32
gnome_rr_output_get_id (GnomeRROutput *output)
{
g_assert(output != NULL);
return output->id;
}
const guint8 *
gnome_rr_output_get_edid_data (GnomeRROutput *output, gsize *size)
{
g_return_val_if_fail (output != NULL, NULL);
if (size)
*size = output->edid_size;
return output->edid_data;
}
gboolean
gnome_rr_output_get_ids_from_edid (GnomeRROutput *output,
char **vendor,
int *product,
int *serial)
{
MonitorInfo *info;
g_return_val_if_fail (output != NULL, FALSE);
if (!output->edid_data)
return FALSE;
info = decode_edid (output->edid_data);
if (!info)
return FALSE;
if (vendor)
*vendor = g_memdup (info->manufacturer_code, 4);
if (product)
*product = info->product_code;
if (serial)
*serial = info->serial_number;
g_free (info);
return TRUE;
}
/**
* gnome_rr_output_get_backlight_min:
*
* Returns: The mimimum backlight value, or -1 if not supported
*/
gint
gnome_rr_output_get_backlight_min (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, -1);
return output->backlight_min;
}
/**
* gnome_rr_output_get_backlight_max:
*
* Returns: The maximum backlight value, or -1 if not supported
*/
gint
gnome_rr_output_get_backlight_max (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, -1);
return output->backlight_max;
}
/**
* gnome_rr_output_get_backlight:
*
* Returns: The currently set backlight brightness
*/
gint
gnome_rr_output_get_backlight (GnomeRROutput *output, GError **error)
{
guint now = -1;
unsigned long nitems;
unsigned long bytes_after;
guint *prop;
Atom atom;
Atom actual_type;
int actual_format;
gint retval;
g_return_val_if_fail (output != NULL, -1);
gdk_error_trap_push ();
atom = XInternAtom (DISPLAY (output), "BACKLIGHT", FALSE);
retval = XRRGetOutputProperty (DISPLAY (output), output->id, atom,
0, 4, False, False, None,
&actual_type, &actual_format,
&nitems, &bytes_after, ((unsigned char **)&prop));
gdk_flush ();
if (gdk_error_trap_pop ())
{
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_UNKNOWN,
"unhandled X error while getting the range of backlight values");
goto out;
}
if (retval != Success) {
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_RANDR_ERROR,
"could not get the range of backlight values");
goto out;
}
if (actual_type == XA_INTEGER &&
nitems == 1 &&
actual_format == 32)
{
memcpy (&now, prop, sizeof (guint));
}
else
{
g_set_error (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_RANDR_ERROR,
"failed to get correct property type, got %lu,%i",
nitems, actual_format);
}
out:
XFree (prop);
return now;
}
/**
* gnome_rr_output_set_backlight:
* @value: the absolute value which is min >= this <= max
*
* Returns: %TRUE for success
*/
gboolean
gnome_rr_output_set_backlight (GnomeRROutput *output, gint value, GError **error)
{
gboolean ret = FALSE;
Atom atom;
g_return_val_if_fail (output != NULL, FALSE);
/* check this is sane */
if (value < output->backlight_min ||
value > output->backlight_max)
{
g_set_error (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_BOUNDS_ERROR,
"out of brightness range: %i, has to be %i -> %i",
value,
output->backlight_max, output->backlight_min);
goto out;
}
/* don't abort on error */
gdk_error_trap_push ();
atom = XInternAtom (DISPLAY (output), "BACKLIGHT", FALSE);
XRRChangeOutputProperty (DISPLAY (output), output->id, atom,
XA_INTEGER, 32, PropModeReplace,
(unsigned char *) &value, 1);
if (gdk_error_trap_pop ())
{
g_set_error_literal (error,
GNOME_RR_ERROR,
GNOME_RR_ERROR_UNKNOWN,
"unhandled X error while setting the backlight values");
goto out;
}
/* we assume this succeeded as there's no return value */
ret = TRUE;
out:
return ret;
}
/**
* gnome_rr_screen_get_output_by_name:
*
* Returns: (transfer none): the output identified by @name
*/
GnomeRROutput *
gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen,
const char *name)
{
int i;
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), NULL);
g_return_val_if_fail (screen->priv->info != NULL, NULL);
for (i = 0; screen->priv->info->outputs[i] != NULL; ++i)
{
GnomeRROutput *output = screen->priv->info->outputs[i];
if (strcmp (output->name, name) == 0)
return output;
}
return NULL;
}
GnomeRRCrtc *
gnome_rr_output_get_crtc (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, NULL);
return output->current_crtc;
}
/* Returns NULL if the ConnectorType property is not available */
const char *
gnome_rr_output_get_connector_type (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, NULL);
return output->connector_type;
}
gboolean
_gnome_rr_output_name_is_laptop (const char *name)
{
if (!name)
return FALSE;
if (strstr (name, "lvds") || /* Most drivers use an "LVDS" prefix... */
strstr (name, "LVDS") ||
strstr (name, "Lvds") ||
strstr (name, "LCD") || /* ... but fglrx uses "LCD" in some versions. Shoot me now, kthxbye. */
strstr (name, "eDP") || /* eDP is for internal laptop panel connections */
strstr (name, "default")) /* Finally, NVidia and all others that don't bother to do RANDR properly */
return TRUE;
return FALSE;
}
gboolean
gnome_rr_output_is_laptop (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, FALSE);
if (!output->connected)
return FALSE;
/* The ConnectorType property is present in RANDR 1.3 and greater */
if (g_strcmp0 (output->connector_type, GNOME_RR_CONNECTOR_TYPE_PANEL) == 0)
return TRUE;
/* Older versions of RANDR - this is a best guess, as @#$% RANDR doesn't have standard output names,
* so drivers can use whatever they like.
*/
if (_gnome_rr_output_name_is_laptop (output->name))
return TRUE;
return FALSE;
}
GnomeRRMode *
gnome_rr_output_get_current_mode (GnomeRROutput *output)
{
GnomeRRCrtc *crtc;
g_return_val_if_fail (output != NULL, NULL);
if ((crtc = gnome_rr_output_get_crtc (output)))
return gnome_rr_crtc_get_current_mode (crtc);
return NULL;
}
void
gnome_rr_output_get_position (GnomeRROutput *output,
int *x,
int *y)
{
GnomeRRCrtc *crtc;
g_return_if_fail (output != NULL);
if ((crtc = gnome_rr_output_get_crtc (output)))
gnome_rr_crtc_get_position (crtc, x, y);
}
const char *
gnome_rr_output_get_name (GnomeRROutput *output)
{
g_assert (output != NULL);
return output->name;
}
int
gnome_rr_output_get_width_mm (GnomeRROutput *output)
{
g_assert (output != NULL);
return output->width_mm;
}
int
gnome_rr_output_get_height_mm (GnomeRROutput *output)
{
g_assert (output != NULL);
return output->height_mm;
}
GnomeRRMode *
gnome_rr_output_get_preferred_mode (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, NULL);
if (output->n_preferred)
return output->modes[0];
return NULL;
}
GnomeRRMode **
gnome_rr_output_list_modes (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, NULL);
return output->modes;
}
gboolean
gnome_rr_output_is_connected (GnomeRROutput *output)
{
g_return_val_if_fail (output != NULL, FALSE);
return output->connected;
}
gboolean
gnome_rr_output_supports_mode (GnomeRROutput *output,
GnomeRRMode *mode)
{
int i;
g_return_val_if_fail (output != NULL, FALSE);
g_return_val_if_fail (mode != NULL, FALSE);
for (i = 0; output->modes[i] != NULL; ++i)
{
if (output->modes[i] == mode)
return TRUE;
}
return FALSE;
}
gboolean
gnome_rr_output_can_clone (GnomeRROutput *output,
GnomeRROutput *clone)
{
int i;
g_return_val_if_fail (output != NULL, FALSE);
g_return_val_if_fail (clone != NULL, FALSE);
for (i = 0; output->clones[i] != NULL; ++i)
{
if (output->clones[i] == clone)
return TRUE;
}
return FALSE;
}
gboolean
gnome_rr_output_get_is_primary (GnomeRROutput *output)
{
return output->info->primary == output->id;
}
void
gnome_rr_screen_set_primary_output (GnomeRRScreen *screen,
GnomeRROutput *output)
{
GnomeRRScreenPrivate *priv;
RROutput id;
g_return_if_fail (GNOME_IS_RR_SCREEN (screen));
priv = screen->priv;
if (output)
id = output->id;
else
id = None;
if (SERVERS_RANDR_IS_AT_LEAST_1_3 (priv))
XRRSetOutputPrimary (priv->xdisplay, priv->xroot, id);
}
/* GnomeRRCrtc */
typedef struct
{
Rotation xrot;
GnomeRRRotation rot;
} RotationMap;
static const RotationMap rotation_map[] =
{
{ RR_Rotate_0, GNOME_RR_ROTATION_0 },
{ RR_Rotate_90, GNOME_RR_ROTATION_90 },
{ RR_Rotate_180, GNOME_RR_ROTATION_180 },
{ RR_Rotate_270, GNOME_RR_ROTATION_270 },
{ RR_Reflect_X, GNOME_RR_REFLECT_X },
{ RR_Reflect_Y, GNOME_RR_REFLECT_Y },
};
static GnomeRRRotation
gnome_rr_rotation_from_xrotation (Rotation r)
{
int i;
GnomeRRRotation result = 0;
for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
{
if (r & rotation_map[i].xrot)
result |= rotation_map[i].rot;
}
return result;
}
static Rotation
xrotation_from_rotation (GnomeRRRotation r)
{
int i;
Rotation result = 0;
for (i = 0; i < G_N_ELEMENTS (rotation_map); ++i)
{
if (r & rotation_map[i].rot)
result |= rotation_map[i].xrot;
}
return result;
}
static void
set_crtc_scale (GnomeRRCrtc *crtc,
GnomeRRMode *mode,
float scale,
guint global_scale)
{
gchar *filter;
float real_scale;
int looks_like_w, looks_like_h;
real_scale = global_scale / scale;
looks_like_w = 0;
looks_like_h = 0;
if (mode != NULL)
{
looks_like_w = gnome_rr_mode_get_width (mode) * real_scale / global_scale;
looks_like_h = gnome_rr_mode_get_height (mode) * real_scale / global_scale;
}
// Fractional scales use bilinear, doubling/halving can use nearest for better quality.
if (real_scale == 0.5 || real_scale == 1.0)
{
filter = g_strdup ("nearest");
}
else
{
filter = g_strdup ("bilinear");
}
g_debug ("\n\n(xid: %lu) Transforming based on:\n"
"global ui scale: %d\n"
"requested logical scale: %.2f\n"
"requested logical size: %dx%d\n"
"xrandr transform value: %.2f (%d)\n"
"scaling method: %s",
crtc->id,
global_scale, scale,
looks_like_w, looks_like_h,
real_scale, XDoubleToFixed (real_scale),
filter);
XTransform transform = {{
{ XDoubleToFixed (real_scale), 0 , 0 },
{ 0 , XDoubleToFixed (real_scale), 0 },
{ 0 , 0 , XDoubleToFixed (1.0) },
}};
XRRSetCrtcTransform (DISPLAY (crtc), crtc->id,
&transform,
filter,
NULL, 0);
}
gboolean
gnome_rr_crtc_set_config_with_time (GnomeRRCrtc *crtc,
guint32 timestamp,
int x,
int y,
GnomeRRMode *mode,
GnomeRRRotation rotation,
GnomeRROutput **outputs,
int n_outputs,
float scale,
guint global_scale,
GError **error)
{
ScreenInfo *info;
GArray *output_ids;
Status status;
gboolean result;
int i;
g_return_val_if_fail (crtc != NULL, FALSE);
g_return_val_if_fail (mode != NULL || outputs == NULL || n_outputs == 0, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
info = crtc->info;
if (mode)
{
if (x + mode->width > info->max_width || y + mode->height > info->max_height)
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR,
/* Translators: the "position", "size", and "maximum"
* words here are not keywords; please translate them
* as usual. A CRTC is a CRT Controller (this is X terminology) */
_("requested position/size for CRTC %d is outside the allowed limit: "
"position=(%d, %d), size=(%d, %d), maximum=(%d, %d)"),
(int) crtc->id,
x, y,
mode->width, mode->height,
info->max_width, info->max_height);
return FALSE;
}
}
output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput));
if (outputs)
{
for (i = 0; i < n_outputs; ++i)
g_array_append_val (output_ids, outputs[i]->id);
}
gdk_error_trap_push ();
set_crtc_scale (crtc, mode, scale, global_scale);
status = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id,
timestamp,
x, y,
mode ? mode->id : None,
xrotation_from_rotation (rotation),
(RROutput *)output_ids->data,
output_ids->len);
g_array_free (output_ids, TRUE);
if (gdk_error_trap_pop () || status != RRSetConfigSuccess) {
/* Translators: CRTC is a CRT Controller (this is X terminology).
* It is *very* unlikely that you'll ever get this error, so it is
* only listed for completeness. */
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
_("could not set the configuration for CRTC %d"),
(int) crtc->id);
return FALSE;
} else {
result = TRUE;
}
return result;
}
GnomeRRMode *
gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc)
{
g_return_val_if_fail (crtc != NULL, NULL);
return crtc->current_mode;
}
guint32
gnome_rr_crtc_get_id (GnomeRRCrtc *crtc)
{
g_return_val_if_fail (crtc != NULL, 0);
return crtc->id;
}
gboolean
gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc,
GnomeRROutput *output)
{
int i;
g_return_val_if_fail (crtc != NULL, FALSE);
g_return_val_if_fail (output != NULL, FALSE);
for (i = 0; crtc->possible_outputs[i] != NULL; ++i)
{
if (crtc->possible_outputs[i] == output)
return TRUE;
}
return FALSE;
}
/* FIXME: merge with get_mode()? */
void
gnome_rr_crtc_get_position (GnomeRRCrtc *crtc,
int *x,
int *y)
{
g_return_if_fail (crtc != NULL);
if (x)
*x = crtc->x;
if (y)
*y = crtc->y;
}
float
gnome_rr_crtc_get_scale (GnomeRRCrtc *crtc)
{
g_return_val_if_fail (crtc != NULL, MINIMUM_LOGICAL_SCALE_FACTOR);
return crtc->scale;
}
/* FIXME: merge with get_mode()? */
GnomeRRRotation
gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc)
{
g_assert(crtc != NULL);
return crtc->current_rotation;
}
GnomeRRRotation
gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc)
{
g_assert(crtc != NULL);
return crtc->rotations;
}
gboolean
gnome_rr_crtc_supports_rotation (GnomeRRCrtc * crtc,
GnomeRRRotation rotation)
{
g_return_val_if_fail (crtc != NULL, FALSE);
return (crtc->rotations & rotation);
}
static GnomeRRCrtc *
crtc_new (ScreenInfo *info, RROutput id)
{
GnomeRRCrtc *crtc = g_slice_new0 (GnomeRRCrtc);
crtc->id = id;
crtc->info = info;
return crtc;
}
static GnomeRRCrtc *
crtc_copy (const GnomeRRCrtc *from)
{
GnomeRROutput **p_output;
GPtrArray *array;
GnomeRRCrtc *to = g_slice_new0 (GnomeRRCrtc);
to->info = from->info;
to->id = from->id;
to->current_mode = from->current_mode;
to->x = from->x;
to->y = from->y;
to->current_rotation = from->current_rotation;
to->rotations = from->rotations;
to->gamma_size = from->gamma_size;
array = g_ptr_array_new ();
for (p_output = from->current_outputs; *p_output != NULL; p_output++)
{
g_ptr_array_add (array, *p_output);
}
to->current_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
array = g_ptr_array_new ();
for (p_output = from->possible_outputs; *p_output != NULL; p_output++)
{
g_ptr_array_add (array, *p_output);
}
to->possible_outputs = (GnomeRROutput**) g_ptr_array_free (array, FALSE);
return to;
}
static float
scale_from_transformation (XRRCrtcTransformAttributes *transformation)
{
XTransform *xt;
float scale;
if (!transformation)
return 1.0f;
xt = &transformation->currentTransform;
if (xt->matrix[0][0] == xt->matrix[1][1])
scale = XFixedToDouble (xt->matrix[0][0]);
else
scale = XFixedToDouble (xt->matrix[0][0] + xt->matrix[1][1]) / 2.0;
return 1.0f / scale;
}
static float
get_transform_scale (GnomeRRCrtc *crtc)
{
XRRCrtcTransformAttributes *transform_attributes;
float ret;
if (!XRRGetCrtcTransform (DISPLAY (crtc), crtc->id, &transform_attributes))
{
transform_attributes = NULL;
}
ret = scale_from_transformation (transform_attributes);
XFree (transform_attributes);
return ret;
}
guint
gnome_rr_screen_get_global_scale (GnomeRRScreen *screen)
{
GdkScreen *gdkscreen;
GValue value = G_VALUE_INIT;
gint window_scale = 1;
gdkscreen = gdk_screen_get_default ();
g_value_init (&value, G_TYPE_INT);
if (gdk_screen_get_setting (gdkscreen, "gdk-window-scaling-factor", &value))
{
window_scale = g_value_get_int (&value);
}
return (guint) CLAMP (window_scale, MINIMUM_GLOBAL_SCALE_FACTOR, MAXIMUM_GLOBAL_SCALE_FACTOR);
}
guint
gnome_rr_screen_get_global_scale_setting (GnomeRRScreen *screen)
{
guint scale_factor;
scale_factor = g_settings_get_uint (screen->priv->interface_settings,
GLOBAL_SCALE_FACTOR_KEY);
return scale_factor;
}
void
gnome_rr_screen_set_global_scale_setting (GnomeRRScreen *screen,
guint scale_factor)
{
g_settings_set_uint (screen->priv->interface_settings,
GLOBAL_SCALE_FACTOR_KEY,
scale_factor);
}
static float
get_crtc_scale (GnomeRRCrtc *crtc)
{
return gnome_rr_screen_get_global_scale (NULL) * get_transform_scale (crtc);
}
static gboolean
crtc_initialize (GnomeRRCrtc *crtc,
XRRScreenResources *res,
GError **error)
{
XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id);
GPtrArray *a;
int i;
#if 0
g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp);
#endif
if (!info)
{
/* FIXME: We need to reaquire the screen resources */
/* FIXME: can we actually catch BadRRCrtc, and does it make sense to emit that? */
/* Translators: CRTC is a CRT Controller (this is X terminology).
* It is *very* unlikely that you'll ever get this error, so it is
* only listed for completeness. */
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR,
_("could not get information about CRTC %d"),
(int) crtc->id);
return FALSE;
}
/* GnomeRRMode */
crtc->current_mode = mode_by_id (crtc->info, info->mode);
crtc->x = info->x;
crtc->y = info->y;
/* Current outputs */
a = g_ptr_array_new ();
for (i = 0; i < info->noutput; ++i)
{
GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->outputs[i]);
if (output)
g_ptr_array_add (a, output);
}
g_ptr_array_add (a, NULL);
crtc->current_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
/* Possible outputs */
a = g_ptr_array_new ();
for (i = 0; i < info->npossible; ++i)
{
GnomeRROutput *output = gnome_rr_output_by_id (crtc->info, info->possible[i]);
if (output)
g_ptr_array_add (a, output);
}
g_ptr_array_add (a, NULL);
crtc->possible_outputs = (GnomeRROutput **)g_ptr_array_free (a, FALSE);
/* Rotations */
crtc->current_rotation = gnome_rr_rotation_from_xrotation (info->rotation);
crtc->rotations = gnome_rr_rotation_from_xrotation (info->rotations);
crtc->scale = get_crtc_scale (crtc);
XRRFreeCrtcInfo (info);
/* get an store gamma size */
crtc->gamma_size = XRRGetCrtcGammaSize (DISPLAY (crtc), crtc->id);
g_debug ("Initialized GnomeCrtc: %d, at %d, %d, with a scale factor of %.2f (%u global scale)",
(int) crtc->id, crtc->x, crtc->y, crtc->scale, gnome_rr_screen_get_global_scale (NULL));
return TRUE;
}
static void
crtc_free (GnomeRRCrtc *crtc)
{
g_free (crtc->current_outputs);
g_free (crtc->possible_outputs);
g_slice_free (GnomeRRCrtc, crtc);
}
/* GnomeRRMode */
static GnomeRRMode *
mode_new (ScreenInfo *info, RRMode id)
{
GnomeRRMode *mode = g_slice_new0 (GnomeRRMode);
mode->id = id;
mode->info = info;
return mode;
}
guint32
gnome_rr_mode_get_id (GnomeRRMode *mode)
{
g_return_val_if_fail (mode != NULL, 0);
return mode->id;
}
guint
gnome_rr_mode_get_width (GnomeRRMode *mode)
{
g_return_val_if_fail (mode != NULL, 0);
return mode->width;
}
guint
gnome_rr_mode_get_height (GnomeRRMode *mode)
{
g_return_val_if_fail (mode != NULL, 0);
return mode->height;
}
int
gnome_rr_mode_get_freq (GnomeRRMode *mode)
{
g_return_val_if_fail (mode != NULL, 0);
return (mode->freq) / 1000;
}
double
gnome_rr_mode_get_freq_f (GnomeRRMode *mode)
{
g_return_val_if_fail (mode != NULL, 0.0);
return (mode->freq) / 1000.0;
}
void
gnome_rr_mode_get_flags (GnomeRRMode *mode,
gboolean *doublescan,
gboolean *interlaced,
gboolean *vsync)
{
g_return_if_fail (mode != NULL);
if (doublescan)
*doublescan = mode->doublescan;
if (interlaced)
*interlaced = mode->interlaced;
if (vsync)
*vsync = mode->vsync;
}
static void
mode_initialize (GnomeRRMode *mode, XRRModeInfo *info)
{
g_assert (mode != NULL);
g_assert (info != NULL);
mode->name = g_strdup (info->name);
mode->width = info->width;
mode->height = info->height;
mode->freq = info->dotClock / ((float)info->hTotal * info->vTotal) * 1000;
mode->doublescan = (info->modeFlags & RR_DoubleScan);
mode->interlaced = (info->modeFlags & RR_Interlace);
mode->vsync = (info->modeFlags & RR_VSyncPositive);
}
static GnomeRRMode *
mode_copy (const GnomeRRMode *from)
{
GnomeRRMode *to = g_slice_new0 (GnomeRRMode);
to->id = from->id;
to->info = from->info;
to->name = g_strdup (from->name);
to->width = from->width;
to->height = from->height;
to->freq = from->freq;
return to;
}
static void
mode_free (GnomeRRMode *mode)
{
g_free (mode->name);
g_slice_free (GnomeRRMode, mode);
}
void
gnome_rr_crtc_set_gamma (GnomeRRCrtc *crtc, int size,
unsigned short *red,
unsigned short *green,
unsigned short *blue)
{
int copy_size;
XRRCrtcGamma *gamma;
g_return_if_fail (crtc != NULL);
g_return_if_fail (red != NULL);
g_return_if_fail (green != NULL);
g_return_if_fail (blue != NULL);
if (size != crtc->gamma_size)
return;
gamma = XRRAllocGamma (crtc->gamma_size);
copy_size = crtc->gamma_size * sizeof (unsigned short);
memcpy (gamma->red, red, copy_size);
memcpy (gamma->green, green, copy_size);
memcpy (gamma->blue, blue, copy_size);
XRRSetCrtcGamma (DISPLAY (crtc), crtc->id, gamma);
XRRFreeGamma (gamma);
}
gboolean
gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc, int *size,
unsigned short **red, unsigned short **green,
unsigned short **blue)
{
int copy_size;
unsigned short *r, *g, *b;
XRRCrtcGamma *gamma;
g_return_val_if_fail (crtc != NULL, FALSE);
gamma = XRRGetCrtcGamma (DISPLAY (crtc), crtc->id);
if (!gamma)
return FALSE;
copy_size = crtc->gamma_size * sizeof (unsigned short);
if (red) {
r = g_new0 (unsigned short, crtc->gamma_size);
memcpy (r, gamma->red, copy_size);
*red = r;
}
if (green) {
g = g_new0 (unsigned short, crtc->gamma_size);
memcpy (g, gamma->green, copy_size);
*green = g;
}
if (blue) {
b = g_new0 (unsigned short, crtc->gamma_size);
memcpy (b, gamma->blue, copy_size);
*blue = b;
}
XRRFreeGamma (gamma);
if (size)
*size = crtc->gamma_size;
return TRUE;
}
#define SCALE_FACTORS_PER_INTEGER 4
#define SCALE_FACTORS_STEPS (1.0 / (float) SCALE_FACTORS_PER_INTEGER)
/* The minimum resolution at which we turn on a window-scale of 2 */
#define HIDPI_LIMIT 192
/* The minimum screen height at which we automatically turn on a window
*-scale of 2; below this there just isn't enough vertical real estate for GNOME
* apps to work, and it's better to just be tiny */
#define MINIMUM_REAL_VERTICAL_PIXELS 1400
/* The minimum logical height we'll allow - any smaller than this is
* not very usable and can make Cinnamon behave unpredictably. */
#define MINIMUM_LOGICAL_VERTICAL_PIXELS 700
static gboolean
is_logical_size_large_enough (int width,
int height)
{
return height >= MINIMUM_LOGICAL_VERTICAL_PIXELS;
}
static gboolean
is_scale_valid_for_size (float width,
float height,
float scale)
{
return scale >= MINIMUM_LOGICAL_SCALE_FACTOR &&
scale <= MAXIMUM_LOGICAL_SCALE_FACTOR &&
is_logical_size_large_enough (floorf (width/scale), floorf (height/scale));
}
static float
get_closest_scale_factor_for_resolution (float width,
float height,
float scale)
{
unsigned int i, j;
float scaled_h;
float scaled_w;
float best_scale;
int base_scaled_w;
gboolean found_one;
best_scale = 0;
if (!is_scale_valid_for_size (width, height, scale))
goto out;
if (fmodf (width, scale) == 0.0 && fmodf (height, scale) == 0.0)
return scale;
i = 0;
found_one = FALSE;
base_scaled_w = floorf (width / scale);
do
{
for (j = 0; j < 2; j++)
{
float current_scale;
int offset = i * (j ? 1 : -1);
scaled_w = base_scaled_w + offset;
current_scale = width / scaled_w;
scaled_h = height / current_scale;
if (current_scale >= scale + SCALE_FACTORS_STEPS ||
current_scale <= scale - SCALE_FACTORS_STEPS ||
current_scale < MINIMUM_LOGICAL_SCALE_FACTOR ||
current_scale > MAXIMUM_LOGICAL_SCALE_FACTOR)
{
goto out;
}
if (floorf (scaled_h) == scaled_h)
{
found_one = TRUE;
if (fabsf (current_scale - scale) < fabsf (best_scale - scale))
best_scale = current_scale;
}
}
i++;
}
while (!found_one);
out:
return best_scale;
}
float *
gnome_rr_screen_calculate_supported_scales (GnomeRRScreen *screen,
int width,
int height,
int *n_supported_scales)
{
unsigned int i, j;
GArray *supported_scales;
supported_scales = g_array_new (FALSE, FALSE, sizeof (float));
for (i = floorf (MINIMUM_LOGICAL_SCALE_FACTOR);
i <= ceilf (MAXIMUM_LOGICAL_SCALE_FACTOR);
i++)
{
for (j = 0; j < SCALE_FACTORS_PER_INTEGER; j++)
{
float scale;
float scale_value = i + j * SCALE_FACTORS_STEPS;
scale = get_closest_scale_factor_for_resolution (width,
height,
scale_value);
if (scale > 0.0f)
g_array_append_val (supported_scales, scale);
}
}
if (supported_scales->len == 0)
{
float fallback_scale;
fallback_scale = MINIMUM_LOGICAL_SCALE_FACTOR;
g_array_append_val (supported_scales, fallback_scale);
}
*n_supported_scales = supported_scales->len;
return (float *) g_array_free (supported_scales, FALSE);
}
static void
get_real_monitor_size (GnomeRRScreen *screen,
GdkMonitor *monitor,
gint monitor_index,
gint *width,
gint *height)
{
GnomeRROutput **outputs;
XID output_id;
gint i;
*width = 0;
*height = 0;
output_id = gdk_x11_screen_get_monitor_output (gdk_screen_get_default (), monitor_index);
outputs = gnome_rr_screen_list_outputs (screen);
for (i = 0; outputs[i] != NULL; i++)
{
GnomeRROutput *output = outputs[i];
if (gnome_rr_output_get_id (output) == output_id)
{
GnomeRRMode *mode = gnome_rr_output_get_current_mode (output);
if (mode == NULL)
{
mode = gnome_rr_output_get_preferred_mode (output);
}
if (mode != NULL)
{
*width = gnome_rr_mode_get_width (mode);
*height = gnome_rr_mode_get_height (mode);
}
break;
}
}
if (*width == 0 || *height == 0)
{
GdkRectangle rect;
gdk_monitor_get_geometry (monitor, &rect);
*width = rect.width;
*height = rect.height;
}
}
guint
gnome_rr_screen_calculate_best_global_scale (GnomeRRScreen *screen,
gint index)
{
guint window_scale;
GdkDisplay *display;
GdkMonitor *monitor;
int width_mm, height_mm;
int monitor_scale;
double dpi_x, dpi_y;
int real_width, real_height;
display = gdk_display_get_default ();
if (index == -1)
{
monitor = gdk_display_get_primary_monitor (display);
index = 0;
}
else
{
if ((index >= 0) && (index < gdk_display_get_n_monitors (display)))
{
monitor = gdk_display_get_monitor (display, index);
}
else
{
g_warning ("Invalid monitor index provided (%d)", index);
return 1;
}
}
/* GdkMonitor geometry is affected by any active current transformation/scaling!!!!
* So if I have 2x global scale, and a transform on a 1080 monitor down to 540, that's
* what gdk_monitor_get_geometry() returns. We actually have to get the dimensions from
* the current RRMode for the given monitor.
*/
get_real_monitor_size (screen, monitor, index, &real_width, &real_height);
width_mm = gdk_monitor_get_width_mm (monitor);
height_mm = gdk_monitor_get_height_mm (monitor);
monitor_scale = gdk_monitor_get_scale_factor (monitor);
window_scale = 1;
g_debug ("Calculating best global scale for monitor %d. Physical size: %dmm x %dmm,"
" REAL pixel size: %d x %d. Current global scale: %d, reported monitor scale: %d",
index, width_mm, height_mm, real_width, real_height, gnome_rr_screen_get_global_scale (NULL), monitor_scale);
if (real_height < MINIMUM_REAL_VERTICAL_PIXELS)
{
g_debug ("REAL height of %d for monitor %d is less than %d, so the recommended scale will be 1", real_height, index, MINIMUM_REAL_VERTICAL_PIXELS);
goto out;
}
/* Some monitors/TV encode the aspect ratio (16/9 or 16/10) instead of the physical size */
if ((width_mm == 160 && height_mm == 90) ||
(width_mm == 160 && height_mm == 100) ||
(width_mm == 16 && height_mm == 9) ||
(width_mm == 16 && height_mm == 10) ||
(width_mm == 0 || height_mm == 0))
{
g_debug ("Aspect ratio instead of physical dimensions were encoded as the physical size, or the physical"
" size was not set. Unable to reliably calculate the recommended scale, returning 1");
goto out;
}
if (width_mm > 0 && height_mm > 0) {
dpi_x = (double) real_width / (width_mm / 25.4);
dpi_y = (double) real_height / (height_mm / 25.4);
/* We don't completely trust these values so both must be high, and never pick higher ratio than
2 automatically */
if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT)
{
g_debug ("The REAL monitor DPI of %.1f x %.1f exceeds the cutoff of %d x %d, recommended scale will be 2",
dpi_x, dpi_y, HIDPI_LIMIT, HIDPI_LIMIT);
window_scale = 2;
}
else
{
g_debug ("The REAL monitor DPI of %.1f x %.1f does not meet the cutoff of %d x %d, recommended scale will be 1",
dpi_x, dpi_y, HIDPI_LIMIT, HIDPI_LIMIT);
}
}
out:
return window_scale;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/test-xkb-info.c 0000664 0001750 0001750 00000003065 14167325242 022524 0 ustar fabio fabio #include
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include
int
main (int argc, char **argv)
{
GnomeXkbInfo *info;
GList *layouts, *l;
GList *option_groups, *g;
GList *options, *o;
gtk_init (&argc, &argv);
info = gnome_xkb_info_new ();
layouts = gnome_xkb_info_get_all_layouts (info);
for (l = layouts; l != NULL; l = l->next) {
const char *id = l->data;
const char *display_name;
const char *short_name;
const char *xkb_layout;
const char *xkb_variant;
if (gnome_xkb_info_get_layout_info (info, id,
&display_name,
&short_name,
&xkb_layout,
&xkb_variant) == FALSE) {
g_warning ("Failed to get info for layout '%s'", id);
} else {
g_print ("id: %s\n", id);
g_print ("\tdisplay name: %s\n", display_name);
g_print ("\tshort name: %s\n", short_name);
g_print ("\txkb layout: %s\n", xkb_layout);
g_print ("\txkb variant: %s\n", xkb_variant);
}
}
g_list_free (layouts);
option_groups = gnome_xkb_info_get_all_option_groups (info);
for (g = option_groups; g != NULL; g = g->next) {
const char *group_id = g->data;
g_print ("\noption group: %s\n", group_id);
options = gnome_xkb_info_get_options_for_group (info, group_id);
for (o = options; o != NULL; o = o->next) {
const char *id = o->data;
g_print ("id: %s\n", id);
g_print ("\tdescription: %s\n",
gnome_xkb_info_description_for_option (info,
group_id,
id));
}
g_list_free (options);
}
g_list_free (option_groups);
g_object_unref (info);
return 0;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-wall-clock.c 0000664 0001750 0001750 00000044142 14167325242 023166 0 ustar fabio fabio /* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
* gnome-wall-clock.h - monitors TZ setting files and signals changes
*
* Copyright (C) 2010 Red Hat, Inc.
* Copyright (C) 2011 Red Hat, Inc.
*
* This program 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.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Author: Colin Walters
*/
#include "config.h"
#include
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-wall-clock.h"
#include "gnome-datetime-source.h"
typedef enum
{
INTERVAL_SECOND,
INTERVAL_MINUTE,
} ClockInterval;
struct _GnomeWallClockPrivate {
guint clock_update_id;
char *clock_string;
const char *default_time_format;
const char *default_date_format;
char *format_string;
gboolean custom_format;
GFileMonitor *tz_monitor;
GSettings *desktop_settings;
ClockInterval update_interval;
};
enum {
PROP_0,
PROP_CLOCK,
PROP_FORMAT_STRING,
};
G_DEFINE_TYPE (GnomeWallClock, gnome_wall_clock, G_TYPE_OBJECT);
/* Date/Time format defaults - options are stored in org.cinnamon.desktop.interface keys.
* The wall clock is used variously in Cinnamon applets and desklets, as well as
* cinnamon-screensaver's default lock screen. */
/* Default date format (typically matching date portion of WITH_DATE_* defaults.)
* Currently used by cinnamon-screensaver default clock */
#define DATE_ONLY (_("%A, %B %e"))
/* Defaut date/time format when show-date, show-seconds, use-24h are set */
#define WITH_DATE_24H_SECONDS (_("%A %B %e, %R:%S"))
/* Default date/time format when show-date, show-seconds are set */
#define WITH_DATE_12H_SECONDS (_("%A %B %e, %l:%M:%S %p"))
/* Default date/time format when show-date, use-24h are set */
#define WITH_DATE_24H (_("%A %B %e, %R"))
/* Default date/time format when just show-date is set */
#define WITH_DATE_12H (_("%A %B %e, %l:%M %p"))
/* Default date/time format when show-seconds, use-24h are set */
#define NO_DATE_24H_SECONDS (_("%R:%S"))
/* Default date/time format when just show-seconds is set */
#define NO_DATE_12H_SECONDS (_("%l:%M:%S %p"))
/* Default date/time format when just use-24h is set */
#define NO_DATE_24H (_("%R"))
/* Default date/time format with no options are set */
#define NO_DATE_12H (_("%l:%M %p"))
#define NO_DATE ("")
/************/
static void update_format_string (GnomeWallClock *self, const gchar *format_string);
static gboolean update_clock (gpointer data);
static void on_schema_change (GSettings *schema,
const char *key,
gpointer user_data);
static void on_tz_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent *event,
gpointer user_data);
static void
gnome_wall_clock_init (GnomeWallClock *self)
{
GFile *tz;
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_WALL_CLOCK, GnomeWallClockPrivate);
self->priv->clock_string = NULL;
tz = g_file_new_for_path ("/etc/localtime");
self->priv->tz_monitor = g_file_monitor_file (tz, 0, NULL, NULL);
g_object_unref (tz);
g_signal_connect (self->priv->tz_monitor, "changed", G_CALLBACK (on_tz_changed), self);
self->priv->desktop_settings = g_settings_new ("org.cinnamon.desktop.interface");
g_signal_connect (self->priv->desktop_settings, "changed", G_CALLBACK (on_schema_change), self);
/* A format string provided for construction will be set after gnome_wall_clock_init()
* finishes. If not provided, our internal format and interval will still be set to
* some default by this. */
gnome_wall_clock_set_format_string (self, NULL);
}
static void
gnome_wall_clock_dispose (GObject *object)
{
GnomeWallClock *self = GNOME_WALL_CLOCK (object);
if (self->priv->clock_update_id) {
g_source_remove (self->priv->clock_update_id);
self->priv->clock_update_id = 0;
}
if (self->priv->tz_monitor != NULL) {
g_object_unref (self->priv->tz_monitor);
self->priv->tz_monitor = NULL;
}
if (self->priv->desktop_settings != NULL) {
g_object_unref (self->priv->desktop_settings);
self->priv->desktop_settings = NULL;
}
G_OBJECT_CLASS (gnome_wall_clock_parent_class)->dispose (object);
}
static void
gnome_wall_clock_finalize (GObject *object)
{
GnomeWallClock *self = GNOME_WALL_CLOCK (object);
g_clear_pointer (&self->priv->clock_string, g_free);
g_clear_pointer (&self->priv->format_string, g_free);
G_OBJECT_CLASS (gnome_wall_clock_parent_class)->finalize (object);
}
static void
gnome_wall_clock_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GnomeWallClock *self = GNOME_WALL_CLOCK (gobject);
switch (prop_id)
{
case PROP_CLOCK:
g_value_set_string (value, self->priv->clock_string);
break;
case PROP_FORMAT_STRING:
g_value_set_string (value, self->priv->format_string);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gnome_wall_clock_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GnomeWallClock *self = GNOME_WALL_CLOCK (gobject);
switch (prop_id)
{
case PROP_FORMAT_STRING:
gnome_wall_clock_set_format_string (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gnome_wall_clock_class_init (GnomeWallClockClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gnome_wall_clock_get_property;
gobject_class->set_property = gnome_wall_clock_set_property;
gobject_class->dispose = gnome_wall_clock_dispose;
gobject_class->finalize = gnome_wall_clock_finalize;
/**
* GnomeWallClock:clock:
*
* A formatted string representing the current clock display.
*/
g_object_class_install_property (gobject_class,
PROP_CLOCK,
g_param_spec_string ("clock",
"",
"",
NULL,
G_PARAM_READABLE));
/**
* GnomeWallClock:format-string:
*
* If not NULL, the wall clock will format the time/date according to
* this format string. If the format string is invalid, the default string
* will be used instead.
*/
g_object_class_install_property (gobject_class,
PROP_FORMAT_STRING,
g_param_spec_string ("format-string",
"The string to format the clock to",
"The string to format the clock to",
NULL,
G_PARAM_READABLE | G_PARAM_WRITABLE));
g_type_class_add_private (gobject_class, sizeof (GnomeWallClockPrivate));
}
static void
update_format_string (GnomeWallClock *self, const gchar *format_string)
{
guint i;
gchar *old_format;
gboolean use_24h, show_date, show_seconds;
const gchar *default_format, *env_language, *env_lc_time;
static const gchar* seconds_tokens[] = {
"\%s",
"\%S",
"\%T",
"\%X",
"\%c"
};
ClockInterval new_interval = INTERVAL_MINUTE;
gchar *new_format = NULL;
/* First parse the settings and fill out our default format strings -
* Date-only, Time-only, and combined.
*/
use_24h = g_settings_get_boolean (self->priv->desktop_settings, "clock-use-24h");
show_date = g_settings_get_boolean (self->priv->desktop_settings, "clock-show-date");
show_seconds = g_settings_get_boolean (self->priv->desktop_settings, "clock-show-seconds");
/* Override LANGUAGE with the LC_TIME environment variable
* This is needed for gettext to fetch our clock format
* according to LC_TIME, and not according to the DE LANGUAGE.
*/
env_language = g_getenv("LANGUAGE");
env_lc_time = g_getenv("LC_TIME");
if (env_language != NULL && env_lc_time != NULL && env_language != env_lc_time) {
g_setenv("LANGUAGE", env_lc_time, TRUE);
}
if (use_24h) {
if (show_date) {
/* Translators: This is the time format with full date used
in 24-hour mode. */
if (show_seconds) {
default_format = WITH_DATE_24H_SECONDS;
self->priv->default_time_format = NO_DATE_24H_SECONDS;
} else {
default_format = WITH_DATE_24H;
self->priv->default_time_format = NO_DATE_24H;
}
self->priv->default_date_format = DATE_ONLY;
} else {
/* Translators: This is the time format without date used
in 24-hour mode. */
if (show_seconds) {
default_format = NO_DATE_24H_SECONDS;
self->priv->default_time_format = NO_DATE_24H_SECONDS;
} else {
default_format = NO_DATE_24H;
self->priv->default_time_format = NO_DATE_24H;
}
self->priv->default_date_format = NO_DATE;
}
} else {
if (show_date) {
/* Translators: This is a time format with full date used
for AM/PM. */
if (show_seconds) {
default_format = WITH_DATE_12H_SECONDS;
self->priv->default_time_format = NO_DATE_12H_SECONDS;
} else {
default_format = WITH_DATE_12H;
self->priv->default_time_format = NO_DATE_12H;
}
self->priv->default_date_format = DATE_ONLY;
} else {
/* Translators: This is a time format without date used
for AM/PM. */
if (show_seconds) {
default_format = NO_DATE_12H_SECONDS;
self->priv->default_time_format = NO_DATE_12H_SECONDS;
} else {
default_format = NO_DATE_12H;
self->priv->default_time_format = NO_DATE_12H;
}
self->priv->default_date_format = NO_DATE;
}
}
/* Set back LANGUAGE the way it was before */
if (env_language != NULL && env_lc_time != NULL && env_language != env_lc_time) {
g_setenv("LANGUAGE", env_language, TRUE);
}
/* Then look at our custom format if we received one, and test it out.
* If it's ok, it's used, otherwise we use the default format */
if (format_string != NULL) {
GDateTime *test_now;
gchar *str;
test_now = g_date_time_new_now_local ();
str = g_date_time_format (test_now, format_string);
if (str != NULL) {
new_format = g_strdup (format_string);
}
g_date_time_unref (test_now);
g_clear_pointer (&str, g_free);
}
if (new_format == NULL) {
new_format = g_strdup (default_format);
}
/* Now determine whether we need seconds ticking or not */
for (i = 0; i < G_N_ELEMENTS (seconds_tokens); i++) {
if (g_strstr_len (new_format, -1, seconds_tokens[i])) {
new_interval = INTERVAL_SECOND;
break;
}
}
old_format = self->priv->format_string;
self->priv->format_string = new_format;
self->priv->update_interval = new_interval;
g_free (old_format);
g_debug ("Updated format string and interval. '%s', update every %s.",
new_format,
new_interval == 1 ? "minute" : "second");
}
static gboolean
update_clock (gpointer data)
{
GnomeWallClock *self = data;
GSource *source;
GDateTime *now;
GDateTime *expiry;
now = g_date_time_new_now_local ();
/* Setup the next update */
if (self->priv->update_interval == INTERVAL_SECOND) {
expiry = g_date_time_add_seconds (now, 1);
} else {
expiry = g_date_time_add_seconds (now, 60 - g_date_time_get_second (now));
}
if (self->priv->clock_update_id) {
g_source_remove (self->priv->clock_update_id);
self->priv->clock_update_id = 0;
}
source = _gnome_datetime_source_new (now, expiry, TRUE);
g_source_set_priority (source, G_PRIORITY_HIGH);
g_source_set_callback (source, update_clock, self, NULL);
self->priv->clock_update_id = g_source_attach (source, NULL);
g_source_unref (source);
/* Update the clock and notify */
g_free (self->priv->clock_string);
self->priv->clock_string = g_date_time_format (now, self->priv->format_string);
g_date_time_unref (now);
g_date_time_unref (expiry);
g_debug ("Sending clock notify: '%s'", self->priv->clock_string);
g_object_notify ((GObject *) self, "clock");
return FALSE;
}
static void
on_schema_change (GSettings *schema,
const char *key,
gpointer user_data)
{
GnomeWallClock *self = GNOME_WALL_CLOCK (user_data);
g_debug ("Updating clock because schema changed");
update_format_string (self, self->priv->custom_format ? self->priv->format_string : NULL);
update_clock (self);
}
static void
on_tz_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent *event,
gpointer user_data)
{
GnomeWallClock *self = GNOME_WALL_CLOCK (user_data);
g_debug ("Updating clock because timezone changed");
update_format_string (self, self->priv->custom_format ? self->priv->format_string : NULL);
update_clock (self);
}
/**
* gnome_wall_clock_get_clock:
* @clock: The GnomeWallClock
*
* Returns a formatted date and time based on either default format
* settings, or via a custom-set format string.
*
* The returned string should be ready to be set on a label.
*
* Returns: (transfer none): The formatted date/time string.
**/
const char *
gnome_wall_clock_get_clock (GnomeWallClock *clock)
{
return clock->priv->clock_string;
}
/**
* gnome_wall_clock_get_default_time_format:
* @clock: The GnomeWallClock
*
* Returns the current time-only format based on current locale
* defaults and clock settings.
*
* Returns: (transfer none): The default time format string.
**/
const gchar *
gnome_wall_clock_get_default_time_format (GnomeWallClock *clock)
{
return clock->priv->default_time_format;
}
/**
* gnome_wall_clock_get_default_date_format:
* @clock: The GnomeWallClock
*
* Returns the current date-only format based on current locale
* defaults and clock settings.
*
* Returns: (transfer none): The default date format string.
**/
const gchar *
gnome_wall_clock_get_default_date_format (GnomeWallClock *clock)
{
return clock->priv->default_date_format;
}
/**
* gnome_wall_clock_get_clock_for_format:
* @clock: The GnomeWallClock
* @format_string: (not nullable)
*
* Returns a formatted date and time based on the provided format string.
* The returned string should be ready to be set on a label.
*
* Returns: (transfer full): The formatted date/time string, or NULL
* if there was a problem with the format string.
**/
gchar *
gnome_wall_clock_get_clock_for_format (GnomeWallClock *clock,
const gchar *format_string)
{
gchar *ret;
GDateTime *now;
g_return_val_if_fail (format_string != NULL, NULL);
now = g_date_time_new_now_local ();
ret = g_date_time_format (now, format_string);
g_date_time_unref (now);
return ret;
}
/**
* gnome_wall_clock_new:
*
* Returns a new GnomeWallClock instance
*
* Returns: A pointer to a new GnomeWallClock instance.
**/
GnomeWallClock *
gnome_wall_clock_new (void)
{
return g_object_new (GNOME_TYPE_WALL_CLOCK, NULL);
}
/**
* gnome_wall_clock_set_format_string:
* @clock: The GnomeWallClock
* @format_string: (nullable)
*
* Sets the wall clock to use the provided format string for any
* subsequent updates. Passing NULL will un-set any custom format,
* and rely on a default locale format.
*
* Any invalid format string passed will cause it to be ignored,
* and the default locale format used instead.
*
* Returns: Whether or not the format string was valid and accepted.
**/
gboolean
gnome_wall_clock_set_format_string (GnomeWallClock *clock,
const gchar *format_string)
{
gboolean ret = FALSE;
update_format_string (clock, format_string);
if (format_string != NULL) {
clock->priv->custom_format = g_strcmp0 (format_string, clock->priv->format_string) == 0;
ret = clock->priv->custom_format;
} else {
clock->priv->custom_format = FALSE;
ret = TRUE;
}
update_clock (clock);
return ret;
}
/**
* gnome_wall_clock_lctime_format:
* @clock: The GnomeWallClock
* @gettext_domain: (nullable)
* @format_string: (nullable)
*
* Returns the translation of the format string according to
* the LC_TIME locale.
*
* Returns: (transfer none): The translated format string.
**/
gchar *
gnome_wall_clock_lctime_format (const gchar * gettext_domain, const gchar * format_string)
{
const gchar *env_language, *env_lc_time;
gchar *string;
gboolean use_lctime;
/* Use LC_TIME if it's set and different than LANGUAGE */
env_language = g_getenv("LANGUAGE");
env_lc_time = g_getenv("LC_TIME");
use_lctime = (env_language != NULL) && (env_lc_time != NULL) && (g_strcmp0 (env_language, env_lc_time) != 0);
if (use_lctime) {
/* Set LANGUAGE to the LC_TIME value, so we can get the right date format via gettext */
g_setenv("LANGUAGE", env_lc_time, TRUE);
}
string = dgettext(gettext_domain, format_string);
if (use_lctime) {
/* Set back LANGUAGE the way it was before */
g_setenv("LANGUAGE", env_language, TRUE);
}
return string;
} cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-wall-clock.h 0000664 0001750 0001750 00000006062 14167325242 023172 0 ustar fabio fabio /* gnome-tz-monitor.h - fade window background between two surfaces
Copyright 2008, Red Hat, Inc.
Copyright 2011, 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: Colin Walters
*/
#ifndef __GNOME_WALL_CLOCK_H__
#define __GNOME_WALL_CLOCK_H__
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error This is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-wall-clock.h
#endif
#include
#include "cdesktop-enums.h"
G_BEGIN_DECLS
#define GNOME_TYPE_WALL_CLOCK (gnome_wall_clock_get_type ())
#define GNOME_WALL_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_WALL_CLOCK, GnomeWallClock))
#define GNOME_WALL_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_WALL_CLOCK, GnomeWallClockClass))
#define GNOME_IS_WALL_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_WALL_CLOCK))
#define GNOME_IS_WALL_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_WALL_CLOCK))
#define GNOME_WALL_CLOCK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_WALL_CLOCK, GnomeWallClockClass))
typedef struct _GnomeWallClockPrivate GnomeWallClockPrivate;
typedef struct _GnomeWallClock GnomeWallClock;
typedef struct _GnomeWallClockClass GnomeWallClockClass;
struct _GnomeWallClock
{
GObject parent_object;
GnomeWallClockPrivate *priv;
};
struct _GnomeWallClockClass
{
GObjectClass parent_class;
};
GType gnome_wall_clock_get_type (void);
const char * gnome_wall_clock_get_clock (GnomeWallClock *clock);
const gchar * gnome_wall_clock_get_default_time_format (GnomeWallClock *clock);
const gchar * gnome_wall_clock_get_default_date_format (GnomeWallClock *clock);
gchar * gnome_wall_clock_get_clock_for_format (GnomeWallClock *clock,
const gchar *format_string);
GnomeWallClock * gnome_wall_clock_new (void);
gboolean gnome_wall_clock_set_format_string (GnomeWallClock *clock,
const gchar *format_string);
gchar * gnome_wall_clock_lctime_format (const gchar * gettext_domain,
const gchar * format_string);
G_END_DECLS
#endif
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr-config.h 0000664 0001750 0001750 00000017557 14167325242 023043 0 ustar fabio fabio /* gnome-rr-config.h
* -*- c-basic-offset: 4 -*-
*
* Copyright 2007, 2008, Red Hat, Inc.
* Copyright 2010 Giovanni Campagna
*
* 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
*/
#ifndef GNOME_RR_CONFIG_H
#define GNOME_RR_CONFIG_H
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error gnome-rr-config.h is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-rr-config.h
#endif
#include
#include
#include
typedef struct GnomeRROutputInfoPrivate GnomeRROutputInfoPrivate;
typedef struct GnomeRRConfigPrivate GnomeRRConfigPrivate;
typedef struct
{
GObject parent;
/*< private >*/
GnomeRROutputInfoPrivate *priv;
} GnomeRROutputInfo;
typedef struct
{
GObjectClass parent_class;
} GnomeRROutputInfoClass;
#define GNOME_TYPE_RR_OUTPUT_INFO (gnome_rr_output_info_get_type())
#define GNOME_RR_OUTPUT_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfo))
#define GNOME_IS_RR_OUTPUT_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_OUTPUT_INFO))
#define GNOME_RR_OUTPUT_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfoClass))
#define GNOME_IS_RR_OUTPUT_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_OUTPUT_INFO))
#define GNOME_RR_OUTPUT_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_OUTPUT_INFO, GnomeRROutputInfoClass))
GType gnome_rr_output_info_get_type (void);
const char *gnome_rr_output_info_get_name (GnomeRROutputInfo *self);
gboolean gnome_rr_output_info_is_active (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_active (GnomeRROutputInfo *self, gboolean active);
void gnome_rr_output_info_get_geometry (GnomeRROutputInfo *self, int *x, int *y, int *width, int *height);
void gnome_rr_output_info_set_geometry (GnomeRROutputInfo *self, int x, int y, int width, int height);
float gnome_rr_output_info_get_scale (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_scale (GnomeRROutputInfo *self, float scale);
int gnome_rr_output_info_get_refresh_rate (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_refresh_rate (GnomeRROutputInfo *self, int rate);
double gnome_rr_output_info_get_refresh_rate_f (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_refresh_rate_f (GnomeRROutputInfo *self, double rate);
GnomeRRRotation gnome_rr_output_info_get_rotation (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_rotation (GnomeRROutputInfo *self, GnomeRRRotation rotation);
gboolean gnome_rr_output_info_is_connected (GnomeRROutputInfo *self);
void gnome_rr_output_info_get_vendor (GnomeRROutputInfo *self, gchar* vendor);
guint gnome_rr_output_info_get_product (GnomeRROutputInfo *self);
guint gnome_rr_output_info_get_serial (GnomeRROutputInfo *self);
double gnome_rr_output_info_get_aspect_ratio (GnomeRROutputInfo *self);
const char *gnome_rr_output_info_get_display_name (GnomeRROutputInfo *self);
gboolean gnome_rr_output_info_get_primary (GnomeRROutputInfo *self);
void gnome_rr_output_info_set_primary (GnomeRROutputInfo *self, gboolean primary);
int gnome_rr_output_info_get_preferred_width (GnomeRROutputInfo *self);
int gnome_rr_output_info_get_preferred_height (GnomeRROutputInfo *self);
void gnome_rr_output_info_get_flags (GnomeRROutputInfo *self,
gboolean *doublescan,
gboolean *interlaced,
gboolean *vsync);
void gnome_rr_output_info_set_flags (GnomeRROutputInfo *self,
gboolean doublescan,
gboolean interlaced,
gboolean vsync);
typedef struct
{
GObject parent;
/*< private >*/
GnomeRRConfigPrivate *priv;
} GnomeRRConfig;
typedef struct
{
GObjectClass parent_class;
} GnomeRRConfigClass;
#define GNOME_TYPE_RR_CONFIG (gnome_rr_config_get_type())
#define GNOME_RR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_RR_CONFIG, GnomeRRConfig))
#define GNOME_IS_RR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_RR_CONFIG))
#define GNOME_RR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_RR_CONFIG, GnomeRRConfigClass))
#define GNOME_IS_RR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_RR_CONFIG))
#define GNOME_RR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_RR_CONFIG, GnomeRRConfigClass))
GType gnome_rr_config_get_type (void);
GnomeRRConfig *gnome_rr_config_new_current (GnomeRRScreen *screen,
GError **error);
GnomeRRConfig *gnome_rr_config_new_stored (GnomeRRScreen *screen,
GError **error);
gboolean gnome_rr_config_load_current (GnomeRRConfig *self,
GError **error);
gboolean gnome_rr_config_load_filename (GnomeRRConfig *self,
const gchar *filename,
GError **error);
gboolean gnome_rr_config_match (GnomeRRConfig *config1,
GnomeRRConfig *config2);
gboolean gnome_rr_config_equal (GnomeRRConfig *config1,
GnomeRRConfig *config2);
gboolean gnome_rr_config_save (GnomeRRConfig *configuration,
GError **error);
void gnome_rr_config_sanitize (GnomeRRConfig *configuration);
gboolean gnome_rr_config_ensure_primary (GnomeRRConfig *configuration);
gboolean gnome_rr_config_apply_with_time (GnomeRRConfig *configuration,
GnomeRRScreen *screen,
guint32 timestamp,
GError **error);
gboolean gnome_rr_config_apply_from_filename_with_time (GnomeRRScreen *screen,
const char *filename,
guint32 timestamp,
GError **error);
gboolean gnome_rr_config_applicable (GnomeRRConfig *configuration,
GnomeRRScreen *screen,
GError **error);
gboolean gnome_rr_config_get_clone (GnomeRRConfig *configuration);
void gnome_rr_config_set_clone (GnomeRRConfig *configuration, gboolean clone);
guint gnome_rr_config_get_base_scale (GnomeRRConfig *self);
void gnome_rr_config_set_base_scale (GnomeRRConfig *self,
guint base_scale);
gboolean gnome_rr_config_get_auto_scale (GnomeRRConfig *self);
void gnome_rr_config_set_auto_scale (GnomeRRConfig *self,
gboolean auto_scale);
GnomeRROutputInfo **gnome_rr_config_get_outputs (GnomeRRConfig *configuration);
char *gnome_rr_config_get_backup_filename (void);
char *gnome_rr_config_get_intended_filename (void);
char *gnome_rr_config_get_legacy_filename (void);
#endif
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-bg-crossfade.c 0000664 0001750 0001750 00000036363 14167325242 023503 0 ustar fabio fabio /* gnome-bg-crossfade.h - fade window background between two surfaces
*
* Copyright (C) 2008 Red Hat, Inc.
*
* This program 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.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Author: Ray Strode
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-bg.h"
#include "gnome-bg-crossfade.h"
struct _GnomeBGCrossfadePrivate
{
GdkWindow *window;
int width;
int height;
cairo_surface_t *fading_surface;
cairo_surface_t *end_surface;
gdouble start_time;
gdouble total_duration;
guint timeout_id;
guint is_first_frame : 1;
};
enum {
PROP_0,
PROP_WIDTH,
PROP_HEIGHT,
};
enum {
FINISHED,
NUMBER_OF_SIGNALS
};
static guint signals[NUMBER_OF_SIGNALS] = { 0 };
G_DEFINE_TYPE (GnomeBGCrossfade, gnome_bg_crossfade, G_TYPE_OBJECT)
#define GNOME_BG_CROSSFADE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),\
GNOME_TYPE_BG_CROSSFADE,\
GnomeBGCrossfadePrivate))
static void
gnome_bg_crossfade_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GnomeBGCrossfade *fade;
g_assert (GNOME_IS_BG_CROSSFADE (object));
fade = GNOME_BG_CROSSFADE (object);
switch (property_id)
{
case PROP_WIDTH:
fade->priv->width = g_value_get_int (value);
break;
case PROP_HEIGHT:
fade->priv->height = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gnome_bg_crossfade_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GnomeBGCrossfade *fade;
g_assert (GNOME_IS_BG_CROSSFADE (object));
fade = GNOME_BG_CROSSFADE (object);
switch (property_id)
{
case PROP_WIDTH:
g_value_set_int (value, fade->priv->width);
break;
case PROP_HEIGHT:
g_value_set_int (value, fade->priv->height);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gnome_bg_crossfade_finalize (GObject *object)
{
GnomeBGCrossfade *fade;
fade = GNOME_BG_CROSSFADE (object);
gnome_bg_crossfade_stop (fade);
if (fade->priv->fading_surface != NULL) {
cairo_surface_destroy (fade->priv->fading_surface);
fade->priv->fading_surface = NULL;
}
if (fade->priv->end_surface != NULL) {
g_object_unref (fade->priv->end_surface);
fade->priv->end_surface = NULL;
}
}
static void
gnome_bg_crossfade_class_init (GnomeBGCrossfadeClass *fade_class)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (fade_class);
gobject_class->get_property = gnome_bg_crossfade_get_property;
gobject_class->set_property = gnome_bg_crossfade_set_property;
gobject_class->finalize = gnome_bg_crossfade_finalize;
/**
* GnomeBGCrossfade:width:
*
* When a crossfade is running, this is width of the fading
* surface.
*/
g_object_class_install_property (gobject_class,
PROP_WIDTH,
g_param_spec_int ("width",
"Window Width",
"Width of window to fade",
0, G_MAXINT, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
/**
* GnomeBGCrossfade:height:
*
* When a crossfade is running, this is height of the fading
* surface.
*/
g_object_class_install_property (gobject_class,
PROP_HEIGHT,
g_param_spec_int ("height", "Window Height",
"Height of window to fade on",
0, G_MAXINT, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
/**
* GnomeBGCrossfade::finished:
* @fade: the #GnomeBGCrossfade that received the signal
* @window: the #GdkWindow the crossfade happend on.
*
* When a crossfade finishes, @window will have a copy
* of the end surface as its background, and this signal will
* get emitted.
*/
signals[FINISHED] = g_signal_new ("finished",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
g_type_class_add_private (gobject_class, sizeof (GnomeBGCrossfadePrivate));
}
static void
gnome_bg_crossfade_init (GnomeBGCrossfade *fade)
{
fade->priv = GNOME_BG_CROSSFADE_GET_PRIVATE (fade);
fade->priv->fading_surface = NULL;
fade->priv->end_surface = NULL;
fade->priv->timeout_id = 0;
}
/**
* gnome_bg_crossfade_new:
* @width: The width of the crossfading window
* @height: The height of the crossfading window
*
* Creates a new object to manage crossfading a
* window background between two #cairo_surface_ts.
*
* Return value: the new #GnomeBGCrossfade
**/
GnomeBGCrossfade *
gnome_bg_crossfade_new (int width,
int height)
{
GObject *object;
object = g_object_new (GNOME_TYPE_BG_CROSSFADE,
"width", width,
"height", height, NULL);
return (GnomeBGCrossfade *) object;
}
static cairo_surface_t *
tile_surface (cairo_surface_t *surface,
int width,
int height)
{
cairo_surface_t *copy;
cairo_t *cr;
if (surface == NULL) {
copy = gdk_window_create_similar_surface (gdk_get_default_root_window (),
CAIRO_CONTENT_COLOR,
width, height);
} else {
copy = cairo_surface_create_similar (surface,
cairo_surface_get_content (surface),
width, height);
}
cr = cairo_create (copy);
if (surface != NULL) {
cairo_pattern_t *pattern;
cairo_set_source_surface (cr, surface, 0.0, 0.0);
pattern = cairo_get_source (cr);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
} else {
GtkStyle *style;
style = gtk_widget_get_default_style ();
gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
}
cairo_paint (cr);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (copy);
copy = NULL;
}
cairo_destroy (cr);
return copy;
}
/**
* gnome_bg_crossfade_set_start_surface:
* @fade: a #GnomeBGCrossfade
* @surface: The cairo surface to fade from
*
* Before initiating a crossfade with gnome_bg_crossfade_start()
* a start and end surface have to be set. This function sets
* the surface shown at the beginning of the crossfade effect.
*
* Return value: %TRUE if successful, or %FALSE if the surface
* could not be copied.
**/
gboolean
gnome_bg_crossfade_set_start_surface (GnomeBGCrossfade *fade,
cairo_surface_t *surface)
{
g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
if (fade->priv->fading_surface != NULL) {
cairo_surface_destroy (fade->priv->fading_surface);
fade->priv->fading_surface = NULL;
}
fade->priv->fading_surface = tile_surface (surface,
fade->priv->width,
fade->priv->height);
return fade->priv->fading_surface != NULL;
}
static gdouble
get_current_time (void)
{
const double microseconds_per_second = (double) G_USEC_PER_SEC;
double timestamp;
GTimeVal now;
g_get_current_time (&now);
timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) /
microseconds_per_second;
return timestamp;
}
/**
* gnome_bg_crossfade_set_end_surface:
* @fade: a #GnomeBGCrossfade
* @surface: The cairo surface to fade to
*
* Before initiating a crossfade with gnome_bg_crossfade_start()
* a start and end surface have to be set. This function sets
* the surface shown at the end of the crossfade effect.
*
* Return value: %TRUE if successful, or %FALSE if the surface
* could not be copied.
**/
gboolean
gnome_bg_crossfade_set_end_surface (GnomeBGCrossfade *fade,
cairo_surface_t *surface)
{
g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
if (fade->priv->end_surface != NULL) {
cairo_surface_destroy (fade->priv->end_surface);
fade->priv->end_surface = NULL;
}
fade->priv->end_surface = tile_surface (surface,
fade->priv->width,
fade->priv->height);
/* Reset timer in case we're called while animating
*/
fade->priv->start_time = get_current_time ();
return fade->priv->end_surface != NULL;
}
static gboolean
animations_are_disabled (GnomeBGCrossfade *fade)
{
GtkSettings *settings;
GdkScreen *screen;
gboolean are_enabled;
g_assert (fade->priv->window != NULL);
screen = gdk_window_get_screen (fade->priv->window);
settings = gtk_settings_get_for_screen (screen);
g_object_get (settings, "gtk-enable-animations", &are_enabled, NULL);
return !are_enabled;
}
static void
send_root_property_change_notification (GnomeBGCrossfade *fade)
{
long zero_length_pixmap;
/* We do a zero length append to force a change notification,
* without changing the value */
XChangeProperty (GDK_WINDOW_XDISPLAY (fade->priv->window),
GDK_WINDOW_XID (fade->priv->window),
gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"),
XA_PIXMAP, 32, PropModeAppend,
(guchar *) &zero_length_pixmap, 0);
}
static void
draw_background (GnomeBGCrossfade *fade)
{
if (gdk_window_get_window_type (fade->priv->window) == GDK_WINDOW_ROOT) {
gdk_error_trap_push ();
XClearArea (GDK_WINDOW_XDISPLAY (fade->priv->window),
GDK_WINDOW_XID (fade->priv->window),
0, 0,
gdk_window_get_width (fade->priv->window),
gdk_window_get_height (fade->priv->window),
False);
send_root_property_change_notification (fade);
gdk_flush ();
gdk_error_trap_pop_ignored (); // ignore errors
} else {
gdk_window_invalidate_rect (fade->priv->window, NULL, FALSE);
gdk_window_process_updates (fade->priv->window, FALSE);
}
}
static gboolean
on_tick (GnomeBGCrossfade *fade)
{
gdouble now, percent_done;
cairo_t *cr;
cairo_status_t status;
g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
now = get_current_time ();
percent_done = (now - fade->priv->start_time) / fade->priv->total_duration;
percent_done = CLAMP (percent_done, 0.0, 1.0);
/* If it's taking a long time to get to the first frame,
* then lengthen the duration, so the user will get to see
* the effect.
*/
if (fade->priv->is_first_frame && percent_done > .33) {
fade->priv->is_first_frame = FALSE;
fade->priv->total_duration *= 1.5;
return on_tick (fade);
}
if (fade->priv->fading_surface == NULL) {
return FALSE;
}
if (animations_are_disabled (fade)) {
return FALSE;
}
/* We accumulate the results in place for performance reasons.
*
* This means 1) The fade is exponential, not linear (looks good!)
* 2) The rate of fade is not independent of frame rate. Slower machines
* will get a slower fade (but never longer than .75 seconds), and
* even the fastest machines will get *some* fade because the framerate
* is capped.
*/
cr = cairo_create (fade->priv->fading_surface);
cairo_set_source_surface (cr, fade->priv->end_surface,
0.0, 0.0);
cairo_paint_with_alpha (cr, percent_done);
status = cairo_status (cr);
cairo_destroy (cr);
if (status == CAIRO_STATUS_SUCCESS) {
draw_background (fade);
}
return percent_done <= .99;
}
static void
on_finished (GnomeBGCrossfade *fade)
{
cairo_pattern_t *pattern;
if (fade->priv->timeout_id == 0)
return;
g_assert (fade->priv->end_surface != NULL);
pattern = cairo_pattern_create_for_surface (fade->priv->end_surface);
gdk_window_set_background_pattern (fade->priv->window, pattern);
cairo_pattern_destroy (pattern);
draw_background (fade);
cairo_surface_destroy (fade->priv->end_surface);
fade->priv->end_surface = NULL;
g_assert (fade->priv->fading_surface != NULL);
cairo_surface_destroy (fade->priv->fading_surface);
fade->priv->fading_surface = NULL;
fade->priv->timeout_id = 0;
g_signal_emit (fade, signals[FINISHED], 0, fade->priv->window);
}
/**
* gnome_bg_crossfade_start:
* @fade: a #GnomeBGCrossfade
* @window: The #GdkWindow to draw crossfade on
*
* This function initiates a quick crossfade between two surfaces on
* the background of @window. Before initiating the crossfade both
* gnome_bg_crossfade_start() and gnome_bg_crossfade_end() need to
* be called. If animations are disabled, the crossfade is skipped,
* and the window background is set immediately to the end surface.
**/
void
gnome_bg_crossfade_start (GnomeBGCrossfade *fade,
GdkWindow *window)
{
GSource *source;
GMainContext *context;
cairo_pattern_t *pattern;
g_return_if_fail (GNOME_IS_BG_CROSSFADE (fade));
g_return_if_fail (window != NULL);
g_return_if_fail (fade->priv->fading_surface != NULL);
g_return_if_fail (fade->priv->end_surface != NULL);
g_return_if_fail (!gnome_bg_crossfade_is_started (fade));
g_return_if_fail (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN);
source = g_timeout_source_new (1000 / 60.0);
g_source_set_callback (source,
(GSourceFunc) on_tick,
fade,
(GDestroyNotify) on_finished);
context = g_main_context_default ();
fade->priv->timeout_id = g_source_attach (source, context);
g_source_unref (source);
fade->priv->window = window;
pattern = cairo_pattern_create_for_surface (fade->priv->fading_surface);
gdk_window_set_background_pattern (fade->priv->window, pattern);
cairo_pattern_destroy (pattern);
draw_background (fade);
fade->priv->is_first_frame = TRUE;
fade->priv->total_duration = .75;
fade->priv->start_time = get_current_time ();
}
/**
* gnome_bg_crossfade_is_started:
* @fade: a #GnomeBGCrossfade
*
* This function reveals whether or not @fade is currently
* running on a window. See gnome_bg_crossfade_start() for
* information on how to initiate a crossfade.
*
* Return value: %TRUE if fading, or %FALSE if not fading
**/
gboolean
gnome_bg_crossfade_is_started (GnomeBGCrossfade *fade)
{
g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
return fade->priv->timeout_id != 0;
}
/**
* gnome_bg_crossfade_stop:
* @fade: a #GnomeBGCrossfade
*
* This function stops any in progress crossfades that may be
* happening. It's harmless to call this function if @fade is
* already stopped.
**/
void
gnome_bg_crossfade_stop (GnomeBGCrossfade *fade)
{
g_return_if_fail (GNOME_IS_BG_CROSSFADE (fade));
if (!gnome_bg_crossfade_is_started (fade))
return;
g_assert (fade->priv->timeout_id != 0);
g_source_remove (fade->priv->timeout_id);
fade->priv->timeout_id = 0;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr-private.h 0000664 0001750 0001750 00000003377 14167325242 023243 0 ustar fabio fabio #ifndef GNOME_RR_PRIVATE_H
#define GNOME_RR_PRIVATE_H
#include
#include
#define MINIMUM_LOGICAL_SCALE_FACTOR 0.74f
#define MAXIMUM_LOGICAL_SCALE_FACTOR 3.0f
#define MINIMUM_GLOBAL_SCALE_FACTOR 1
#define MAXIMUM_GLOBAL_SCALE_FACTOR 3
typedef struct ScreenInfo ScreenInfo;
struct ScreenInfo
{
int min_width;
int max_width;
int min_height;
int max_height;
XRRScreenResources *resources;
GnomeRROutput ** outputs;
GnomeRRCrtc ** crtcs;
GnomeRRMode ** modes;
GnomeRRScreen * screen;
GnomeRRMode ** clone_modes;
RROutput primary;
};
struct GnomeRRScreenPrivate
{
GdkScreen * gdk_screen;
GdkWindow * gdk_root;
Display * xdisplay;
Screen * xscreen;
Window xroot;
ScreenInfo * info;
GSettings * interface_settings;
int randr_event_base;
int rr_major_version;
int rr_minor_version;
Atom connector_type_atom;
gboolean dpms_capable;
};
struct GnomeRROutputInfoPrivate
{
char * name;
gboolean on;
int width;
int height;
double rate;
int x;
int y;
GnomeRRRotation rotation;
gboolean connected;
gchar vendor[4];
guint product;
guint serial;
double aspect;
int pref_width;
int pref_height;
char * display_name;
gboolean primary;
float scale;
gboolean doublescan;
gboolean interlaced;
gboolean vsync;
};
struct GnomeRRConfigPrivate
{
gboolean clone;
GnomeRRScreen *screen;
GnomeRROutputInfo **outputs;
guint base_scale;
gboolean auto_scale;
};
gboolean _gnome_rr_output_name_is_laptop (const char *name);
#endif
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-bg-crossfade.h 0000664 0001750 0001750 00000006006 14167325242 023477 0 ustar fabio fabio /* gnome-bg-crossfade.h - fade window background between two surfaces
Copyright 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: Ray Strode
*/
#ifndef __GNOME_BG_CROSSFADE_H__
#define __GNOME_BG_CROSSFADE_H__
#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
#error GnomeBGCrossfade is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-bg-crossfade.h
#endif
#include
G_BEGIN_DECLS
#define GNOME_TYPE_BG_CROSSFADE (gnome_bg_crossfade_get_type ())
#define GNOME_BG_CROSSFADE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfade))
#define GNOME_BG_CROSSFADE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfadeClass))
#define GNOME_IS_BG_CROSSFADE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_BG_CROSSFADE))
#define GNOME_IS_BG_CROSSFADE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_BG_CROSSFADE))
#define GNOME_BG_CROSSFADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfadeClass))
typedef struct _GnomeBGCrossfadePrivate GnomeBGCrossfadePrivate;
typedef struct _GnomeBGCrossfade GnomeBGCrossfade;
typedef struct _GnomeBGCrossfadeClass GnomeBGCrossfadeClass;
struct _GnomeBGCrossfade
{
GObject parent_object;
GnomeBGCrossfadePrivate *priv;
};
struct _GnomeBGCrossfadeClass
{
GObjectClass parent_class;
void (* finished) (GnomeBGCrossfade *fade, GdkWindow *window);
};
GType gnome_bg_crossfade_get_type (void);
GnomeBGCrossfade *gnome_bg_crossfade_new (int width, int height);
gboolean gnome_bg_crossfade_set_start_surface (GnomeBGCrossfade *fade,
cairo_surface_t *surface);
gboolean gnome_bg_crossfade_set_end_surface (GnomeBGCrossfade *fade,
cairo_surface_t *surface);
void gnome_bg_crossfade_start (GnomeBGCrossfade *fade,
GdkWindow *window);
gboolean gnome_bg_crossfade_is_started (GnomeBGCrossfade *fade);
void gnome_bg_crossfade_stop (GnomeBGCrossfade *fade);
G_END_DECLS
#endif
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-rr-config.c 0000664 0001750 0001750 00000167621 14167325242 023034 0 ustar fabio fabio /* gnome-rr-config.c
* -*- c-basic-offset: 4 -*-
*
* Copyright 2007, 2008, Red Hat, Inc.
* Copyright 2010 Giovanni Campagna
*
* 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
*/
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "gnome-rr-config.h"
#include "edid.h"
#include "gnome-rr-private.h"
#define CONFIG_INTENDED_BASENAME "cinnamon-monitors.xml"
#define CONFIG_BACKUP_BASENAME "cinnamon-monitors.xml.backup"
#define CONFIG_LEGACY_BASENAME "monitors.xml"
#define BASE_SCALE_NOT_CONFIGURED 0
/* 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
/* In version 0 of the config file format, we had several
* toplevel elements and no explicit version number. So, the filed looked
* like
*
*
* ...
*
*
* ...
*
*
* Since version 1 of the config file, the file has a toplevel
* element to group all the configurations. That element has a "version"
* attribute which is an integer. So, the file looks like this:
*
*
*
* ...
*
*
* ...
*
*
*/
/* A helper wrapper around the GMarkup parser stuff */
static gboolean parse_file_gmarkup (const gchar *file,
const GMarkupParser *parser,
gpointer data,
GError **err);
typedef struct CrtcAssignment CrtcAssignment;
static gboolean crtc_assignment_apply (CrtcAssignment *assign,
guint32 timestamp,
GError **error,
guint *global_scale);
static CrtcAssignment *crtc_assignment_new (GnomeRRConfig *config,
GnomeRRScreen *screen,
GnomeRROutputInfo **outputs,
GError **error);
static void crtc_assignment_free (CrtcAssignment *assign);
enum {
PROP_0,
PROP_SCREEN,
PROP_LAST
};
G_DEFINE_TYPE (GnomeRRConfig, gnome_rr_config, G_TYPE_OBJECT)
typedef struct Parser Parser;
/* Parser for monitor configurations */
struct Parser
{
int config_file_version;
GnomeRROutputInfo * output;
GnomeRRConfig * configuration;
GPtrArray * outputs;
GPtrArray * configurations;
GQueue * stack;
};
static int
parse_int (const char *text)
{
return strtol (text, NULL, 0);
}
static guint64
parse_uint64 (const char *text)
{
return strtoul (text, NULL, 0);
}
static double
parse_double (const char *text)
{
return strtod (text, NULL);
}
static gboolean
stack_is (Parser *parser,
const char *s1,
...)
{
GList *stack = NULL;
const char *s;
GList *l1, *l2;
va_list args;
stack = g_list_prepend (stack, (gpointer)s1);
va_start (args, s1);
s = va_arg (args, const char *);
while (s)
{
stack = g_list_prepend (stack, (gpointer)s);
s = va_arg (args, const char *);
}
va_end (args);
l1 = stack;
l2 = parser->stack->head;
while (l1 && l2)
{
if (strcmp (l1->data, l2->data) != 0)
{
g_list_free (stack);
return FALSE;
}
l1 = l1->next;
l2 = l2->next;
}
g_list_free (stack);
return (!l1 && !l2);
}
static void
handle_start_element (GMarkupParseContext *context,
const gchar *name,
const gchar **attr_names,
const gchar **attr_values,
gpointer user_data,
GError **err)
{
Parser *parser = user_data;
if (strcmp (name, "output") == 0)
{
int i;
g_assert (parser->output == NULL);
parser->output = g_object_new (GNOME_TYPE_RR_OUTPUT_INFO, NULL);
parser->output->priv->rotation = 0;
for (i = 0; attr_names[i] != NULL; ++i)
{
if (strcmp (attr_names[i], "name") == 0)
{
parser->output->priv->name = g_strdup (attr_values[i]);
break;
}
}
if (!parser->output->priv->name)
{
/* This really shouldn't happen, but it's better to make
* something up than to crash later.
*/
g_warning ("Malformed monitor configuration file");
parser->output->priv->name = g_strdup ("default");
}
parser->output->priv->connected = FALSE;
parser->output->priv->on = FALSE;
parser->output->priv->primary = FALSE;
}
else if (strcmp (name, "configuration") == 0)
{
g_assert (parser->configuration == NULL);
parser->configuration = g_object_new (GNOME_TYPE_RR_CONFIG, NULL);
parser->configuration->priv->clone = FALSE;
parser->configuration->priv->outputs = NULL;
}
else if (strcmp (name, "monitors") == 0)
{
int i;
for (i = 0; attr_names[i] != NULL; i++)
{
if (strcmp (attr_names[i], "version") == 0)
{
parser->config_file_version = parse_int (attr_values[i]);
break;
}
}
}
g_queue_push_tail (parser->stack, g_strdup (name));
}
static void
handle_end_element (GMarkupParseContext *context,
const gchar *name,
gpointer user_data,
GError **err)
{
Parser *parser = user_data;
if (strcmp (name, "output") == 0)
{
/* If no rotation properties were set, just use GNOME_RR_ROTATION_0 */
if (parser->output->priv->rotation == 0)
parser->output->priv->rotation = GNOME_RR_ROTATION_0;
g_ptr_array_add (parser->outputs, parser->output);
parser->output = NULL;
}
else if (strcmp (name, "configuration") == 0)
{
g_ptr_array_add (parser->outputs, NULL);
parser->configuration->priv->outputs =
(GnomeRROutputInfo **)g_ptr_array_free (parser->outputs, FALSE);
parser->outputs = g_ptr_array_new ();
g_ptr_array_add (parser->configurations, parser->configuration);
parser->configuration = NULL;
}
g_free (g_queue_pop_tail (parser->stack));
}
#define TOPLEVEL_ELEMENT (parser->config_file_version > 0 ? "monitors" : NULL)
static void
handle_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **err)
{
Parser *parser = user_data;
if (stack_is (parser, "vendor", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->connected = TRUE;
strncpy ((gchar*) parser->output->priv->vendor, text, 3);
parser->output->priv->vendor[3] = 0;
}
else if (stack_is (parser, "clone", "configuration", TOPLEVEL_ELEMENT, NULL))
{
if (strcmp (text, "yes") == 0)
parser->configuration->priv->clone = TRUE;
}
else if (stack_is (parser, "base_scale", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->configuration->priv->base_scale = (guint) parse_uint64 (text);
}
else if (stack_is (parser, "product", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->connected = TRUE;
parser->output->priv->product = parse_int (text);
}
else if (stack_is (parser, "serial", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->connected = TRUE;
parser->output->priv->serial = parse_uint64 (text);
}
else if (stack_is (parser, "width", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->on = TRUE;
parser->output->priv->width = parse_int (text);
}
else if (stack_is (parser, "x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->on = TRUE;
parser->output->priv->x = parse_int (text);
}
else if (stack_is (parser, "y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->on = TRUE;
parser->output->priv->y = parse_int (text);
}
else if (stack_is (parser, "scale", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->on = TRUE;
parser->output->priv->scale = parse_double (text);
}
else if (stack_is (parser, "height", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->on = TRUE;
parser->output->priv->height = parse_int (text);
}
else if (stack_is (parser, "rate", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
parser->output->priv->on = TRUE;
parser->output->priv->rate = parse_double (text);
}
else if (stack_is (parser, "rotation", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
if (strcmp (text, "normal") == 0)
{
parser->output->priv->rotation |= GNOME_RR_ROTATION_0;
}
else if (strcmp (text, "left") == 0)
{
parser->output->priv->rotation |= GNOME_RR_ROTATION_90;
}
else if (strcmp (text, "upside_down") == 0)
{
parser->output->priv->rotation |= GNOME_RR_ROTATION_180;
}
else if (strcmp (text, "right") == 0)
{
parser->output->priv->rotation |= GNOME_RR_ROTATION_270;
}
}
else if (stack_is (parser, "reflect_x", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
if (strcmp (text, "yes") == 0)
{
parser->output->priv->rotation |= GNOME_RR_REFLECT_X;
}
}
else if (stack_is (parser, "reflect_y", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
if (strcmp (text, "yes") == 0)
{
parser->output->priv->rotation |= GNOME_RR_REFLECT_Y;
}
}
else if (stack_is (parser, "primary", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
{
if (strcmp (text, "yes") == 0)
{
parser->output->priv->primary = TRUE;
}
}
else
{
/* Ignore other properties so we can expand the format in the future */
}
}
static void
parser_free (Parser *parser)
{
int i;
GList *list;
g_assert (parser != NULL);
if (parser->output)
g_object_unref (parser->output);
if (parser->configuration)
g_object_unref (parser->configuration);
for (i = 0; i < parser->outputs->len; ++i)
{
GnomeRROutputInfo *output = parser->outputs->pdata[i];
g_object_unref (output);
}
g_ptr_array_free (parser->outputs, TRUE);
for (i = 0; i < parser->configurations->len; ++i)
{
GnomeRRConfig *config = parser->configurations->pdata[i];
g_object_unref (config);
}
g_ptr_array_free (parser->configurations, TRUE);
for (list = parser->stack->head; list; list = list->next)
g_free (list->data);
g_queue_free (parser->stack);
g_free (parser);
}
static void
check_auto_scaling (GnomeRRConfig **configs)
{
GnomeRRConfig *config;
gint i;
if (configs == NULL)
{
return;
}
i = 0;
config = configs[i];
while (config != NULL)
{
if (config->priv->base_scale == BASE_SCALE_NOT_CONFIGURED)
{
config->priv->auto_scale = TRUE;
config->priv->base_scale = gnome_rr_screen_get_global_scale (NULL);
}
config = configs[++i];
}
}
static GnomeRRConfig **
configurations_read_from_file (const gchar *filename, GError **error)
{
Parser *parser = g_new0 (Parser, 1);
GnomeRRConfig **result;
GMarkupParser callbacks = {
handle_start_element,
handle_end_element,
handle_text,
NULL, /* passthrough */
NULL, /* error */
};
parser->config_file_version = 0;
parser->configurations = g_ptr_array_new ();
parser->outputs = g_ptr_array_new ();
parser->stack = g_queue_new ();
if (!parse_file_gmarkup (filename, &callbacks, parser, error))
{
result = NULL;
g_assert (parser->outputs);
goto out;
}
g_assert (parser->outputs);
g_ptr_array_add (parser->configurations, NULL);
result = (GnomeRRConfig **)g_ptr_array_free (parser->configurations, FALSE);
parser->configurations = g_ptr_array_new ();
g_assert (parser->outputs);
out:
parser_free (parser);
check_auto_scaling (result);
return result;
}
static void
gnome_rr_config_init (GnomeRRConfig *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_RR_CONFIG, GnomeRRConfigPrivate);
self->priv->clone = FALSE;
self->priv->base_scale = BASE_SCALE_NOT_CONFIGURED;
self->priv->auto_scale = FALSE;
self->priv->screen = NULL;
self->priv->outputs = NULL;
}
static void
gnome_rr_config_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *property)
{
GnomeRRConfig *self = GNOME_RR_CONFIG (gobject);
switch (property_id) {
case PROP_SCREEN:
self->priv->screen = g_value_dup_object (value);
return;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, property);
}
}
static void
gnome_rr_config_finalize (GObject *gobject)
{
GnomeRRConfig *self = GNOME_RR_CONFIG (gobject);
if (self->priv->screen)
g_object_unref (self->priv->screen);
if (self->priv->outputs) {
int i;
for (i = 0; self->priv->outputs[i] != NULL; i++) {
GnomeRROutputInfo *output = self->priv->outputs[i];
g_object_unref (output);
}
g_free (self->priv->outputs);
}
G_OBJECT_CLASS (gnome_rr_config_parent_class)->finalize (gobject);
}
gboolean
gnome_rr_config_load_current (GnomeRRConfig *config, GError **error)
{
GPtrArray *a;
GnomeRROutput **rr_outputs;
int i;
int clone_width = -1;
int clone_height = -1;
int last_x;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (config), FALSE);
a = g_ptr_array_new ();
rr_outputs = gnome_rr_screen_list_outputs (config->priv->screen);
config->priv->clone = FALSE;
config->priv->base_scale = gnome_rr_screen_get_global_scale (config->priv->screen);
if (gnome_rr_screen_get_global_scale_setting (config->priv->screen) == 0)
{
config->priv->auto_scale = TRUE;
}
for (i = 0; rr_outputs[i] != NULL; ++i)
{
GnomeRROutput *rr_output = rr_outputs[i];
GnomeRROutputInfo *output = g_object_new (GNOME_TYPE_RR_OUTPUT_INFO, NULL);
GnomeRRMode *mode = NULL;
const guint8 *edid_data = gnome_rr_output_get_edid_data (rr_output, NULL);
GnomeRRCrtc *crtc;
output->priv->name = g_strdup (gnome_rr_output_get_name (rr_output));
output->priv->connected = gnome_rr_output_is_connected (rr_output);
if (!output->priv->connected)
{
output->priv->x = -1;
output->priv->y = -1;
output->priv->width = -1;
output->priv->height = -1;
output->priv->rate = -1.0f;
output->priv->scale = MINIMUM_LOGICAL_SCALE_FACTOR;
output->priv->rotation = GNOME_RR_ROTATION_0;
output->priv->doublescan = FALSE;
output->priv->interlaced = FALSE;
output->priv->interlaced = FALSE;
}
else
{
MonitorInfo *info = NULL;
if (edid_data)
info = decode_edid (edid_data);
if (info)
{
memcpy (output->priv->vendor, info->manufacturer_code,
sizeof (output->priv->vendor));
output->priv->product = info->product_code;
output->priv->serial = info->serial_number;
output->priv->aspect = info->aspect_ratio;
}
else
{
strcpy (output->priv->vendor, "???");
output->priv->product = 0;
output->priv->serial = 0;
}
if (gnome_rr_output_is_laptop (rr_output))
output->priv->display_name = g_strdup (_("Laptop"));
else
output->priv->display_name = make_display_name (info);
g_free (info);
crtc = gnome_rr_output_get_crtc (rr_output);
mode = crtc? gnome_rr_crtc_get_current_mode (crtc) : NULL;
if (crtc && mode)
{
output->priv->on = TRUE;
gnome_rr_crtc_get_position (crtc, &output->priv->x, &output->priv->y);
output->priv->width = gnome_rr_mode_get_width (mode);
output->priv->height = gnome_rr_mode_get_height (mode);
output->priv->rate = gnome_rr_mode_get_freq_f (mode);
output->priv->rotation = gnome_rr_crtc_get_current_rotation (crtc);
output->priv->scale = gnome_rr_crtc_get_scale (crtc);
gnome_rr_mode_get_flags (mode,
&output->priv->doublescan,
&output->priv->interlaced,
&output->priv->vsync);
if (output->priv->x == 0 && output->priv->y == 0) {
if (clone_width == -1) {
clone_width = output->priv->width;
clone_height = output->priv->height;
} else if (clone_width == output->priv->width &&
clone_height == output->priv->height) {
config->priv->clone = TRUE;
}
}
}
else
{
output->priv->on = FALSE;
config->priv->clone = FALSE;
}
/* Get preferred size for the monitor */
mode = gnome_rr_output_get_preferred_mode (rr_output);
if (!mode)
{
GnomeRRMode **modes = gnome_rr_output_list_modes (rr_output);
/* FIXME: we should pick the "best" mode here, where best is
* sorted wrt
*
* - closest aspect ratio
* - mode area
* - refresh rate
* - We may want to extend randrwrap so that get_preferred
* returns that - although that could also depend on
* the crtc.
*/
if (modes[0])
mode = modes[0];
}
if (mode)
{
output->priv->pref_width = gnome_rr_mode_get_width (mode);
output->priv->pref_height = gnome_rr_mode_get_height (mode);
}
else
{
/* Pick some random numbers. This should basically never happen */
output->priv->pref_width = 1024;
output->priv->pref_height = 768;
}
}
output->priv->primary = gnome_rr_output_get_is_primary (rr_output);
g_ptr_array_add (a, output);
}
g_ptr_array_add (a, NULL);
config->priv->outputs = (GnomeRROutputInfo **)g_ptr_array_free (a, FALSE);
/* Walk the outputs computing the right-most edge of all
* lit-up displays
*/
last_x = 0;
for (i = 0; config->priv->outputs[i] != NULL; ++i)
{
GnomeRROutputInfo *output = config->priv->outputs[i];
if (output->priv->on)
{
last_x = MAX (last_x, output->priv->x + output->priv->width);
}
}
/* Now position all off displays to the right of the
* on displays
*/
for (i = 0; config->priv->outputs[i] != NULL; ++i)
{
GnomeRROutputInfo *output = config->priv->outputs[i];
if (output->priv->connected && !output->priv->on)
{
output->priv->x = last_x;
last_x = output->priv->x + (output->priv->width * config->priv->base_scale);
}
}
g_assert (gnome_rr_config_match (config, config));
return TRUE;
}
static void
ensure_scale_factor (GnomeRRConfig *config_from_file,
GnomeRROutputInfo *info_from_file)
{
/* Loading an old config for the first time, there probably won't be any
* scale factor. If this happens, give it the matching current output's
* scale factor (what actual 'is' right now) - to maintain their existing
* configuration. */
int k;
for (k = 0; config_from_file->priv->outputs[k] != NULL; ++k)
{
if (config_from_file->priv->auto_scale)
{
info_from_file->priv->scale = (float) config_from_file->priv->base_scale;
continue;
}
gchar *current_output_name, *new_output_name;
current_output_name = config_from_file->priv->outputs[k]->priv->name;
new_output_name = info_from_file->priv->name;
if (g_strcmp0 (current_output_name, new_output_name) == 0)
{
info_from_file->priv->scale = config_from_file->priv->outputs[k]->priv->scale;
}
}
if (info_from_file->priv->scale == 0)
{
info_from_file->priv->scale = MINIMUM_LOGICAL_SCALE_FACTOR;
}
}
gboolean
gnome_rr_config_load_filename (GnomeRRConfig *result, const char *filename, GError **error)
{
GnomeRRConfig *current;
GnomeRRConfig **configs;
gboolean found = FALSE;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (result), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
current = gnome_rr_config_new_current (result->priv->screen, error);
configs = configurations_read_from_file (filename, error);
if (configs)
{
int i;
for (i = 0; configs[i] != NULL; ++i)
{
if (gnome_rr_config_match (configs[i], current))
{
int j;
GPtrArray *array;
result->priv->clone = configs[i]->priv->clone;
result->priv->auto_scale = configs[i]->priv->auto_scale;
result->priv->base_scale = configs[i]->priv->base_scale;
array = g_ptr_array_new ();
for (j = 0; configs[i]->priv->outputs[j] != NULL; j++) {
g_object_ref (configs[i]->priv->outputs[j]);
g_ptr_array_add (array, configs[i]->priv->outputs[j]);
ensure_scale_factor (configs[i], configs[i]->priv->outputs[j]);
}
g_ptr_array_add (array, NULL);
result->priv->outputs = (GnomeRROutputInfo **) g_ptr_array_free (array, FALSE);
found = TRUE;
break;
}
g_object_unref (configs[i]);
}
g_free (configs);
if (!found)
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG,
_("none of the saved display configurations matched the active configuration"));
}
g_object_unref (current);
return found;
}
static void
gnome_rr_config_class_init (GnomeRRConfigClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GnomeRROutputInfoPrivate));
gobject_class->set_property = gnome_rr_config_set_property;
gobject_class->finalize = gnome_rr_config_finalize;
g_object_class_install_property (gobject_class, PROP_SCREEN,
g_param_spec_object ("screen", "Screen", "The GnomeRRScreen this config applies to", GNOME_TYPE_RR_SCREEN,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
}
GnomeRRConfig *
gnome_rr_config_new_current (GnomeRRScreen *screen, GError **error)
{
GnomeRRConfig *self = g_object_new (GNOME_TYPE_RR_CONFIG, "screen", screen, NULL);
if (gnome_rr_config_load_current (self, error))
return self;
else
{
g_object_unref (self);
return NULL;
}
}
GnomeRRConfig *
gnome_rr_config_new_stored (GnomeRRScreen *screen, GError **error)
{
GnomeRRConfig *self = g_object_new (GNOME_TYPE_RR_CONFIG, "screen", screen, NULL);
char *filename;
gboolean success;
filename = gnome_rr_config_get_intended_filename ();
success = gnome_rr_config_load_filename (self, filename, error);
if (!success)
{
g_clear_error (error);
g_debug ("existing monitor config (%s) not found. Looking for legacy configuration (monitors.xml)", filename);
g_free (filename);
filename = gnome_rr_config_get_legacy_filename ();
success = gnome_rr_config_load_filename (self, filename, error);
}
g_free (filename);
if (success)
return self;
else
{
g_object_unref (self);
return NULL;
}
}
static gboolean
parse_file_gmarkup (const gchar *filename,
const GMarkupParser *parser,
gpointer data,
GError **err)
{
GMarkupParseContext *context = NULL;
gchar *contents = NULL;
gboolean result = TRUE;
gsize len;
if (!g_file_get_contents (filename, &contents, &len, err))
{
result = FALSE;
goto out;
}
context = g_markup_parse_context_new (parser, 0, data, NULL);
if (!g_markup_parse_context_parse (context, contents, len, err))
{
result = FALSE;
goto out;
}
if (!g_markup_parse_context_end_parse (context, err))
{
result = FALSE;
goto out;
}
out:
if (contents)
g_free (contents);
if (context)
g_markup_parse_context_free (context);
return result;
}
static gboolean
output_match (GnomeRROutputInfo *output1, GnomeRROutputInfo *output2)
{
g_assert (GNOME_IS_RR_OUTPUT_INFO (output1));
g_assert (GNOME_IS_RR_OUTPUT_INFO (output2));
if (strcmp (output1->priv->name, output2->priv->name) != 0)
return FALSE;
if (strcmp (output1->priv->vendor, output2->priv->vendor) != 0)
return FALSE;
if (output1->priv->product != output2->priv->product)
return FALSE;
if (output1->priv->serial != output2->priv->serial)
return FALSE;
if (output1->priv->connected != output2->priv->connected)
return FALSE;
return TRUE;
}
static gboolean
output_equal (GnomeRROutputInfo *output1, GnomeRROutputInfo *output2)
{
g_assert (GNOME_IS_RR_OUTPUT_INFO (output1));
g_assert (GNOME_IS_RR_OUTPUT_INFO (output2));
if (!output_match (output1, output2))
return FALSE;
if (output1->priv->on != output2->priv->on)
return FALSE;
if (output1->priv->on)
{
if (output1->priv->width != output2->priv->width)
return FALSE;
if (output1->priv->height != output2->priv->height)
return FALSE;
if (output1->priv->rate != output2->priv->rate)
return FALSE;
if (output1->priv->x != output2->priv->x)
return FALSE;
if (output1->priv->y != output2->priv->y)
return FALSE;
if (output1->priv->rotation != output2->priv->rotation)
return FALSE;
if (output1->priv->scale != output2->priv->scale)
return FALSE;
}
return TRUE;
}
static GnomeRROutputInfo *
find_output (GnomeRRConfig *config, const char *name)
{
int i;
for (i = 0; config->priv->outputs[i] != NULL; ++i)
{
GnomeRROutputInfo *output = config->priv->outputs[i];
if (strcmp (name, output->priv->name) == 0)
return output;
}
return NULL;
}
/* Match means "these configurations apply to the same hardware
* setups"
*/
gboolean
gnome_rr_config_match (GnomeRRConfig *c1, GnomeRRConfig *c2)
{
int i;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (c1), FALSE);
g_return_val_if_fail (GNOME_IS_RR_CONFIG (c2), FALSE);
for (i = 0; c1->priv->outputs[i] != NULL; ++i)
{
GnomeRROutputInfo *output1 = c1->priv->outputs[i];
GnomeRROutputInfo *output2;
output2 = find_output (c2, output1->priv->name);
if (!output2 || !output_match (output1, output2))
return FALSE;
}
return TRUE;
}
/* Equal means "the configurations will result in the same
* modes being set on the outputs"
*/
gboolean
gnome_rr_config_equal (GnomeRRConfig *c1,
GnomeRRConfig *c2)
{
int i;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (c1), FALSE);
g_return_val_if_fail (GNOME_IS_RR_CONFIG (c2), FALSE);
if (c1->priv->auto_scale != c2->priv->auto_scale)
{
return FALSE;
}
if (c1->priv->base_scale != c2->priv->base_scale)
{
return FALSE;
}
for (i = 0; c1->priv->outputs[i] != NULL; ++i)
{
GnomeRROutputInfo *output1 = c1->priv->outputs[i];
GnomeRROutputInfo *output2;
output2 = find_output (c2, output1->priv->name);
if (!output2 || !output_equal (output1, output2))
return FALSE;
}
return TRUE;
}
static GnomeRROutputInfo **
make_outputs (GnomeRRConfig *config)
{
GPtrArray *outputs;
GnomeRROutputInfo *first_on;
int i;
outputs = g_ptr_array_new ();
first_on = NULL;
for (i = 0; config->priv->outputs[i] != NULL; ++i)
{
GnomeRROutputInfo *old = config->priv->outputs[i];
GnomeRROutputInfo *new = g_object_new (GNOME_TYPE_RR_OUTPUT_INFO, NULL);
*(new->priv) = *(old->priv);
if (old->priv->name)
new->priv->name = g_strdup (old->priv->name);
if (old->priv->display_name)
new->priv->display_name = g_strdup (old->priv->display_name);
if (old->priv->on && !first_on)
first_on = old;
if (config->priv->clone && new->priv->on)
{
g_assert (first_on);
new->priv->width = first_on->priv->width;
new->priv->height = first_on->priv->height;
new->priv->rotation = first_on->priv->rotation;
new->priv->x = 0;
new->priv->y = 0;
new->priv->scale = first_on->priv->scale;
new->priv->rate = 60.0f;
}
g_ptr_array_add (outputs, new);
}
g_ptr_array_add (outputs, NULL);
return (GnomeRROutputInfo **)g_ptr_array_free (outputs, FALSE);
}
gboolean
gnome_rr_config_applicable (GnomeRRConfig *configuration,
GnomeRRScreen *screen,
GError **error)
{
GnomeRROutputInfo **outputs;
CrtcAssignment *assign;
gboolean result;
int i;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (configuration), FALSE);
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
outputs = make_outputs (configuration);
assign = crtc_assignment_new (configuration, screen, outputs, error);
if (assign)
{
result = TRUE;
crtc_assignment_free (assign);
}
else
{
result = FALSE;
}
for (i = 0; outputs[i] != NULL; i++) {
g_object_unref (outputs[i]);
}
return result;
}
/* Database management */
static void
ensure_config_directory (void)
{
g_mkdir_with_parents (g_get_user_config_dir (), 0700);
}
char *
gnome_rr_config_get_backup_filename (void)
{
ensure_config_directory ();
return g_build_filename (g_get_user_config_dir (), CONFIG_BACKUP_BASENAME, NULL);
}
char *
gnome_rr_config_get_intended_filename (void)
{
ensure_config_directory ();
return g_build_filename (g_get_user_config_dir (), CONFIG_INTENDED_BASENAME, NULL);
}
char *
gnome_rr_config_get_legacy_filename (void)
{
ensure_config_directory ();
return g_build_filename (g_get_user_config_dir (), CONFIG_LEGACY_BASENAME, NULL);
}
static const char *
get_rotation_name (GnomeRRRotation r)
{
if (r & GNOME_RR_ROTATION_0)
return "normal";
if (r & GNOME_RR_ROTATION_90)
return "left";
if (r & GNOME_RR_ROTATION_180)
return "upside_down";
if (r & GNOME_RR_ROTATION_270)
return "right";
return "normal";
}
static const char *
yes_no (int x)
{
return x? "yes" : "no";
}
static const char *
get_reflect_x (GnomeRRRotation r)
{
return yes_no (r & GNOME_RR_REFLECT_X);
}
static const char *
get_reflect_y (GnomeRRRotation r)
{
return yes_no (r & GNOME_RR_REFLECT_Y);
}
static void
emit_configuration (GnomeRRConfig *config,
GString *string)
{
int j;
g_string_append_printf (string, " \n");
g_string_append_printf (string, " %s\n", yes_no (config->priv->clone));
if (!config->priv->auto_scale)
{
g_string_append_printf (string, " %d\n", config->priv->base_scale);
}
for (j = 0; config->priv->outputs[j] != NULL; ++j)
{
GnomeRROutputInfo *output = config->priv->outputs[j];
g_string_append_printf (
string, " \n");
}
g_string_append_printf (string, " \n");
}
void
gnome_rr_config_sanitize (GnomeRRConfig *config)
{
int i;
int x_offset, y_offset;
gboolean found;
/* Offset everything by the top/left-most coordinate to
* make sure the configuration starts at (0, 0)
*/
x_offset = y_offset = G_MAXINT;
for (i = 0; config->priv->outputs[i]; ++i)
{
GnomeRROutputInfo *output = config->priv->outputs[i];
if (output->priv->on)
{
x_offset = MIN (x_offset, output->priv->x);
y_offset = MIN (y_offset, output->priv->y);
}
}
for (i = 0; config->priv->outputs[i]; ++i)
{
GnomeRROutputInfo *output = config->priv->outputs[i];
output->priv->x -= x_offset;
output->priv->y -= y_offset;
}
/* Only one primary, please */
found = FALSE;
for (i = 0; config->priv->outputs[i]; ++i)
{
if (config->priv->outputs[i]->priv->primary)
{
if (found)
{
config->priv->outputs[i]->priv->primary = FALSE;
}
else
{
found = TRUE;
}
}
}
}
gboolean
gnome_rr_config_ensure_primary (GnomeRRConfig *configuration)
{
int i;
GnomeRROutputInfo *laptop;
GnomeRROutputInfo *top_left;
gboolean found;
GnomeRRConfigPrivate *priv;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (configuration), FALSE);
laptop = NULL;
top_left = NULL;
found = FALSE;
priv = configuration->priv;
for (i = 0; priv->outputs[i] != NULL; ++i) {
GnomeRROutputInfo *info = priv->outputs[i];
if (!info->priv->on) {
info->priv->primary = FALSE;
continue;
}
/* ensure only one */
if (info->priv->primary) {
if (found) {
info->priv->primary = FALSE;
} else {
found = TRUE;
}
}
if (top_left == NULL
|| (info->priv->x < top_left->priv->x
&& info->priv->y < top_left->priv->y)) {
top_left = info;
}
if (laptop == NULL
&& _gnome_rr_output_name_is_laptop (info->priv->name)) {
/* shame we can't find the connector type
as with gnome_rr_output_is_laptop */
laptop = info;
}
}
if (!found) {
if (laptop != NULL) {
laptop->priv->primary = TRUE;
} else if (top_left != NULL) {
/* Note: top_left can be NULL if all outputs are off */
top_left->priv->primary = TRUE;
}
}
return !found;
}
gboolean
gnome_rr_config_save (GnomeRRConfig *configuration, GError **error)
{
GnomeRRConfig **configurations;
GString *output;
int i;
gchar *intended_filename;
gchar *backup_filename;
gboolean result;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (configuration), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
output = g_string_new ("");
backup_filename = gnome_rr_config_get_backup_filename ();
intended_filename = gnome_rr_config_get_intended_filename ();
configurations = configurations_read_from_file (intended_filename, NULL); /* NULL-GError */
g_string_append_printf (output, "\n");
if (configurations)
{
for (i = 0; configurations[i] != NULL; ++i)
{
if (!gnome_rr_config_match (configurations[i], configuration))
emit_configuration (configurations[i], output);
g_object_unref (configurations[i]);
}
g_free (configurations);
}
emit_configuration (configuration, output);
g_string_append_printf (output, "\n");
/* backup the file first */
rename (intended_filename, backup_filename); /* no error checking because the intended file may not even exist */
result = g_file_set_contents (intended_filename, output->str, -1, error);
if (!result)
rename (backup_filename, intended_filename); /* no error checking because the backup may not even exist */
g_free (backup_filename);
g_free (intended_filename);
g_string_free (output, TRUE);
return result;
}
gboolean
gnome_rr_config_apply_with_time (GnomeRRConfig *config,
GnomeRRScreen *screen,
guint32 timestamp,
GError **error)
{
CrtcAssignment *assignment;
GnomeRROutputInfo **outputs;
gboolean result = FALSE;
int i;
guint global_scale;
g_return_val_if_fail (GNOME_IS_RR_CONFIG (config), FALSE);
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), FALSE);
gdk_error_trap_push ();
outputs = make_outputs (config);
assignment = crtc_assignment_new (config, screen, outputs, error);
for (i = 0; outputs[i] != NULL; i++)
g_object_unref (outputs[i]);
g_free (outputs);
global_scale = config->priv->base_scale;
if (assignment)
{
if (crtc_assignment_apply (assignment, timestamp, error, &global_scale))
result = TRUE;
crtc_assignment_free (assignment);
gdk_flush ();
gdk_error_trap_pop_ignored (); // ignore errors
}
if (result == TRUE)
{
gnome_rr_screen_set_global_scale_setting (screen,
config->priv->auto_scale ? 0 : global_scale);
}
return result;
}
/* gnome_rr_config_apply_from_filename_with_time:
* @screen: A #GnomeRRScreen
* @filename: Path of the file to look in for stored RANDR configurations.
* @timestamp: X server timestamp from the event that causes the screen configuration to change (a user's button press, for example)
* @error: Location to store error, or %NULL
*
* Loads the file in @filename and looks for suitable matching RANDR
* configurations in the file; if one is found, that configuration will be
* applied to the current set of RANDR outputs.
*
* Typically, @filename is the result of gnome_rr_config_get_intended_filename() or
* gnome_rr_config_get_backup_filename().
*
* Returns: TRUE if the RANDR configuration was loaded and applied from
* the specified file, or FALSE otherwise:
*
* If the file in question is loaded successfully but the configuration cannot
* be applied, the @error will have a domain of #GNOME_RR_ERROR. Note that an
* error code of #GNOME_RR_ERROR_NO_MATCHING_CONFIG is not a real error; it
* simply means that there were no stored configurations that match the current
* set of RANDR outputs.
*
* If the file in question cannot be loaded, the @error will have a domain of
* #G_FILE_ERROR. Note that an error code of G_FILE_ERROR_NOENT is not really
* an error, either; it means that there was no stored configuration file and so
* nothing is changed.
*/
gboolean
gnome_rr_config_apply_from_filename_with_time (GnomeRRScreen *screen, const char *filename, guint32 timestamp, GError **error)
{
GnomeRRConfig *stored;
g_return_val_if_fail (GNOME_IS_RR_SCREEN (screen), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
stored = g_object_new (GNOME_TYPE_RR_CONFIG, "screen", screen, NULL);
if (gnome_rr_config_load_filename (stored, filename, error))
{
gboolean result;
gnome_rr_config_ensure_primary (stored);
result = gnome_rr_config_apply_with_time (stored, screen, timestamp, error);
g_object_unref (stored);
return result;
}
else
{
g_object_unref (stored);
return FALSE;
}
}
/**
* gnome_rr_config_get_outputs:
*
* Returns: (array zero-terminated=1) (element-type CinnamonDesktop.RROutputInfo) (transfer none): the output configuration for this #GnomeRRConfig
*/
GnomeRROutputInfo **
gnome_rr_config_get_outputs (GnomeRRConfig *self)
{
g_return_val_if_fail (GNOME_IS_RR_CONFIG (self), NULL);
return self->priv->outputs;
}
/**
* gnome_rr_config_get_clone:
*
* Returns: whether at least two outputs are at (0, 0) offset and they
* have the same width/height. Those outputs are of course connected and on
* (i.e. they have a CRTC assigned).
*/
gboolean
gnome_rr_config_get_clone (GnomeRRConfig *self)
{
g_return_val_if_fail (GNOME_IS_RR_CONFIG (self), FALSE);
return self->priv->clone;
}
void
gnome_rr_config_set_clone (GnomeRRConfig *self, gboolean clone)
{
g_return_if_fail (GNOME_IS_RR_CONFIG (self));
self->priv->clone = clone;
}
guint
gnome_rr_config_get_base_scale (GnomeRRConfig *self)
{
g_return_val_if_fail (GNOME_IS_RR_CONFIG (self), MINIMUM_GLOBAL_SCALE_FACTOR);
if (self->priv->auto_scale)
{
return gnome_rr_screen_get_global_scale (self->priv->screen);
}
return self->priv->base_scale;
}
void
gnome_rr_config_set_base_scale (GnomeRRConfig *self,
guint base_scale)
{
g_return_if_fail (GNOME_IS_RR_CONFIG (self) || base_scale < MINIMUM_GLOBAL_SCALE_FACTOR);
self->priv->base_scale = base_scale;
}
gboolean
gnome_rr_config_get_auto_scale (GnomeRRConfig *self)
{
g_return_val_if_fail (GNOME_IS_RR_CONFIG (self), TRUE);
return self->priv->auto_scale;
}
void
gnome_rr_config_set_auto_scale (GnomeRRConfig *self,
gboolean auto_scale)
{
g_return_if_fail (GNOME_IS_RR_CONFIG (self));
self->priv->auto_scale = auto_scale;
}
/*
* CRTC assignment
*/
typedef struct CrtcInfo CrtcInfo;
struct CrtcInfo
{
GnomeRRMode *mode;
int x;
int y;
float scale;
GnomeRRRotation rotation;
GPtrArray *outputs;
};
struct CrtcAssignment
{
GnomeRRScreen *screen;
GHashTable *info;
GnomeRROutput *primary;
};
static gboolean
can_clone (CrtcInfo *info,
GnomeRROutput *output)
{
int i;
for (i = 0; i < info->outputs->len; ++i)
{
GnomeRROutput *clone = info->outputs->pdata[i];
if (!gnome_rr_output_can_clone (clone, output))
return FALSE;
}
return TRUE;
}
static gboolean
crtc_assignment_assign (CrtcAssignment *assign,
GnomeRRCrtc *crtc,
GnomeRRMode *mode,
int x,
int y,
GnomeRRRotation rotation,
gboolean primary,
float scale,
GnomeRROutput *output,
GError **error)
{
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
guint32 crtc_id;
const char *output_name;
crtc_id = gnome_rr_crtc_get_id (crtc);
output_name = gnome_rr_output_get_name (output);
if (!gnome_rr_crtc_can_drive_output (crtc, output))
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("CRTC %d cannot drive output %s"), crtc_id, output_name);
return FALSE;
}
if (!gnome_rr_output_supports_mode (output, mode))
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("output %s does not support mode %dx%d@%dHz"),
output_name,
gnome_rr_mode_get_width (mode),
gnome_rr_mode_get_height (mode),
gnome_rr_mode_get_freq (mode));
return FALSE;
}
if (!gnome_rr_crtc_supports_rotation (crtc, rotation))
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("CRTC %d does not support rotation=%s"),
crtc_id,
get_rotation_name (rotation));
return FALSE;
}
if (info)
{
if (!(info->mode == mode &&
info->x == x &&
info->y == y &&
info->scale == scale &&
info->rotation == rotation))
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("output %s does not have the same parameters as another cloned output:\n"
"existing mode = %d, new mode = %d\n"
"existing coordinates = (%d, %d), new coordinates = (%d, %d)\n"
"existing rotation = %s, new rotation = %s"
"existing scale = %.2f, new scale = %.2f"),
output_name,
gnome_rr_mode_get_id (info->mode), gnome_rr_mode_get_id (mode),
info->x, info->y,
x, y,
get_rotation_name (info->rotation), get_rotation_name (rotation),
info->scale, scale);
return FALSE;
}
if (!can_clone (info, output))
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("cannot clone to output %s"),
output_name);
return FALSE;
}
g_ptr_array_add (info->outputs, output);
if (primary && !assign->primary)
{
assign->primary = output;
}
return TRUE;
}
else
{
CrtcInfo *info = g_new0 (CrtcInfo, 1);
info->mode = mode;
info->x = x;
info->y = y;
info->rotation = rotation;
info->scale = scale;
info->outputs = g_ptr_array_new ();
g_ptr_array_add (info->outputs, output);
g_hash_table_insert (assign->info, crtc, info);
if (primary && !assign->primary)
{
assign->primary = output;
}
return TRUE;
}
return FALSE;
}
static void
crtc_assignment_unassign (CrtcAssignment *assign,
GnomeRRCrtc *crtc,
GnomeRROutput *output)
{
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
if (info)
{
g_ptr_array_remove (info->outputs, output);
if (assign->primary == output)
{
assign->primary = NULL;
}
if (info->outputs->len == 0)
g_hash_table_remove (assign->info, crtc);
}
}
static void
crtc_assignment_free (CrtcAssignment *assign)
{
g_hash_table_destroy (assign->info);
g_free (assign);
}
typedef struct {
guint32 timestamp;
gboolean has_error;
GError **error;
guint global_scale;
} ConfigureCrtcState;
// static guint
// get_max_info_scale (CrtcAssignment *assignment)
// {
// GList *infos, *iter;
// float max_scale = 0;
// infos = g_hash_table_get_values (assignment->info);
// for (iter = infos; iter != NULL; iter = iter->next)
// {
// CrtcInfo *info = iter->data;
// if (info->scale > max_scale)
// {
// max_scale = info->scale;
// }
// }
// g_list_free (infos);
// return CLAMP ((guint) ceilf (max_scale),
// MINIMUM_GLOBAL_SCALE_FACTOR,
// MAXIMUM_GLOBAL_SCALE_FACTOR);
// }
// static guint
// get_min_info_scale (CrtcAssignment *assignment)
// {
// GList *infos, *iter;
// float min_scale = 4.0f;
// infos = g_hash_table_get_values (assignment->info);
// for (iter = infos; iter != NULL; iter = iter->next)
// {
// CrtcInfo *info = iter->data;
// if (info->scale < min_scale)
// {
// min_scale = info->scale;
// }
// }
// g_list_free (infos);
// return CLAMP ((guint) floorf (min_scale),
// MINIMUM_GLOBAL_SCALE_FACTOR,
// MAXIMUM_GLOBAL_SCALE_FACTOR);
// }
static void
configure_crtc (gpointer key,
gpointer value,
gpointer data)
{
GnomeRRCrtc *crtc = key;
CrtcInfo *info = value;
ConfigureCrtcState *state = data;
if (state->has_error)
return;
if (!gnome_rr_crtc_set_config_with_time (crtc,
state->timestamp,
info->x, info->y,
info->mode,
info->rotation,
(GnomeRROutput **)info->outputs->pdata,
info->outputs->len,
info->scale,
state->global_scale,
state->error))
state->has_error = TRUE;
}
static gboolean
mode_is_rotated (CrtcInfo *info)
{
if ((info->rotation & GNOME_RR_ROTATION_270) ||
(info->rotation & GNOME_RR_ROTATION_90))
{
return TRUE;
}
return FALSE;
}
static gboolean
crtc_is_rotated (GnomeRRCrtc *crtc)
{
GnomeRRRotation r = gnome_rr_crtc_get_current_rotation (crtc);
if ((r & GNOME_RR_ROTATION_270) ||
(r & GNOME_RR_ROTATION_90))
{
return TRUE;
}
return FALSE;
}
static void
accumulate_error (GString *accumulated_error, GError *error)
{
g_string_append_printf (accumulated_error, " %s\n", error->message);
g_error_free (error);
}
/* Check whether the given set of settings can be used
* at the same time -- ie. whether there is an assignment
* of CRTC's to outputs.
*
* Brute force - the number of objects involved is small
* enough that it doesn't matter.
*/
static gboolean
real_assign_crtcs (GnomeRRScreen *screen,
GnomeRROutputInfo **outputs,
CrtcAssignment *assignment,
GError **error)
{
GnomeRRCrtc **crtcs = gnome_rr_screen_list_crtcs (screen);
GnomeRROutputInfo *output;
int i;
gboolean tried_mode;
GError *my_error;
GString *accumulated_error;
gboolean success;
output = *outputs;
if (!output)
return TRUE;
/* It is always allowed for an output to be turned off */
if (!output->priv->on)
{
return real_assign_crtcs (screen, outputs + 1, assignment, error);
}
success = FALSE;
tried_mode = FALSE;
accumulated_error = g_string_new (NULL);
for (i = 0; crtcs[i] != NULL; ++i)
{
GnomeRRCrtc *crtc = crtcs[i];
int crtc_id = gnome_rr_crtc_get_id (crtc);
int pass;
g_debug (_("Trying modes for CRTC %d"),
crtc_id);
g_string_append_printf (accumulated_error,
_("Trying modes for CRTC %d\n"),
crtc_id);
/* Make two passes, one where frequencies must match, then
* one where they don't have to
*/
for (pass = 0; pass < 2; ++pass)
{
GnomeRROutput *gnome_rr_output = gnome_rr_screen_get_output_by_name (screen, output->priv->name);
GnomeRRMode **modes = gnome_rr_output_list_modes (gnome_rr_output);
int j;
for (j = 0; modes[j] != NULL; ++j)
{
GnomeRRMode *mode = modes[j];
int mode_width;
int mode_height;
double mode_freq;
mode_width = gnome_rr_mode_get_width (mode);
mode_height = gnome_rr_mode_get_height (mode);
mode_freq = gnome_rr_mode_get_freq_f (mode);
g_string_append_printf (accumulated_error,
_("CRTC %d: trying mode %dx%d@%.2fHz with output at %dx%d@%.2fHz (pass %d)\n"),
crtc_id,
mode_width, mode_height, mode_freq,
output->priv->width, output->priv->height, output->priv->rate,
pass);
if (mode_width == output->priv->width &&
mode_height == output->priv->height &&
(pass == 1 || mode_freq == output->priv->rate))
{
tried_mode = TRUE;
my_error = NULL;
if (crtc_assignment_assign (
assignment, crtc, modes[j],
output->priv->x, output->priv->y,
output->priv->rotation,
output->priv->primary,
output->priv->scale,
gnome_rr_output,
&my_error))
{
my_error = NULL;
if (real_assign_crtcs (screen, outputs + 1, assignment, &my_error)) {
success = TRUE;
goto out;
} else
accumulate_error (accumulated_error, my_error);
crtc_assignment_unassign (assignment, crtc, gnome_rr_output);
} else
accumulate_error (accumulated_error, my_error);
}
}
}
}
out:
if (success)
g_string_free (accumulated_error, TRUE);
else {
char *str;
str = g_string_free (accumulated_error, FALSE);
if (tried_mode)
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("could not assign CRTCs to outputs:\n%s"),
str);
else
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT,
_("none of the selected modes were compatible with the possible modes:\n%s"),
str);
g_free (str);
}
return success;
}
static void
crtc_info_free (CrtcInfo *info)
{
g_ptr_array_free (info->outputs, TRUE);
g_free (info);
}
static void
get_required_virtual_size (CrtcAssignment *assign,
GnomeRRScreen *screen,
int *width,
int *height,
float *avg_scale,
guint *global_scale)
{
GList *active_crtcs = g_hash_table_get_keys (assign->info);
GList *list;
int crtc_count;
float avg_screen_scale;
/*
if (gnome_rr_screen_get_use_upscaling (screen))
{
*global_scale = get_min_info_scale (assign);
}
else
{
*global_scale = get_max_info_scale (assign);
}
*/
/* Compute size of the screen */
*width = *height = 1;
avg_screen_scale = 0;
crtc_count = 0;
for (list = active_crtcs; list != NULL; list = list->next)
{
GnomeRRCrtc *crtc = list->data;
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
int w, h;
float scale = 1.0f;
scale = *global_scale / info->scale;
w = gnome_rr_mode_get_width (info->mode);
h = gnome_rr_mode_get_height (info->mode);
if (mode_is_rotated (info))
{
int tmp = h;
h = w;
w = tmp;
}
*width = MAX (*width, info->x + roundf (w * scale));
*height = MAX (*height, info->y + roundf (h * scale));
avg_screen_scale += (info->scale - avg_screen_scale) / (float) (++crtc_count);
}
*avg_scale = avg_screen_scale;
g_debug ("Proposed screen size: %dx%d average scale: %.2f, ui scale: %d",
*width, *height, *avg_scale, *global_scale);
g_list_free (active_crtcs);
}
static CrtcAssignment *
crtc_assignment_new (GnomeRRConfig *config,
GnomeRRScreen *screen,
GnomeRROutputInfo **outputs,
GError **error)
{
CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1);
assignment->info = g_hash_table_new_full (
g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free);
if (real_assign_crtcs (screen, outputs, assignment, error))
{
int width, height;
int min_width, max_width, min_height, max_height;
float scale;
guint global_scale = config->priv->base_scale;
get_required_virtual_size (assignment,
screen,
&width, &height,
&scale, &global_scale);
gnome_rr_screen_get_ranges (
screen, &min_width, &max_width, &min_height, &max_height);
if (width < min_width || width > max_width ||
height < min_height || height > max_height)
{
g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR,
/* Translators: the "requested", "minimum", and
* "maximum" words here are not keywords; please
* translate them as usual. */
_("required virtual size does not fit available size: "
"requested=(%d, %d), minimum=(%d, %d), maximum=(%d, %d)"),
width, height,
min_width, min_height,
max_width, max_height);
goto fail;
}
assignment->screen = screen;
return assignment;
}
fail:
crtc_assignment_free (assignment);
return NULL;
}
static gboolean
crtc_assignment_apply (CrtcAssignment *assign,
guint32 timestamp,
GError **error,
guint *global_scale)
{
GnomeRRCrtc **all_crtcs = gnome_rr_screen_list_crtcs (assign->screen);
int width, height;
int i;
int min_width, max_width, min_height, max_height;
int width_mm, height_mm;
float average_scale;
gboolean success = TRUE;
/* Compute size of the screen */
get_required_virtual_size (assign,
assign->screen,
&width, &height,
&average_scale, global_scale);
gnome_rr_screen_get_ranges (
assign->screen, &min_width, &max_width, &min_height, &max_height);
/* We should never get here if the dimensions don't fit in the virtual size,
* but just in case we do, fix it up.
*/
width = MAX (min_width, width);
width = MIN (max_width, width);
height = MAX (min_height, height);
height = MIN (max_height, height);
/* FMQ: do we need to check the sizes instead of clamping them? */
/* Grab the server while we fiddle with the CRTCs and the screen, so that
* apps that listen for RANDR notifications will only receive the final
* status.
*/
gdk_x11_display_grab (gdk_screen_get_display (assign->screen->priv->gdk_screen));
/* Turn off all crtcs that are currently displaying outside the new screen,
* or are not used in the new setup
*/
for (i = 0; all_crtcs[i] != NULL; ++i)
{
GnomeRRCrtc *crtc = all_crtcs[i];
GnomeRRMode *mode = gnome_rr_crtc_get_current_mode (crtc);
int x, y;
if (mode)
{
int w, h;
gnome_rr_crtc_get_position (crtc, &x, &y);
w = gnome_rr_mode_get_width (mode) * (*global_scale);
h = gnome_rr_mode_get_height (mode) * (*global_scale);
if (crtc_is_rotated (crtc))
{
int tmp = h;
h = w;
w = tmp;
}
if (x + w > width || y + h > height || !g_hash_table_lookup (assign->info, crtc))
{
if (!gnome_rr_crtc_set_config_with_time (crtc,
timestamp,
0, 0,
NULL,
GNOME_RR_ROTATION_0,
NULL,
0,
1.0f,
1,
error))
{
success = FALSE;
break;
}
}
}
}
/* 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 / average_scale)) * 25.4 + 0.5;
height_mm = (height / (DPI_FALLBACK / average_scale)) * 25.4 + 0.5;
if (success)
{
ConfigureCrtcState state;
state.timestamp = timestamp;
state.has_error = FALSE;
state.error = error;
state.global_scale = *global_scale;
gnome_rr_screen_set_size (assign->screen, width, height, width_mm, height_mm);
g_hash_table_foreach (assign->info, configure_crtc, &state);
success = !state.has_error;
}
gnome_rr_screen_set_primary_output (assign->screen, assign->primary);
gdk_x11_display_ungrab (gdk_screen_get_display (assign->screen->priv->gdk_screen));
return success;
}
cinnamon-desktop-5.2.1/libcinnamon-desktop/gnome-pnp-ids.h 0000664 0001750 0001750 00000004510 14167325242 022510 0 ustar fabio fabio /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2009-2010 Richard Hughes
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __GNOME_PNP_IDS_H
#define __GNOME_PNP_IDS_H
#include
G_BEGIN_DECLS
#define GNOME_TYPE_PNP_IDSS (gnome_pnp_ids_get_type ())
#define GNOME_PNP_IDS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNOME_TYPE_PNP_IDSS, GnomePnpIds))
#define GNOME_PNP_IDS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GNOME_TYPE_PNP_IDSS, GnomePnpIdsClass))
#define GNOME_IS_PNP_IDSS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNOME_TYPE_PNP_IDSS))
#define GNOME_IS_PNP_IDSS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GNOME_TYPE_PNP_IDSS))
#define GNOME_PNP_IDS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GNOME_TYPE_PNP_IDSS, GnomePnpIdsClass))
#define GNOME_PNP_IDS_ERROR (gnome_pnp_ids_error_quark ())
typedef struct _GnomePnpIdsPrivate GnomePnpIdsPrivate;
typedef struct _GnomePnpIds GnomePnpIds;
typedef struct _GnomePnpIdsClass GnomePnpIdsClass;
struct _GnomePnpIds
{
GObject parent;
GnomePnpIdsPrivate *priv;
};
struct _GnomePnpIdsClass
{
GObjectClass parent_class;
};
GType gnome_pnp_ids_get_type (void);
GnomePnpIds *gnome_pnp_ids_new (void);
gchar *gnome_pnp_ids_get_pnp_id (GnomePnpIds *pnp_ids,
const gchar *pnp_id);
G_END_DECLS
#endif /* __GNOME_PNP_IDS_H */
cinnamon-desktop-5.2.1/libcinnamon-desktop/pnp.ids 0000664 0001750 0001750 00000027477 14167325242 021201 0 ustar fabio fabio
hwdata.git - Hardware Database, including Monitors, pci.ids, usb.ids, and video cards