From c1903572eb0e4c8df7fa0c6fc063d74acfe8aa9a Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Tue, 18 Jun 2024 21:24:11 +0000 Subject: Deploy mate-desktop/marco to github.com/mate-desktop/marco.git:gh-pages --- .../index.html | 185 + .../report-009c20.html | 1399 +++ .../report-064f1f.html | 3758 ++++++++ .../report-071a16.html | 1834 ++++ .../report-19e9c7.html | 1420 +++ .../report-2430c2.html | 3697 ++++++++ .../report-29575a.html | 1346 +++ .../report-3ed76c.html | 1416 +++ .../report-3eecf0.html | 816 ++ .../report-58a7de.html | 937 ++ .../report-641a36.html | 1807 ++++ .../report-658c39.html | 3169 +++++++ .../report-6885b9.html | 1807 ++++ .../report-6a7c12.html | 1117 +++ .../report-6ce2b4.html | 3697 ++++++++ .../report-6de546.html | 8014 ++++++++++++++++ .../report-79e718.html | 8003 ++++++++++++++++ .../report-82159e.html | 2038 ++++ .../report-857384.html | 8010 ++++++++++++++++ .../report-894891.html | 3187 +++++++ .../report-b7dd8c.html | 937 ++ .../report-c5605e.html | 1961 ++++ .../report-d1db2e.html | 8003 ++++++++++++++++ .../report-dac1a9.html | 9762 ++++++++++++++++++++ .../report-e47d9e.html | 3192 +++++++ .../report-e9815c.html | 3755 ++++++++ .../report-ec6e93.html | 1117 +++ .../report-ed0075.html | 3708 ++++++++ .../report-ef49e8.html | 8003 ++++++++++++++++ .../report-f74df1.html | 816 ++ .../scanview.css | 62 + .../sorttable.js | 492 + 32 files changed, 99465 insertions(+) create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/index.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-009c20.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-064f1f.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-071a16.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-19e9c7.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-2430c2.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-29575a.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3ed76c.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3eecf0.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-58a7de.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-641a36.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-658c39.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6885b9.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6a7c12.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6ce2b4.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6de546.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-79e718.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-82159e.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-857384.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-894891.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-b7dd8c.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-c5605e.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-d1db2e.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-dac1a9.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e47d9e.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e9815c.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ec6e93.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ed0075.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ef49e8.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-f74df1.html create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/scanview.css create mode 100644 2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/sorttable.js (limited to '2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp') diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/index.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/index.html new file mode 100644 index 00000000..ff9886b4 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/index.html @@ -0,0 +1,185 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@ca40eb176027
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 17.0.6 (Fedora 17.0.6-2.fc39) +
Date:Mon Apr 8 16:40:12 2024
+

Bug Summary

+ + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs29
Logic error
Cast region with wrong size2
Dereference of null pointer2
Out-of-bound access6
Result of operation is garbage or undefined2
Use fixed address1
Unused code
Dead assignment6
Unreachable code10
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Logic errorCast region with wrong sizeui/theme.cmeta_color_spec_new13244View Report
Logic errorCast region with wrong sizeui/theme.cmeta_draw_op_new31743View Report
Unused codeDead assignmentwm-tester/test-size-hints.cmain921View Report
Unused codeDead assignmentwm-tester/test-resizing.cmain1381View Report
Unused codeDead assignmentui/frames.cmeta_frames_button_press_event17791View Report
Unused codeDead assignmentwm-tester/test-resizing.cmain1391View Report
Unused codeDead assignmentcore/edge-resistance.cfind_nearest_position2041View Report
Unused codeDead assignmentwm-tester/test-size-hints.cmain911View Report
Logic errorDereference of null pointerui/theme-viewer.cmain89510View Report
Logic errorDereference of null pointercore/window.cidle_calc_showing16254View Report
Logic errorOut-of-bound accesscore/screen.cmeta_screen_get_natural_xinerama_list177931View Report
Logic errorOut-of-bound accesscore/async-getprop.casync_get_property_handler44820View Report
Logic errorOut-of-bound accesscore/async-getprop.casync_get_property_handler38519View Report
Logic errorOut-of-bound accesscore/xprops.cutf8_list_from_results47528View Report
Logic errorOut-of-bound accesscore/screen.cmeta_screen_get_natural_xinerama_list178129View Report
Logic errorOut-of-bound accesscore/screen.cmeta_screen_get_natural_xinerama_list173313View Report
Logic errorResult of operation is garbage or undefinedcore/prefs.cbutton_layout_handler15217View Report
Logic errorResult of operation is garbage or undefinedcore/prefs.cbutton_layout_equal13139View Report
Unused codeUnreachable codecore/util.cmeta_gravity_to_string5001View Report
Unused codeUnreachable codeui/frames.cmeta_frames_button_press_event17021View Report
Unused codeUnreachable codeui/theme-viewer.cmain8961View Report
Unused codeUnreachable codecore/prefs.cmeta_prefs_get_application_based15851View Report
Unused codeUnreachable codeui/theme-viewer.cmain9031View Report
Unused codeUnreachable codecore/bell.cmeta_bell_init4011View Report
Unused codeUnreachable codeui/theme.cmeta_image_fill_type_to_string68591View Report
Unused codeUnreachable codeui/theme.cmeta_gtk_shadow_to_string67831View Report
Unused codeUnreachable codecore/bell.cmeta_bell_init4091View Report
Unused codeUnreachable codeui/theme.cmeta_gtk_arrow_to_string68201View Report
Logic errorUse fixed addresscore/main.cmain4083View Report
+ + diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-009c20.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-009c20.html new file mode 100644 index 00000000..d14f2425 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-009c20.html @@ -0,0 +1,1399 @@ + + + +core/util.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/util.c
Warning:line 500, column 7
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name util.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/util.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco utilities */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 * Copyright (C) 2005 Elijah Newren
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25#define _GNU_SOURCE
26#define _POSIX_C_SOURCE200809L 200112L /* for fdopen() */
27
28#include <config.h>
29#include <glib/gi18n-lib.h>
30
31#include "util.h"
32#include "main.h"
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <errno(*__errno_location ()).h>
38#include <string.h>
39#include <X11/Xlib.h> /* must explicitly be included for Solaris; #326746 */
40#include <X11/Xutil.h> /* Just for the definition of the various gravities */
41
42#ifdef HAVE_BACKTRACE1
43#include <execinfo.h>
44void
45meta_print_backtrace (void)
46{
47 void *bt[500];
48 int bt_size;
49 int i;
50 char **syms;
51
52 bt_size = backtrace (bt, 500);
53
54 syms = backtrace_symbols (bt, bt_size);
55
56 i = 0;
57 while (i < bt_size)
58 {
59 meta_verbosemeta_verbose_real (" %s\n", syms[i]);
60 ++i;
61 }
62
63 free (syms);
64}
65#else
66void
67meta_print_backtrace (void)
68{
69 meta_verbosemeta_verbose_real ("Not compiled with backtrace support\n");
70}
71#endif
72
73static gboolean is_verbose = FALSE(0);
74static gboolean is_debugging = FALSE(0);
75static gboolean replace_current = FALSE(0);
76static int no_prefix = 0;
77
78#ifdef WITH_VERBOSE_MODE1
79static FILE* logfile = NULL((void*)0);
80
81static void
82ensure_logfile (void)
83{
84 if (logfile == NULL((void*)0) && g_getenv ("MARCO_USE_LOGFILE"))
85 {
86 char *filename = NULL((void*)0);
87 char *tmpl;
88 int fd;
89 GError *err;
90
91 tmpl = g_strdup_printf ("marco-%d-debug-log-XXXXXX",
92 (int) getpid ());
93
94 err = NULL((void*)0);
95 fd = g_file_open_tmp (tmpl,
96 &filename,
97 &err);
98
99 g_free (tmpl);
100
101 if (err != NULL((void*)0))
102 {
103 meta_warning (_("Failed to open debug log: %s\n")((char *) g_dgettext ("marco", "Failed to open debug log: %s\n"
))
,
104 err->message);
105 g_error_free (err);
106 return;
107 }
108
109 logfile = fdopen (fd, "w");
110
111 if (logfile == NULL((void*)0))
112 {
113 meta_warning (_("Failed to fdopen() log file %s: %s\n")((char *) g_dgettext ("marco", "Failed to fdopen() log file %s: %s\n"
))
,
114 filename, strerror (errno(*__errno_location ())));
115 close (fd);
116 }
117 else
118 {
119 g_printerr (_("Opened log file %s\n")((char *) g_dgettext ("marco", "Opened log file %s\n")), filename);
120 }
121
122 g_free (filename);
123 }
124}
125#endif
126
127gboolean
128meta_is_verbose (void)
129{
130 return is_verbose;
131}
132
133void
134meta_set_verbose (gboolean setting)
135{
136#ifndef WITH_VERBOSE_MODE1
137 if (setting)
138 meta_fatal (_("Marco was compiled without support for verbose mode\n")((char *) g_dgettext ("marco", "Marco was compiled without support for verbose mode\n"
))
);
139#else
140 if (setting)
141 ensure_logfile ();
142#endif
143
144 is_verbose = setting;
145}
146
147gboolean
148meta_is_debugging (void)
149{
150 return is_debugging;
151}
152
153void
154meta_set_debugging (gboolean setting)
155{
156#ifdef WITH_VERBOSE_MODE1
157 if (setting)
158 ensure_logfile ();
159#endif
160
161 is_debugging = setting;
162}
163
164gboolean
165meta_get_replace_current_wm (void)
166{
167 return replace_current;
168}
169
170void
171meta_set_replace_current_wm (gboolean setting)
172{
173 replace_current = setting;
174}
175
176char *
177meta_g_utf8_strndup (const gchar *src,
178 gsize n)
179{
180 const gchar *s = src;
181 while (n && *s)
182 {
183 s = g_utf8_next_char (s)(char *)((s) + g_utf8_skip[*(const guchar *)(s)]);
184 n--;
185 }
186
187 return g_strndup (src, s - src);
188}
189
190static int
191utf8_fputs (const char *str,
192 FILE *f)
193{
194 char *l;
195 int retval;
196
197 l = g_locale_from_utf8 (str, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
198
199 if (l == NULL((void*)0))
200 retval = fputs (str, f); /* just print it anyway, better than nothing */
201 else
202 retval = fputs (l, f);
203
204 g_free (l);
205
206 return retval;
207}
208
209#ifdef WITH_VERBOSE_MODE1
210void
211meta_debug_spew_real (const char *format, ...)
212{
213 va_list args;
214 gchar *str;
215 FILE *out;
216
217 g_return_if_fail (format != NULL)do { if ((format != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "format != NULL"); return
; } } while (0)
;
218
219 if (!is_debugging)
220 return;
221
222 va_start (args, format)__builtin_va_start(args, format);
223 str = g_strdup_vprintf (format, args);
224 va_end (args)__builtin_va_end(args);
225
226 out = logfile ? logfile : stderrstderr;
227
228 if (no_prefix == 0)
229 utf8_fputs (_("Window manager: ")((char *) g_dgettext ("marco", "Window manager: ")), out);
230 utf8_fputs (str, out);
231
232 fflush (out);
233
234 g_free (str);
235}
236#endif /* WITH_VERBOSE_MODE */
237
238#ifdef WITH_VERBOSE_MODE1
239void
240meta_verbose_real (const char *format, ...)
241{
242 va_list args;
243 gchar *str;
244 FILE *out;
245
246 g_return_if_fail (format != NULL)do { if ((format != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "format != NULL"); return
; } } while (0)
;
247
248 if (!is_verbose)
249 return;
250
251 va_start (args, format)__builtin_va_start(args, format);
252 str = g_strdup_vprintf (format, args);
253 va_end (args)__builtin_va_end(args);
254
255 out = logfile ? logfile : stderrstderr;
256
257 if (no_prefix == 0)
258 utf8_fputs ("Window manager: ", out);
259 utf8_fputs (str, out);
260
261 fflush (out);
262
263 g_free (str);
264}
265#endif /* WITH_VERBOSE_MODE */
266
267#ifdef WITH_VERBOSE_MODE1
268static const char*
269topic_name (MetaDebugTopic topic)
270{
271 switch (topic)
272 {
273 case META_DEBUG_FOCUS:
274 return "FOCUS";
275 case META_DEBUG_WORKAREA:
276 return "WORKAREA";
277 case META_DEBUG_STACK:
278 return "STACK";
279 case META_DEBUG_THEMES:
280 return "THEMES";
281 case META_DEBUG_SM:
282 return "SM";
283 case META_DEBUG_EVENTS:
284 return "EVENTS";
285 case META_DEBUG_WINDOW_STATE:
286 return "WINDOW_STATE";
287 case META_DEBUG_WINDOW_OPS:
288 return "WINDOW_OPS";
289 case META_DEBUG_PLACEMENT:
290 return "PLACEMENT";
291 case META_DEBUG_GEOMETRY:
292 return "GEOMETRY";
293 case META_DEBUG_PING:
294 return "PING";
295 case META_DEBUG_XINERAMA:
296 return "XINERAMA";
297 case META_DEBUG_KEYBINDINGS:
298 return "KEYBINDINGS";
299 case META_DEBUG_SYNC:
300 return "SYNC";
301 case META_DEBUG_ERRORS:
302 return "ERRORS";
303 case META_DEBUG_STARTUP:
304 return "STARTUP";
305 case META_DEBUG_PREFS:
306 return "PREFS";
307 case META_DEBUG_GROUPS:
308 return "GROUPS";
309 case META_DEBUG_RESIZING:
310 return "RESIZING";
311 case META_DEBUG_SHAPES:
312 return "SHAPES";
313 case META_DEBUG_COMPOSITOR:
314 return "COMPOSITOR";
315 case META_DEBUG_EDGE_RESISTANCE:
316 return "EDGE_RESISTANCE";
317 }
318
319 return "WM";
320}
321
322static int sync_count = 0;
323
324void
325meta_topic_real (MetaDebugTopic topic,
326 const char *format,
327 ...)
328{
329 va_list args;
330 gchar *str;
331 FILE *out;
332
333 g_return_if_fail (format != NULL)do { if ((format != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "format != NULL"); return
; } } while (0)
;
334
335 if (!is_verbose)
336 return;
337
338 va_start (args, format)__builtin_va_start(args, format);
339 str = g_strdup_vprintf (format, args);
340 va_end (args)__builtin_va_end(args);
341
342 out = logfile ? logfile : stderrstderr;
343
344 if (no_prefix == 0)
345 fprintf (out, "%s: ", topic_name (topic));
346
347 if (topic == META_DEBUG_SYNC)
348 {
349 ++sync_count;
350 fprintf (out, "%d: ", sync_count);
351 }
352
353 utf8_fputs (str, out);
354
355 fflush (out);
356
357 g_free (str);
358}
359#endif /* WITH_VERBOSE_MODE */
360
361void
362meta_bug (const char *format, ...)
363{
364 va_list args;
365 gchar *str;
366 FILE *out;
367
368 g_assert (format != NULL)do { if (format != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/util.c", 368, ((const char*) (__func__)), "format != NULL"
); } while (0)
;
369
370 va_start (args, format)__builtin_va_start(args, format);
371 str = g_strdup_vprintf (format, args);
372 va_end (args)__builtin_va_end(args);
373
374#ifdef WITH_VERBOSE_MODE1
375 out = logfile ? logfile : stderrstderr;
376#else
377 out = stderrstderr;
378#endif
379
380 if (no_prefix == 0)
381 utf8_fputs (_("Bug in window manager: ")((char *) g_dgettext ("marco", "Bug in window manager: ")), out);
382 utf8_fputs (str, out);
383
384 fflush (out);
385
386 g_free (str);
387
388 meta_print_backtrace ();
389
390 /* stop us in a debugger */
391 abort ();
392}
393
394void
395meta_warning (const char *format, ...)
396{
397 va_list args;
398 gchar *str;
399 FILE *out;
400
401 g_return_if_fail (format != NULL)do { if ((format != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "format != NULL"); return
; } } while (0)
;
402
403 va_start (args, format)__builtin_va_start(args, format);
404 str = g_strdup_vprintf (format, args);
405 va_end (args)__builtin_va_end(args);
406
407#ifdef WITH_VERBOSE_MODE1
408 out = logfile ? logfile : stderrstderr;
409#else
410 out = stderrstderr;
411#endif
412
413 if (no_prefix == 0)
414 utf8_fputs (_("Window manager warning: ")((char *) g_dgettext ("marco", "Window manager warning: ")), out);
415 utf8_fputs (str, out);
416
417 fflush (out);
418
419 g_free (str);
420}
421
422void
423meta_fatal (const char *format, ...)
424{
425 va_list args;
426 gchar *str;
427 FILE *out;
428
429 g_return_if_fail (format != NULL)do { if ((format != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "format != NULL"); return
; } } while (0)
;
430
431 va_start (args, format)__builtin_va_start(args, format);
432 str = g_strdup_vprintf (format, args);
433 va_end (args)__builtin_va_end(args);
434
435#ifdef WITH_VERBOSE_MODE1
436 out = logfile ? logfile : stderrstderr;
437#else
438 out = stderrstderr;
439#endif
440
441 if (no_prefix == 0)
442 utf8_fputs (_("Window manager error: ")((char *) g_dgettext ("marco", "Window manager error: ")), out);
443 utf8_fputs (str, out);
444
445 fflush (out);
446
447 g_free (str);
448
449 meta_exit (META_EXIT_ERROR);
450}
451
452void
453meta_push_no_msg_prefix (void)
454{
455 ++no_prefix;
456}
457
458void
459meta_pop_no_msg_prefix (void)
460{
461 g_return_if_fail (no_prefix > 0)do { if ((no_prefix > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "no_prefix > 0"); return
; } } while (0)
;
462
463 --no_prefix;
464}
465
466void
467meta_exit (MetaExitCode code)
468{
469
470 exit (code);
471}
472
473gint
474meta_unsigned_long_equal (gconstpointer v1,
475 gconstpointer v2)
476{
477 return *((const gulong*) v1) == *((const gulong*) v2);
478}
479
480guint
481meta_unsigned_long_hash (gconstpointer v)
482{
483 gulong val = * (const gulong *) v;
484
485 /* I'm not sure this works so well. */
486#if GLIB_SIZEOF_LONG8 > 4
487 return (guint) (val ^ (val >> 32));
488#else
489 return val;
490#endif
491}
492
493const char*
494meta_gravity_to_string (int gravity)
495{
496 switch (gravity)
497 {
498 case NorthWestGravity1:
499 return "NorthWestGravity";
500 break;
This statement is never executed
501 case NorthGravity2:
502 return "NorthGravity";
503 break;
504 case NorthEastGravity3:
505 return "NorthEastGravity";
506 break;
507 case WestGravity4:
508 return "WestGravity";
509 break;
510 case CenterGravity5:
511 return "CenterGravity";
512 break;
513 case EastGravity6:
514 return "EastGravity";
515 break;
516 case SouthWestGravity7:
517 return "SouthWestGravity";
518 break;
519 case SouthGravity8:
520 return "SouthGravity";
521 break;
522 case SouthEastGravity9:
523 return "SouthEastGravity";
524 break;
525 case StaticGravity10:
526 return "StaticGravity";
527 break;
528 default:
529 return "NorthWestGravity";
530 break;
531 }
532}
533
534GPid
535meta_show_dialog (const char *type,
536 const char *message,
537 const char *timeout,
538 const char *display,
539 const char *ok_text,
540 const char *cancel_text,
541 const int transient_for,
542 GSList *columns,
543 GSList *entries)
544{
545 GError *error = NULL((void*)0);
546 GSList *tmp;
547 int i=0;
548 GPid child_pid;
549 const char **argvl = g_malloc(sizeof (char*) *
550 (17 +
551 g_slist_length (columns)*2 +
552 g_slist_length (entries)));
553
554 argvl[i++] = "zenity";
555 argvl[i++] = type;
556 argvl[i++] = "--display";
557 argvl[i++] = display;
558 argvl[i++] = "--class";
559 argvl[i++] = "marco-dialog";
560 argvl[i++] = "--title";
561 /* Translators: This is the title used on dialog boxes */
562 argvl[i++] = _("Marco")((char *) g_dgettext ("marco", "Marco"));
563 argvl[i++] = "--text";
564 argvl[i++] = message;
565
566 if (timeout)
567 {
568 argvl[i++] = "--timeout";
569 argvl[i++] = timeout;
570 }
571
572 if (ok_text)
573 {
574 argvl[i++] = "--ok-label";
575 argvl[i++] = ok_text;
576 }
577
578 if (cancel_text)
579 {
580 argvl[i++] = "--cancel-label";
581 argvl[i++] = cancel_text;
582 }
583
584 tmp = columns;
585 while (tmp)
586 {
587 argvl[i++] = "--column";
588 argvl[i++] = tmp->data;
589 tmp = tmp->next;
590 }
591
592 tmp = entries;
593 while (tmp)
594 {
595 argvl[i++] = tmp->data;
596 tmp = tmp->next;
597 }
598
599 argvl[i] = NULL((void*)0);
600
601 if (transient_for)
602 {
603 gchar *env = g_strdup_printf("%d", transient_for);
604 setenv ("WINDOWID", env, 1);
605 g_free (env);
606 }
607
608 g_spawn_async (
609 "/",
610 (gchar**) argvl, /* ugh */
611 NULL((void*)0),
612 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
613 NULL((void*)0), NULL((void*)0),
614 &child_pid,
615 &error
616 );
617
618 if (transient_for)
619 unsetenv ("WINDOWID");
620
621 g_free (argvl);
622
623 if (error)
624 {
625 meta_warning ("%s\n", error->message);
626 g_error_free (error);
627 }
628
629 return child_pid;
630}
631
632GPid
633meta_show_entry_dialog(const char *message,
634 gint *active_workspace_id,
635 const char *entry_text,
636 const char *display,
637 const char *ok_text,
638 const char *cancel_text,
639 const int transient_for,
640 const GIOFunc stdio_func_cb)
641{
642 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
643 "meta_show_entry_dialog: called. active_workspace_id=%d message=%s entry_text=%s\n",
644 *active_workspace_id, message, entry_text);
645
646 GError *error = NULL((void*)0);
647 int i = 0;
648 GPid child_pid;
649 gint stdout_fd;
650 const char **argvl = g_malloc (sizeof (char *) * (17));
651
652 argvl[i++] = "zenity";
653 argvl[i++] = "--entry";
654 argvl[i++] = "--display";
655 argvl[i++] = display;
656 argvl[i++] = "--class";
657 argvl[i++] = "marco-dialog";
658 argvl[i++] = "--title";
659 /* Translators: This is the title used on dialog boxes */
660 argvl[i++] = _ ("Marco")((char *) g_dgettext ("marco", "Marco"));
661 argvl[i++] = "--text";
662 argvl[i++] = message;
663
664 if (entry_text)
665 {
666 argvl[i++] = "--entry-text";
667 argvl[i++] = entry_text;
668 }
669
670 if (ok_text)
671 {
672 argvl[i++] = "--ok-label";
673 argvl[i++] = ok_text;
674 }
675
676 if (cancel_text)
677 {
678 argvl[i++] = "--cancel-label";
679 argvl[i++] = cancel_text;
680 }
681 argvl[i] = NULL((void*)0);
682
683 unsetenv ("WINDOWID"); /* start in current workspace */
684 g_spawn_async_with_pipes (
685 "/",
686 (gchar **) argvl,
687 NULL((void*)0),
688 (GSpawnFlags) G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
689 NULL((void*)0),
690 NULL((void*)0),
691 &child_pid,
692 NULL((void*)0),
693 &stdout_fd,
694 NULL((void*)0),
695 &error
696 );
697
698 g_free (argvl);
699
700 if (error)
701 {
702 meta_warning ("%s\n", error->message);
703 g_error_free (error);
704 child_pid = -1;
705 }
706 else
707 {
708 GIOChannel *ioc = g_io_channel_unix_new(stdout_fd);
709 g_io_channel_set_encoding(ioc, NULL((void*)0), NULL((void*)0));
710 g_io_channel_set_buffered (ioc, FALSE(0));
711 g_io_channel_set_close_on_unref (ioc, TRUE(!(0)));
712 g_io_add_watch(ioc, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL, stdio_func_cb, active_workspace_id);
713 g_io_channel_unref(ioc);
714 }
715
716 return child_pid;
717}
718/* eof util.c */
719
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-064f1f.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-064f1f.html new file mode 100644 index 00000000..6c0670c0 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-064f1f.html @@ -0,0 +1,3758 @@ + + + +core/screen.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/screen.c
Warning:line 1779, column 11
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name screen.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/screen.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco X screen handler */
4
5/*
6 * Copyright (C) 2001, 2002 Havoc Pennington
7 * Copyright (C) 2002, 2003 Red Hat Inc.
8 * Some ICCCM manager selection code derived from fvwm2,
9 * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
10 * Copyright (C) 2003 Rob Adams
11 * Copyright (C) 2004-2006 Elijah Newren
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301, USA.
27 */
28
29#include <config.h>
30#include <glib/gi18n-lib.h>
31
32#include "screen-private.h"
33#include "util.h"
34#include "errors.h"
35#include "window-private.h"
36#include "frame-private.h"
37#include "prefs.h"
38#include "workspace.h"
39#include "keybindings.h"
40#include "prefs.h"
41#include "stack.h"
42#include "xprops.h"
43#include "compositor.h"
44
45#ifdef HAVE_SOLARIS_XINERAMA
46#include <X11/extensions/xinerama.h>
47#endif
48#ifdef HAVE_XFREE_XINERAMA
49#include <X11/extensions/Xinerama.h>
50#endif
51
52#include <X11/Xatom.h>
53#include <cairo/cairo-xlib.h>
54#include <locale.h>
55#include <string.h>
56#include <stdio.h>
57
58static char* get_screen_name (MetaDisplay *display,
59 int number);
60
61static void update_num_workspaces (MetaScreen *screen,
62 guint32 timestamp);
63static void update_focus_mode (MetaScreen *screen);
64static void set_workspace_names (MetaScreen *screen);
65static void prefs_changed_callback (MetaPreference pref,
66 gpointer data);
67
68static void set_desktop_geometry_hint (MetaScreen *screen);
69static void set_desktop_viewport_hint (MetaScreen *screen);
70
71#ifdef HAVE_STARTUP_NOTIFICATION
72static void meta_screen_sn_event (SnMonitorEvent *event,
73 void *user_data);
74#endif
75
76static int
77set_wm_check_hint (MetaScreen *screen)
78{
79 unsigned long data[1];
80
81 g_return_val_if_fail (screen->display->leader_window != None, 0)do { if ((screen->display->leader_window != 0L)) { } else
{ g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "screen->display->leader_window != None"); return (
0); } } while (0)
;
82
83 data[0] = screen->display->leader_window;
84
85 XChangeProperty (screen->display->xdisplay, screen->xroot,
86 screen->display->atom__NET_SUPPORTING_WM_CHECK,
87 XA_WINDOW((Atom) 33),
88 32, PropModeReplace0, (guchar*) data, 1);
89
90 return Success0;
91}
92
93static void
94unset_wm_check_hint (MetaScreen *screen)
95{
96 XDeleteProperty (screen->display->xdisplay, screen->xroot,
97 screen->display->atom__NET_SUPPORTING_WM_CHECK);
98}
99
100static int
101set_supported_hint (MetaScreen *screen)
102{
103 Atom atoms[] = {
104#define EWMH_ATOMS_ONLY
105#define item(x) screen->display->atom_##x,
106#include "atomnames.h"
107#undef item
108#undef EWMH_ATOMS_ONLY
109 screen->display->atom__GTK_FRAME_EXTENTS,
110 screen->display->atom__GTK_SHOW_WINDOW_MENU,
111 screen->display->atom__GTK_WORKAREAS
112 };
113
114 XChangeProperty (screen->display->xdisplay, screen->xroot,
115 screen->display->atom__NET_SUPPORTED,
116 XA_ATOM((Atom) 4),
117 32, PropModeReplace0,
118 (guchar*) atoms, G_N_ELEMENTS(atoms)(sizeof (atoms) / sizeof ((atoms)[0])));
119
120 return Success0;
121}
122
123static int
124set_wm_icon_size_hint (MetaScreen *screen)
125{
126 int icon_size = meta_prefs_get_icon_size();
127#define N_VALS 6
128 gulong vals[N_VALS];
129
130 /* min width, min height, max w, max h, width inc, height inc */
131 vals[0] = icon_size; /* width */
132 vals[1] = icon_size; /* height */
133 vals[2] = icon_size; /* width */
134 vals[3] = icon_size; /* height */
135 vals[4] = 0;
136 vals[5] = 0;
137
138 XChangeProperty (screen->display->xdisplay, screen->xroot,
139 screen->display->atom_WM_ICON_SIZE,
140 XA_CARDINAL((Atom) 6),
141 32, PropModeReplace0, (guchar*) vals, N_VALS);
142
143 return Success0;
144#undef N_VALS
145}
146
147static void
148reload_xinerama_infos (MetaScreen *screen)
149{
150 MetaDisplay *display;
151
152 {
153 GList *tmp;
154
155 tmp = screen->workspaces;
156 while (tmp != NULL((void*)0))
157 {
158 MetaWorkspace *space = tmp->data;
159
160 meta_workspace_invalidate_work_area (space);
161
162 tmp = tmp->next;
163 }
164 }
165
166 display = screen->display;
167
168 if (screen->xinerama_infos)
169 g_free (screen->xinerama_infos);
170
171 screen->xinerama_infos = NULL((void*)0);
172 screen->n_xinerama_infos = 0;
173 screen->last_xinerama_index = 0;
174
175 screen->display->xinerama_cache_invalidated = TRUE(!(0));
176
177#ifdef HAVE_XFREE_XINERAMA
178 if (XineramaIsActive (display->xdisplay))
179 {
180 XineramaScreenInfo *infos;
181 int n_infos;
182 int i;
183
184 n_infos = 0;
185 infos = XineramaQueryScreens (display->xdisplay, &n_infos);
186
187 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
188 "Found %d Xinerama screens on display %s\n",
189 n_infos, display->name);
190
191 if (n_infos > 0)
192 {
193 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos)((MetaXineramaScreenInfo *) g_malloc_n ((n_infos), sizeof (MetaXineramaScreenInfo
)))
;
194 screen->n_xinerama_infos = n_infos;
195
196 i = 0;
197 while (i < n_infos)
198 {
199 screen->xinerama_infos[i].number = infos[i].screen_number;
200 screen->xinerama_infos[i].rect.x = infos[i].x_org;
201 screen->xinerama_infos[i].rect.y = infos[i].y_org;
202 screen->xinerama_infos[i].rect.width = infos[i].width;
203 screen->xinerama_infos[i].rect.height = infos[i].height;
204
205 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
206 "Xinerama %d is %d,%d %d x %d\n",
207 screen->xinerama_infos[i].number,
208 screen->xinerama_infos[i].rect.x,
209 screen->xinerama_infos[i].rect.y,
210 screen->xinerama_infos[i].rect.width,
211 screen->xinerama_infos[i].rect.height);
212
213 ++i;
214 }
215 }
216
217 meta_XFree (infos)do { if ((infos)) XFree ((infos)); } while (0);
218 }
219 else
220 {
221 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
222 "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
223 display->name);
224 }
225#else
226 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
227 "Marco compiled without XFree86 Xinerama support\n");
228#endif /* HAVE_XFREE_XINERAMA */
229
230#ifdef HAVE_SOLARIS_XINERAMA
231 /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
232 if (screen->n_xinerama_infos == 0 &&
233 XineramaGetState (screen->display->xdisplay,
234 screen->number))
235 {
236 XRectangle monitors[MAXFRAMEBUFFERS];
237 unsigned char hints[16];
238 int result;
239 int n_monitors;
240 int i;
241
242 n_monitors = 0;
243 result = XineramaGetInfo (screen->display->xdisplay,
244 screen->number,
245 monitors, hints,
246 &n_monitors);
247 /* Yes I know it should be Success but the current implementation
248 * returns the num of monitor
249 */
250 if (result > 0)
251 {
252 g_assert (n_monitors > 0)do { if (n_monitors > 0) ; else g_assertion_message_expr (
"marco", "core/screen.c", 252, ((const char*) (__func__)), "n_monitors > 0"
); } while (0)
;
253
254 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors)((MetaXineramaScreenInfo *) g_malloc_n ((n_monitors), sizeof (
MetaXineramaScreenInfo)))
;
255 screen->n_xinerama_infos = n_monitors;
256
257 i = 0;
258 while (i < n_monitors)
259 {
260 screen->xinerama_infos[i].number = i;
261 screen->xinerama_infos[i].rect.x = monitors[i].x;
262 screen->xinerama_infos[i].rect.y = monitors[i].y;
263 screen->xinerama_infos[i].rect.width = monitors[i].width;
264 screen->xinerama_infos[i].rect.height = monitors[i].height;
265
266 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
267 "Xinerama %d is %d,%d %d x %d\n",
268 screen->xinerama_infos[i].number,
269 screen->xinerama_infos[i].rect.x,
270 screen->xinerama_infos[i].rect.y,
271 screen->xinerama_infos[i].rect.width,
272 screen->xinerama_infos[i].rect.height);
273
274 ++i;
275 }
276 }
277 }
278 else if (screen->n_xinerama_infos == 0)
279 {
280 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
281 "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
282 display->name);
283 }
284#else
285 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
286 "Marco compiled without Solaris Xinerama support\n");
287#endif /* HAVE_SOLARIS_XINERAMA */
288
289 /* If no Xinerama, fill in the single screen info so
290 * we can use the field unconditionally
291 */
292 if (screen->n_xinerama_infos == 0)
293 {
294 if (g_getenv ("MARCO_DEBUG_XINERAMA"))
295 {
296 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
297 "Pretending a single monitor has two Xinerama screens\n");
298
299 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2)((MetaXineramaScreenInfo *) g_malloc_n ((2), sizeof (MetaXineramaScreenInfo
)))
;
300 screen->n_xinerama_infos = 2;
301
302 screen->xinerama_infos[0].number = 0;
303 screen->xinerama_infos[0].rect = screen->rect;
304 screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
305
306 screen->xinerama_infos[1].number = 1;
307 screen->xinerama_infos[1].rect = screen->rect;
308 screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
309 screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
310 }
311 else
312 {
313 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
314 "No Xinerama screens, using default screen info\n");
315
316 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1)((MetaXineramaScreenInfo *) g_malloc_n ((1), sizeof (MetaXineramaScreenInfo
)))
;
317 screen->n_xinerama_infos = 1;
318
319 screen->xinerama_infos[0].number = 0;
320 screen->xinerama_infos[0].rect = screen->rect;
321 }
322 }
323
324 g_assert (screen->n_xinerama_infos > 0)do { if (screen->n_xinerama_infos > 0) ; else g_assertion_message_expr
("marco", "core/screen.c", 324, ((const char*) (__func__)), "screen->n_xinerama_infos > 0"
); } while (0)
;
325 g_assert (screen->xinerama_infos != NULL)do { if (screen->xinerama_infos != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 325, ((const char*) (__func__)), "screen->xinerama_infos != NULL"
); } while (0)
;
326}
327
328MetaScreen*
329meta_screen_new (MetaDisplay *display,
330 int number,
331 guint32 timestamp)
332{
333 MetaScreen *screen;
334 Window xroot;
335 Display *xdisplay;
336 XWindowAttributes attr;
337 Window new_wm_sn_owner;
338 Window current_wm_sn_owner;
339 gboolean replace_current_wm;
340 Atom wm_sn_atom;
341 char buf[128];
342 guint32 manager_timestamp;
343 gulong current_workspace;
344
345 replace_current_wm = meta_get_replace_current_wm ();
346
347 /* Only display->name, display->xdisplay, and display->error_traps
348 * can really be used in this function, since normally screens are
349 * created from the MetaDisplay constructor
350 */
351
352 xdisplay = display->xdisplay;
353
354 meta_verbosemeta_verbose_real ("Trying screen %d on display '%s'\n",
355 number, display->name);
356
357 xroot = RootWindow (xdisplay, number)((&((_XPrivDisplay)(xdisplay))->screens[number])->root
)
;
358
359 /* FVWM checks for None here, I don't know if this
360 * ever actually happens
361 */
362 if (xroot == None0L)
363 {
364 meta_warning (_("Screen %d on display '%s' is invalid\n")((char *) g_dgettext ("marco", "Screen %d on display '%s' is invalid\n"
))
,
365 number, display->name);
366 return NULL((void*)0);
367 }
368
369 sprintf (buf, "WM_S%d", number);
370 wm_sn_atom = XInternAtom (xdisplay, buf, False0);
371
372 current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
373
374 if (current_wm_sn_owner != None0L)
375 {
376 XSetWindowAttributes attrs;
377
378 if (!replace_current_wm)
379 {
380 meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n")((char *) g_dgettext ("marco", "Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"
))
,
381 number, display->name);
382
383 return NULL((void*)0);
384 }
385
386 /* We want to find out when the current selection owner dies */
387 meta_error_trap_push (display);
388 attrs.event_mask = StructureNotifyMask(1L<<17);
389 XChangeWindowAttributes (xdisplay,
390 current_wm_sn_owner, CWEventMask(1L<<11), &attrs);
391 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
392 current_wm_sn_owner = None0L; /* don't wait for it to die later on */
393 }
394
395 /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
396 * but those cannot be masked, so we only need NoEventMask.
397 */
398 new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask0L);
399
400 manager_timestamp = timestamp;
401
402 XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
403 manager_timestamp);
404
405 if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
406 {
407 meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n")((char *) g_dgettext ("marco", "Could not acquire window manager selection on screen %d display \"%s\"\n"
))
,
408 number, display->name);
409
410 XDestroyWindow (xdisplay, new_wm_sn_owner);
411
412 return NULL((void*)0);
413 }
414
415 {
416 /* Send client message indicating that we are now the WM */
417 XClientMessageEvent ev;
418
419 ev.type = ClientMessage33;
420 ev.window = xroot;
421 ev.message_type = display->atom_MANAGER;
422 ev.format = 32;
423 ev.data.l[0] = manager_timestamp;
424 ev.data.l[1] = wm_sn_atom;
425
426 XSendEvent (xdisplay, xroot, False0, StructureNotifyMask(1L<<17), (XEvent*)&ev);
427 }
428
429 /* Wait for old window manager to go away */
430 if (current_wm_sn_owner != None0L)
431 {
432 XEvent event;
433
434 /* We sort of block infinitely here which is probably lame. */
435
436 meta_verbosemeta_verbose_real ("Waiting for old window manager to exit\n");
437 do
438 {
439 XWindowEvent (xdisplay, current_wm_sn_owner,
440 StructureNotifyMask(1L<<17), &event);
441 }
442 while (event.type != DestroyNotify17);
443 }
444
445 /* select our root window events */
446 meta_error_trap_push (display);
447
448 /* We need to or with the existing event mask since
449 * gtk+ may be interested in other events.
450 */
451 XGetWindowAttributes (xdisplay, xroot, &attr);
452 XSelectInput (xdisplay,
453 xroot,
454 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19) |
455 ColormapChangeMask(1L<<23) | PropertyChangeMask(1L<<22) |
456 LeaveWindowMask(1L<<5) | EnterWindowMask(1L<<4) |
457 KeyPressMask(1L<<0) | KeyReleaseMask(1L<<1) |
458 FocusChangeMask(1L<<21) | StructureNotifyMask(1L<<17) |
459#ifdef HAVE_COMPOSITE_EXTENSIONS1
460 ExposureMask(1L<<15) |
461#endif
462 attr.your_event_mask);
463 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
464 {
465 meta_warning (_("Screen %d on display \"%s\" already has a window manager\n")((char *) g_dgettext ("marco", "Screen %d on display \"%s\" already has a window manager\n"
))
,
466 number, display->name);
467
468 XDestroyWindow (xdisplay, new_wm_sn_owner);
469
470 return NULL((void*)0);
471 }
472
473 screen = g_new (MetaScreen, 1)((MetaScreen *) g_malloc_n ((1), sizeof (MetaScreen)));
474 screen->closing = 0;
475
476 screen->display = display;
477 screen->number = number;
478 screen->screen_name = get_screen_name (display, number);
479 screen->xscreen = ScreenOfDisplay (xdisplay, number)(&((_XPrivDisplay)(xdisplay))->screens[number]);
480 screen->xroot = xroot;
481 screen->rect.x = screen->rect.y = 0;
482 screen->rect.width = WidthOfScreen (screen->xscreen)((screen->xscreen)->width);
483 screen->rect.height = HeightOfScreen (screen->xscreen)((screen->xscreen)->height);
484 screen->current_cursor = -1; /* invalid/unset */
485 screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen)((screen->xscreen)->root_visual);
486 screen->default_depth = DefaultDepthOfScreen (screen->xscreen)((screen->xscreen)->root_depth);
487 screen->flash_window = None0L;
488
489 screen->wm_sn_selection_window = new_wm_sn_owner;
490 screen->wm_sn_atom = wm_sn_atom;
491 screen->wm_sn_timestamp = manager_timestamp;
492
493#ifdef HAVE_COMPOSITE_EXTENSIONS1
494 g_snprintf (buf, sizeof(buf), "_NET_WM_CM_S%d", screen->number);
495 screen->wm_cm_atom = XInternAtom (screen->display->xdisplay, buf, FALSE(0));
496 screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
497 xroot,
498 NoEventMask0L);
499#endif
500 screen->work_area_idle = 0;
501
502 screen->active_workspace = NULL((void*)0);
503 screen->workspaces = NULL((void*)0);
504 screen->rows_of_workspaces = 1;
505 screen->columns_of_workspaces = -1;
506 screen->vertical_workspaces = FALSE(0);
507 screen->starting_corner = META_SCREEN_TOPLEFT;
508 screen->compositor_data = NULL((void*)0);
509
510 {
511 XFontStruct *font_info;
512 XGCValues gc_values;
513 gulong value_mask = 0;
514
515 gc_values.subwindow_mode = IncludeInferiors1;
516 value_mask |= GCSubwindowMode(1L<<15);
517 gc_values.function = GXinvert0xa;
518 value_mask |= GCFunction(1L<<0);
519 gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH2;
520 value_mask |= GCLineWidth(1L<<4);
521
522 font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
523
524 if (font_info != NULL((void*)0))
525 {
526 gc_values.font = font_info->fid;
527 value_mask |= GCFont(1L<<14);
528 XFreeFontInfo (NULL((void*)0), font_info, 1);
529 }
530 else
531 meta_warning ("xserver doesn't have 'fixed' font.\n");
532
533 screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
534 screen->xroot,
535 value_mask,
536 &gc_values);
537 }
538
539 screen->xinerama_infos = NULL((void*)0);
540 screen->n_xinerama_infos = 0;
541 screen->last_xinerama_index = 0;
542
543 reload_xinerama_infos (screen);
544
545 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
546
547 /* Handle creating a no_focus_window for this screen */
548 screen->no_focus_window =
549 meta_create_offscreen_window (display->xdisplay,
550 screen->xroot,
551 FocusChangeMask(1L<<21)|KeyPressMask(1L<<0)|KeyReleaseMask(1L<<1));
552 XMapWindow (display->xdisplay, screen->no_focus_window);
553 /* Done with no_focus_window stuff */
554
555 set_wm_icon_size_hint (screen);
556
557 set_supported_hint (screen);
558
559 set_wm_check_hint (screen);
560
561 set_desktop_viewport_hint (screen);
562
563 set_desktop_geometry_hint (screen);
564
565 meta_screen_update_workspace_layout (screen);
566
567 /* Get current workspace */
568 current_workspace = 0;
569 if (meta_prop_get_cardinal (screen->display,
570 screen->xroot,
571 screen->display->atom__NET_CURRENT_DESKTOP,
572 &current_workspace))
573 meta_verbosemeta_verbose_real ("Read existing _NET_CURRENT_DESKTOP = %d\n",
574 (int) current_workspace);
575 else
576 meta_verbosemeta_verbose_real ("No _NET_CURRENT_DESKTOP present\n");
577
578 /* Screens must have at least one workspace at all times,
579 * so create that required workspace.
580 */
581 meta_workspace_activate (meta_workspace_new (screen), timestamp);
582 update_num_workspaces (screen, timestamp);
583
584 set_workspace_names (screen);
585
586 screen->all_keys_grabbed = FALSE(0);
587 screen->keys_grabbed = FALSE(0);
588 meta_screen_grab_keys (screen);
589
590 screen->ui = meta_ui_new (screen->display->xdisplay,
591 screen->xscreen);
592
593 screen->tab_popup = NULL((void*)0);
594 screen->tile_preview = NULL((void*)0);
595
596 screen->tile_preview_timeout_id = 0;
597
598 screen->stack = meta_stack_new (screen);
599
600 meta_prefs_add_listener (prefs_changed_callback, screen);
601
602#ifdef HAVE_STARTUP_NOTIFICATION
603 screen->sn_context =
604 sn_monitor_context_new (screen->display->sn_display,
605 screen->number,
606 meta_screen_sn_event,
607 screen,
608 NULL((void*)0));
609 screen->startup_sequences = NULL((void*)0);
610 screen->startup_sequence_timeout = 0;
611#endif
612
613 /* Switch to the _NET_CURRENT_DESKTOP workspace */
614 {
615 MetaWorkspace *space;
616
617 space = meta_screen_get_workspace_by_index (screen,
618 current_workspace);
619
620 if (space != NULL((void*)0))
621 meta_workspace_activate (space, timestamp);
622 }
623
624 meta_verbosemeta_verbose_real ("Added screen %d ('%s') root 0x%lx\n",
625 screen->number, screen->screen_name, screen->xroot);
626
627 return screen;
628}
629
630void
631meta_screen_free (MetaScreen *screen,
632 guint32 timestamp)
633{
634 MetaDisplay *display;
635 XGCValues gc_values = { 0 };
636
637 display = screen->display;
638
639 screen->closing += 1;
640
641 meta_display_grab (display);
642
643 if (screen->display->compositor)
644 {
645 meta_compositor_unmanage_screen (screen->display->compositor,
646 screen);
647 }
648
649 meta_display_unmanage_windows_for_screen (display, screen, timestamp);
650
651 meta_prefs_remove_listener (prefs_changed_callback, screen);
652
653 meta_screen_ungrab_keys (screen);
654
655#ifdef HAVE_STARTUP_NOTIFICATION
656 g_slist_free_full (screen->startup_sequences,
657 (GDestroyNotify) sn_startup_sequence_unref);
658 screen->startup_sequences = NULL((void*)0);
659
660 if (screen->startup_sequence_timeout != 0)
661 {
662 g_source_remove (screen->startup_sequence_timeout);
663 screen->startup_sequence_timeout = 0;
664 }
665 if (screen->sn_context)
666 {
667 sn_monitor_context_unref (screen->sn_context);
668 screen->sn_context = NULL((void*)0);
669 }
670#endif
671
672 meta_ui_free (screen->ui);
673
674 meta_stack_free (screen->stack);
675
676 meta_error_trap_push (screen->display);
677 XSelectInput (screen->display->xdisplay, screen->xroot, 0);
678 if (meta_error_trap_pop_with_return (screen->display, FALSE(0)) != Success0)
679 meta_warning (_("Could not release screen %d on display \"%s\"\n")((char *) g_dgettext ("marco", "Could not release screen %d on display \"%s\"\n"
))
,
680 screen->number, screen->display->name);
681
682 unset_wm_check_hint (screen);
683
684 XDestroyWindow (screen->display->xdisplay,
685 screen->wm_sn_selection_window);
686
687 if (screen->work_area_idle != 0)
688 g_source_remove (screen->work_area_idle);
689
690 if (XGetGCValues (screen->display->xdisplay,
691 screen->root_xor_gc,
692 GCFont(1L<<14),
693 &gc_values))
694 {
695 XUnloadFont (screen->display->xdisplay,
696 gc_values.font);
697 }
698
699 XFreeGC (screen->display->xdisplay,
700 screen->root_xor_gc);
701
702 if (screen->xinerama_infos)
703 g_free (screen->xinerama_infos);
704
705 if (screen->tile_preview_timeout_id)
706 g_source_remove (screen->tile_preview_timeout_id);
707
708 if (screen->tile_preview)
709 meta_tile_preview_free (screen->tile_preview);
710
711 g_free (screen->screen_name);
712 g_free (screen);
713
714 XFlush (display->xdisplay);
715 meta_display_ungrab (display);
716}
717
718typedef struct
719{
720 Window xwindow;
721 XWindowAttributes attrs;
722} WindowInfo;
723
724static GList *
725list_windows (MetaScreen *screen)
726{
727 Window ignored1, ignored2;
728 Window *children;
729 guint n_children, i;
730 GList *result;
731
732 XQueryTree (screen->display->xdisplay,
733 screen->xroot,
734 &ignored1, &ignored2, &children, &n_children);
735
736 result = NULL((void*)0);
737 for (i = 0; i < n_children; ++i)
738 {
739 WindowInfo *info = g_new0 (WindowInfo, 1)((WindowInfo *) g_malloc0_n ((1), sizeof (WindowInfo)));
740
741 meta_error_trap_push (screen->display);
742
743 XGetWindowAttributes (screen->display->xdisplay,
744 children[i], &info->attrs);
745
746 if (meta_error_trap_pop_with_return (screen->display, TRUE(!(0))))
747 {
748 meta_verbosemeta_verbose_real ("Failed to get attributes for window 0x%lx\n",
749 children[i]);
750 g_free (info);
751 }
752 else
753 {
754 info->xwindow = children[i];
755 result = g_list_prepend (result, info);
756 }
757 }
758
759 if (children)
760 XFree (children);
761
762 return g_list_reverse (result);
763}
764
765void
766meta_screen_manage_all_windows (MetaScreen *screen)
767{
768 GList *windows;
769 GList *list;
770
771 meta_display_grab (screen->display);
772
773 windows = list_windows (screen);
774
775 meta_stack_freeze (screen->stack);
776 for (list = windows; list != NULL((void*)0); list = list->next)
777 {
778 WindowInfo *info = list->data;
779 MetaWindow *window;
780 gboolean test_window_owner;
781
782 window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE(!(0)),
783 &info->attrs);
784 test_window_owner = info->xwindow == screen->no_focus_window ||
785 info->xwindow == screen->flash_window ||
786 info->xwindow == screen->wm_sn_selection_window;
787
788#ifdef HAVE_COMPOSITE_EXTENSIONS1
789 test_window_owner = test_window_owner || info->xwindow == screen->wm_cm_selection_window;
790#endif
791 if (test_window_owner)
792 {
793 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
794 continue;
795 }
796
797 if (screen->display->compositor)
798 meta_compositor_add_window (screen->display->compositor, window,
799 info->xwindow, &info->attrs);
800 }
801 meta_stack_thaw (screen->stack);
802
803 g_list_free_full (windows, g_free);
804
805 meta_display_ungrab (screen->display);
806}
807
808void
809meta_screen_composite_all_windows (MetaScreen *screen)
810{
811#ifdef HAVE_COMPOSITE_EXTENSIONS1
812 MetaDisplay *display;
813 GList *windows, *list;
814
815 display = screen->display;
816 if (!display->compositor)
817 return;
818
819 windows = list_windows (screen);
820
821 meta_stack_freeze (screen->stack);
822
823 for (list = windows; list != NULL((void*)0); list = list->next)
824 {
825 WindowInfo *info = list->data;
826
827 if (info->xwindow == screen->no_focus_window ||
828 info->xwindow == screen->flash_window ||
829 info->xwindow == screen->wm_sn_selection_window ||
830 info->xwindow == screen->wm_cm_selection_window) {
831 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
832 continue;
833 }
834
835 meta_compositor_add_window (display->compositor,
836 meta_display_lookup_x_window (display,
837 info->xwindow),
838 info->xwindow, &info->attrs);
839 }
840
841 meta_stack_thaw (screen->stack);
842
843 g_list_free_full (windows, g_free);
844#endif
845}
846
847MetaScreen*
848meta_screen_for_x_screen (Screen *xscreen)
849{
850 MetaDisplay *display;
851
852 display = meta_display_for_x_display (DisplayOfScreen (xscreen)((xscreen)->display));
853
854 if (display == NULL((void*)0))
855 return NULL((void*)0);
856
857 return meta_display_screen_for_x_screen (display, xscreen);
858}
859
860static void
861prefs_changed_callback (MetaPreference pref,
862 gpointer data)
863{
864 MetaScreen *screen = data;
865
866 if (pref == META_PREF_NUM_WORKSPACES)
867 {
868 /* GSettings doesn't provide timestamps, but luckily update_num_workspaces
869 * often doesn't need it...
870 */
871 guint32 timestamp =
872 meta_display_get_current_time_roundtrip (screen->display);
873 update_num_workspaces (screen, timestamp);
874 }
875 else if (pref == META_PREF_FOCUS_MODE)
876 {
877 update_focus_mode (screen);
878 }
879 else if (pref == META_PREF_WORKSPACE_NAMES)
880 {
881 set_workspace_names (screen);
882 }
883}
884
885static char*
886get_screen_name (MetaDisplay *display,
887 int number)
888{
889 char *p;
890 char *dname;
891 char *scr;
892
893 /* DisplayString gives us a sort of canonical display,
894 * vs. the user-entered name from XDisplayName()
895 */
896 dname = g_strdup (DisplayString (display->xdisplay))g_strdup_inline ((((_XPrivDisplay)(display->xdisplay))->
display_name))
;
897
898 /* Change display name to specify this screen.
899 */
900 p = strrchr (dname, ':');
901 if (p)
902 {
903 p = strchr (p, '.');
904 if (p)
905 *p = '\0';
906 }
907
908 scr = g_strdup_printf ("%s.%d", dname, number);
909
910 g_free (dname);
911
912 return scr;
913}
914
915static gint
916ptrcmp (gconstpointer a, gconstpointer b)
917{
918 if (a < b)
919 return -1;
920 else if (a > b)
921 return 1;
922 else
923 return 0;
924}
925
926static void
927listify_func (gpointer key, gpointer value, gpointer data)
928{
929 GSList **listp;
930
931 listp = data;
932
933 *listp = g_slist_prepend (*listp, value);
934}
935
936void
937meta_screen_foreach_window (MetaScreen *screen,
938 MetaScreenWindowFunc func,
939 gpointer data)
940{
941 GSList *winlist;
942 GSList *tmp;
943
944 /* If we end up doing this often, just keeping a list
945 * of windows might be sensible.
946 */
947
948 winlist = NULL((void*)0);
949 g_hash_table_foreach (screen->display->window_ids,
950 listify_func,
951 &winlist);
952
953 winlist = g_slist_sort (winlist, ptrcmp);
954
955 tmp = winlist;
956 while (tmp != NULL((void*)0))
957 {
958 /* If the next node doesn't contain this window
959 * a second time, delete the window.
960 */
961 if (tmp->next == NULL((void*)0) ||
962 (tmp->next && tmp->next->data != tmp->data))
963 {
964 MetaWindow *window = tmp->data;
965
966 if (window->screen == screen)
967 (* func) (screen, window, data);
968 }
969
970 tmp = tmp->next;
971 }
972 g_slist_free (winlist);
973}
974
975static void
976queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
977{
978 if (window->frame)
979 meta_frame_queue_draw (window->frame);
980}
981
982void
983meta_screen_queue_frame_redraws (MetaScreen *screen)
984{
985 meta_screen_foreach_window (screen, queue_draw, NULL((void*)0));
986}
987
988static void
989queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
990{
991 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
992}
993
994void
995meta_screen_queue_window_resizes (MetaScreen *screen)
996{
997 meta_screen_foreach_window (screen, queue_resize, NULL((void*)0));
998}
999
1000int
1001meta_screen_get_n_workspaces (MetaScreen *screen)
1002{
1003 return g_list_length (screen->workspaces);
1004}
1005
1006MetaWorkspace*
1007meta_screen_get_workspace_by_index (MetaScreen *screen,
1008 int idx)
1009{
1010 GList *tmp;
1011 int i;
1012
1013 /* should be robust, idx is maybe from an app */
1014 if (idx < 0)
1015 return NULL((void*)0);
1016
1017 i = 0;
1018 tmp = screen->workspaces;
1019 while (tmp != NULL((void*)0))
1020 {
1021 MetaWorkspace *w = tmp->data;
1022
1023 if (i == idx)
1024 return w;
1025
1026 ++i;
1027 tmp = tmp->next;
1028 }
1029
1030 return NULL((void*)0);
1031}
1032
1033static void
1034set_number_of_spaces_hint (MetaScreen *screen,
1035 int n_spaces)
1036{
1037 unsigned long data[1];
1038
1039 if (screen->closing > 0)
1040 return;
1041
1042 data[0] = n_spaces;
1043
1044 meta_verbosemeta_verbose_real ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
1045
1046 meta_error_trap_push (screen->display);
1047 XChangeProperty (screen->display->xdisplay, screen->xroot,
1048 screen->display->atom__NET_NUMBER_OF_DESKTOPS,
1049 XA_CARDINAL((Atom) 6),
1050 32, PropModeReplace0, (guchar*) data, 1);
1051 meta_error_trap_pop (screen->display, FALSE(0));
1052}
1053
1054static void
1055set_desktop_geometry_hint (MetaScreen *screen)
1056{
1057 unsigned long data[2];
1058
1059 if (screen->closing > 0)
1060 return;
1061
1062 data[0] = screen->rect.width;
1063 data[1] = screen->rect.height;
1064
1065 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
1066
1067 meta_error_trap_push (screen->display);
1068 XChangeProperty (screen->display->xdisplay, screen->xroot,
1069 screen->display->atom__NET_DESKTOP_GEOMETRY,
1070 XA_CARDINAL((Atom) 6),
1071 32, PropModeReplace0, (guchar*) data, 2);
1072 meta_error_trap_pop (screen->display, FALSE(0));
1073}
1074
1075static void
1076set_desktop_viewport_hint (MetaScreen *screen)
1077{
1078 unsigned long data[2];
1079
1080 if (screen->closing > 0)
1081 return;
1082
1083 /*
1084 * Marco does not implement viewports, so this is a fixed 0,0
1085 */
1086 data[0] = 0;
1087 data[1] = 0;
1088
1089 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
1090
1091 meta_error_trap_push (screen->display);
1092 XChangeProperty (screen->display->xdisplay, screen->xroot,
1093 screen->display->atom__NET_DESKTOP_VIEWPORT,
1094 XA_CARDINAL((Atom) 6),
1095 32, PropModeReplace0, (guchar*) data, 2);
1096 meta_error_trap_pop (screen->display, FALSE(0));
1097}
1098
1099static void
1100update_num_workspaces (MetaScreen *screen,
1101 guint32 timestamp)
1102{
1103 int new_num;
1104 GList *tmp;
1105 int i;
1106 GList *extras;
1107 MetaWorkspace *last_remaining;
1108 gboolean need_change_space;
1109
1110 new_num = meta_prefs_get_num_workspaces ();
1111
1112 g_assert (new_num > 0)do { if (new_num > 0) ; else g_assertion_message_expr ("marco"
, "core/screen.c", 1112, ((const char*) (__func__)), "new_num > 0"
); } while (0)
;
1113
1114 last_remaining = NULL((void*)0);
1115 extras = NULL((void*)0);
1116 i = 0;
1117 tmp = screen->workspaces;
1118 while (tmp != NULL((void*)0))
1119 {
1120 MetaWorkspace *w = tmp->data;
1121
1122 if (i >= new_num)
1123 extras = g_list_prepend (extras, w);
1124 else
1125 last_remaining = w;
1126
1127 ++i;
1128 tmp = tmp->next;
1129 }
1130
1131 g_assert (last_remaining)do { if (last_remaining) ; else g_assertion_message_expr ("marco"
, "core/screen.c", 1131, ((const char*) (__func__)), "last_remaining"
); } while (0)
;
1132
1133 /* Get rid of the extra workspaces by moving all their windows
1134 * to last_remaining, then activating last_remaining if
1135 * one of the removed workspaces was active. This will be a bit
1136 * wacky if the config tool for changing number of workspaces
1137 * is on a removed workspace ;-)
1138 */
1139 need_change_space = FALSE(0);
1140 tmp = extras;
1141 while (tmp != NULL((void*)0))
1142 {
1143 MetaWorkspace *w = tmp->data;
1144
1145 meta_workspace_relocate_windows (w, last_remaining);
1146
1147 if (w == screen->active_workspace)
1148 need_change_space = TRUE(!(0));
1149
1150 tmp = tmp->next;
1151 }
1152
1153 if (need_change_space)
1154 meta_workspace_activate (last_remaining, timestamp);
1155
1156 /* Should now be safe to free the workspaces */
1157 tmp = extras;
1158 while (tmp != NULL((void*)0))
1159 {
1160 MetaWorkspace *w = tmp->data;
1161
1162 g_assert (w->windows == NULL)do { if (w->windows == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 1162, ((const char*) (__func__)),
"w->windows == NULL"); } while (0)
;
1163 meta_workspace_free (w);
1164
1165 tmp = tmp->next;
1166 }
1167
1168 g_list_free (extras);
1169
1170 while (i < new_num)
1171 {
1172 meta_workspace_new (screen);
1173 ++i;
1174 }
1175
1176 set_number_of_spaces_hint (screen, new_num);
1177
1178 meta_screen_queue_workarea_recalc (screen);
1179}
1180
1181static void
1182update_focus_mode (MetaScreen *screen)
1183{
1184 /* nothing to do anymore */ ;
1185}
1186
1187void
1188meta_screen_set_cursor (MetaScreen *screen,
1189 MetaCursor cursor)
1190{
1191 Cursor xcursor;
1192
1193 if (cursor == screen->current_cursor)
1194 return;
1195
1196 screen->current_cursor = cursor;
1197
1198 xcursor = meta_display_create_x_cursor (screen->display, cursor);
1199 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1200 XFlush (screen->display->xdisplay);
1201 XFreeCursor (screen->display->xdisplay, xcursor);
1202}
1203
1204void
1205meta_screen_update_cursor (MetaScreen *screen)
1206{
1207 Cursor xcursor;
1208
1209 xcursor = meta_display_create_x_cursor (screen->display,
1210 screen->current_cursor);
1211 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1212 XFlush (screen->display->xdisplay);
1213 XFreeCursor (screen->display->xdisplay, xcursor);
1214}
1215
1216#define MAX_PREVIEW_SCREEN_FRACTION0.33 0.33
1217#define MAX_PREVIEW_SIZE300.0 300.0
1218
1219static cairo_surface_t *
1220get_window_surface (MetaWindow *window)
1221{
1222 cairo_surface_t *surface, *scaled;
1223 cairo_t *cr;
1224 const MetaXineramaScreenInfo *current;
1225 int width, height, max_columns;
1226 double max_size;
1227 double ratio;
1228
1229 surface = meta_compositor_get_window_surface (window->display->compositor, window);
1230
1231 if (surface == NULL((void*)0))
1232 return NULL((void*)0);
1233
1234 width = cairo_xlib_surface_get_width (surface);
1235 height = cairo_xlib_surface_get_height (surface);
1236
1237 current = meta_screen_get_current_xinerama (window->screen);
1238 max_columns = meta_prefs_get_alt_tab_max_columns ();
1239
1240 /* Scale surface to fit current screen */
1241 if (width > height)
1242 {
1243 max_size = MIN (MAX_PREVIEW_SIZE, MAX_PREVIEW_SCREEN_FRACTION * ((double) current->rect.width) / ((double) max_columns))(((300.0) < (0.33 * ((double) current->rect.width) / ((
double) max_columns))) ? (300.0) : (0.33 * ((double) current->
rect.width) / ((double) max_columns)))
;
1244 ratio = ((double) width) / max_size;
1245 width = (int) max_size;
1246 height = (int) (((double) height) / ratio);
1247 }
1248 else
1249 {
1250 max_size = MIN (MAX_PREVIEW_SIZE, MAX_PREVIEW_SCREEN_FRACTION * ((double) current->rect.height) / ((double) max_columns))(((300.0) < (0.33 * ((double) current->rect.height) / (
(double) max_columns))) ? (300.0) : (0.33 * ((double) current
->rect.height) / ((double) max_columns)))
;
1251 ratio = ((double) height) / max_size;
1252 height = (int) max_size;
1253 width = (int) (((double) width) / ratio);
1254 }
1255
1256 meta_error_trap_push (window->display);
1257 scaled = cairo_surface_create_similar (surface,
1258 cairo_surface_get_content (surface),
1259 width, height);
1260 if (meta_error_trap_pop_with_return (window->display, FALSE(0)) != Success0)
1261 return NULL((void*)0);
1262
1263 cr = cairo_create (scaled);
1264 cairo_scale (cr, 1/ratio, 1/ratio);
1265 cairo_set_source_surface (cr, surface, 0, 0);
1266 cairo_paint (cr);
1267
1268 cairo_destroy (cr);
1269 cairo_surface_destroy (surface);
1270
1271 return scaled;
1272}
1273
1274void
1275meta_screen_ensure_tab_popup (MetaScreen *screen,
1276 MetaTabList list_type,
1277 MetaTabShowType show_type)
1278{
1279 MetaTabEntry *entries;
1280 GList *tab_list;
1281 GList *tmp;
1282 int len;
1283 int i;
1284 gint border;
1285 int scale;
1286
1287 if (screen->tab_popup)
1288 return;
1289
1290 tab_list = meta_display_get_tab_list (screen->display,
1291 list_type,
1292 screen,
1293 screen->active_workspace);
1294
1295 len = g_list_length (tab_list);
1296 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
1297
1298 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1299 entries[len].key = NULL((void*)0);
1300 entries[len].title = NULL((void*)0);
1301 entries[len].icon = NULL((void*)0);
1302 entries[len].win_surface = NULL((void*)0);
1303
1304 border = meta_prefs_show_tab_border() ? BORDER_OUTLINE_TAB |
1305 BORDER_OUTLINE_WINDOW : BORDER_OUTLINE_TAB;
1306 i = 0;
1307 tmp = tab_list;
1308 while (i < len)
1309 {
1310 MetaWindow *window;
1311 MetaRectangle r;
1312
1313 window = tmp->data;
1314
1315 entries[i].key = (MetaTabEntryKey) window->xwindow;
1316 entries[i].title = window->title;
1317 entries[i].win_surface = NULL((void*)0);
1318
1319 entries[i].icon = g_object_ref (window->icon)((__typeof__ (window->icon)) (g_object_ref) (window->icon
))
;
1320
1321 /* Only get the window thumbnail surface if the user has a compositor
1322 * enabled and does NOT have compositing-fast-alt-tab-set to true in
1323 * GSettings. There is an obvious lag when the surface is retrieved. */
1324 if (meta_prefs_get_compositing_manager() && !meta_prefs_get_compositing_fast_alt_tab())
1325 {
1326 cairo_surface_t *win_surface;
1327
1328 /* Get window thumbnail */
1329 win_surface = get_window_surface (window);
1330
1331 if (win_surface != NULL((void*)0))
1332 {
1333 cairo_surface_t *surface, *icon;
1334 cairo_t *cr;
1335 int width, height, icon_width, icon_height;
1336
1337#define ICON_OFFSET6 6
1338
1339 width = cairo_xlib_surface_get_width (win_surface);
1340 height = cairo_xlib_surface_get_height (win_surface);
1341
1342 /* Create a new surface to overlap the window icon into */
1343 surface = cairo_surface_create_similar (win_surface,
1344 cairo_surface_get_content (win_surface),
1345 width, height);
1346
1347 cr = cairo_create (surface);
1348 cairo_set_source_surface (cr, win_surface, 0, 0);
1349 cairo_paint (cr);
1350
1351 /* Get the window icon as a surface */
1352 icon = gdk_cairo_surface_create_from_pixbuf (window->icon, scale, NULL((void*)0));
1353
1354 icon_width = cairo_image_surface_get_width (icon) / scale;
1355 icon_height = cairo_image_surface_get_height (icon) / scale;
1356
1357 /* Overlap the window icon surface over the window thumbnail */
1358 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
1359 cairo_set_source_surface (cr, icon,
1360 width - icon_width - ICON_OFFSET6,
1361 height - icon_height - ICON_OFFSET6);
1362 cairo_paint (cr);
1363
1364 entries[i].win_surface = surface;
1365
1366 cairo_destroy (cr);
1367 cairo_surface_destroy (icon);
1368 cairo_surface_destroy (win_surface);
1369 }
1370 }
1371
1372 entries[i].blank = FALSE(0);
1373 entries[i].hidden = !meta_window_showing_on_its_workspace (window);
1374 entries[i].demands_attention = window->wm_state_demands_attention;
1375
1376 if (show_type == META_TAB_SHOW_INSTANTLY ||
1377 !entries[i].hidden ||
1378 !meta_window_get_icon_geometry (window, &r))
1379 meta_window_get_outer_rect (window, &r);
1380
1381 entries[i].rect = r;
1382
1383 /* Find inside of highlight rectangle to be used when window is
1384 * outlined for tabbing. This should be the size of the
1385 * east/west frame, and the size of the south frame, on those
1386 * sides. On the top it should be the size of the south frame
1387 * edge.
1388 */
1389 if (border & BORDER_OUTLINE_WINDOW)
1390 {
1391#define OUTLINE_WIDTH5 5
1392 /* Top side */
1393 entries[i].inner_rect.y = OUTLINE_WIDTH5;
1394
1395 /* Bottom side */
1396 entries[i].inner_rect.height = r.height - entries[i].inner_rect.y - OUTLINE_WIDTH5;
1397
1398 /* Left side */
1399 entries[i].inner_rect.x = OUTLINE_WIDTH5;
1400
1401 /* Right side */
1402 entries[i].inner_rect.width = r.width - entries[i].inner_rect.x - OUTLINE_WIDTH5;
1403 }
1404
1405 ++i;
1406 tmp = tmp->next;
1407 }
1408
1409 screen->tab_popup = meta_ui_tab_popup_new (entries,
1410 screen,
1411 len,
1412 meta_prefs_get_alt_tab_max_columns(),
1413 meta_prefs_get_alt_tab_expand_to_fit_title(),
1414 border);
1415
1416 for (i = 0; i < len; i++)
1417 {
1418 g_object_unref (entries[i].icon);
1419 if (entries[i].win_surface)
1420 cairo_surface_destroy (entries[i].win_surface);
1421 }
1422
1423 g_free (entries);
1424
1425 g_list_free (tab_list);
1426
1427 /* don't show tab popup, since proper window isn't selected yet */
1428}
1429
1430void
1431meta_screen_ensure_workspace_popup (MetaScreen *screen)
1432{
1433 MetaTabEntry *entries;
1434 int len;
1435 int i;
1436 MetaWorkspaceLayout layout;
1437 int n_workspaces;
1438 int current_workspace;
1439
1440 if (screen->tab_popup)
1441 return;
1442
1443 current_workspace = meta_workspace_index (screen->active_workspace);
1444 n_workspaces = meta_screen_get_n_workspaces (screen);
1445
1446 meta_screen_calc_workspace_layout (screen, n_workspaces,
1447 current_workspace, &layout);
1448
1449 len = layout.grid_area;
1450
1451 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1452 entries[len].key = NULL((void*)0);
1453 entries[len].title = NULL((void*)0);
1454 entries[len].icon = NULL((void*)0);
1455 entries[len].win_surface = NULL((void*)0);
1456
1457 i = 0;
1458 while (i < len)
1459 {
1460 if (layout.grid[i] >= 0)
1461 {
1462 MetaWorkspace *workspace;
1463
1464 workspace = meta_screen_get_workspace_by_index (screen,
1465 layout.grid[i]);
1466
1467 entries[i].key = (MetaTabEntryKey) workspace;
1468 entries[i].title = meta_workspace_get_name (workspace);
1469 entries[i].icon = NULL((void*)0);
1470 entries[i].win_surface = NULL((void*)0);
1471 entries[i].blank = FALSE(0);
1472
1473 g_assert (entries[i].title != NULL)do { if (entries[i].title != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 1473, ((const char*) (__func__)),
"entries[i].title != NULL"); } while (0)
;
1474 }
1475 else
1476 {
1477 entries[i].key = NULL((void*)0);
1478 entries[i].title = NULL((void*)0);
1479 entries[i].icon = NULL((void*)0);
1480 entries[i].win_surface = NULL((void*)0);
1481 entries[i].blank = TRUE(!(0));
1482 }
1483 entries[i].hidden = FALSE(0);
1484 entries[i].demands_attention = FALSE(0);
1485
1486 ++i;
1487 }
1488
1489 screen->tab_popup = meta_ui_tab_popup_new (entries,
1490 screen,
1491 len,
1492 layout.cols,
1493 FALSE(0), /* expand_for_titles */
1494 BORDER_OUTLINE_WORKSPACE);
1495
1496 g_free (entries);
1497 meta_screen_free_workspace_layout (&layout);
1498
1499 /* don't show tab popup, since proper space isn't selected yet */
1500}
1501
1502static gboolean
1503meta_screen_tile_preview_update_timeout (gpointer data)
1504{
1505 MetaScreen *screen = data;
1506 MetaWindow *window = screen->display->grab_window;
1507 gboolean needs_preview = FALSE(0);
1508
1509 screen->tile_preview_timeout_id = 0;
1510
1511 if (!screen->tile_preview)
1512 screen->tile_preview = meta_tile_preview_new ();
1513
1514 if (window)
1515 {
1516 switch (window->tile_mode)
1517 {
1518 case META_TILE_MAXIMIZED:
1519 if (!META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
)
1520 needs_preview = TRUE(!(0));
1521 break;
1522
1523 case META_TILE_NONE:
1524 needs_preview = FALSE(0);
1525 break;
1526
1527 default:
1528 if (!META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
)
1529 needs_preview = TRUE(!(0));
1530 break;
1531
1532 }
1533 }
1534
1535 if (needs_preview)
1536 {
1537 MetaRectangle tile_rect;
1538
1539 meta_window_get_current_tile_area (window, &tile_rect);
1540 meta_tile_preview_show (screen->tile_preview, &tile_rect, screen);
1541 }
1542 else
1543 meta_tile_preview_hide (screen->tile_preview);
1544
1545 return FALSE(0);
1546}
1547
1548#define TILE_PREVIEW_TIMEOUT_MS200 200
1549
1550void
1551meta_screen_tile_preview_update (MetaScreen *screen,
1552 gboolean delay)
1553{
1554 if (delay)
1555 {
1556 if (screen->tile_preview_timeout_id > 0)
1557 return;
1558
1559 screen->tile_preview_timeout_id =
1560 g_timeout_add (TILE_PREVIEW_TIMEOUT_MS200,
1561 meta_screen_tile_preview_update_timeout,
1562 screen);
1563 }
1564 else
1565 {
1566 if (screen->tile_preview_timeout_id > 0)
1567 g_source_remove (screen->tile_preview_timeout_id);
1568
1569 meta_screen_tile_preview_update_timeout ((gpointer)screen);
1570 }
1571}
1572
1573void
1574meta_screen_tile_preview_hide (MetaScreen *screen)
1575{
1576 if (screen->tile_preview_timeout_id > 0)
1577 g_source_remove (screen->tile_preview_timeout_id);
1578
1579 if (screen->tile_preview)
1580 meta_tile_preview_hide (screen->tile_preview);
1581}
1582
1583MetaWindow*
1584meta_screen_get_mouse_window (MetaScreen *screen,
1585 MetaWindow *not_this_one)
1586{
1587 MetaWindow *window;
1588 Window root_return, child_return;
1589 int root_x_return, root_y_return;
1590 int win_x_return, win_y_return;
1591 unsigned int mask_return;
1592
1593 if (not_this_one)
1594 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1595 "Focusing mouse window excluding %s\n", not_this_one->desc);
1596
1597 meta_error_trap_push (screen->display);
1598 XQueryPointer (screen->display->xdisplay,
1599 screen->xroot,
1600 &root_return,
1601 &child_return,
1602 &root_x_return,
1603 &root_y_return,
1604 &win_x_return,
1605 &win_y_return,
1606 &mask_return);
1607 meta_error_trap_pop (screen->display, TRUE(!(0)));
1608
1609 window = meta_stack_get_default_focus_window_at_point (screen->stack,
1610 screen->active_workspace,
1611 not_this_one,
1612 root_x_return,
1613 root_y_return);
1614
1615 return window;
1616}
1617
1618const MetaXineramaScreenInfo*
1619meta_screen_get_xinerama_for_rect (MetaScreen *screen,
1620 MetaRectangle *rect)
1621{
1622 int i;
1623 int best_xinerama, xinerama_score;
1624
1625 if (screen->n_xinerama_infos == 1)
1626 return &screen->xinerama_infos[0];
1627
1628 best_xinerama = 0;
1629 xinerama_score = 0;
1630
1631 for (i = 0; i < screen->n_xinerama_infos; i++)
1632 {
1633 MetaRectangle dest;
1634 if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
1635 rect,
1636 &dest))
1637 {
1638 int cur = meta_rectangle_area (&dest);
1639 if (cur > xinerama_score)
1640 {
1641 xinerama_score = cur;
1642 best_xinerama = i;
1643 }
1644 }
1645 }
1646
1647 return &screen->xinerama_infos[best_xinerama];
1648}
1649
1650const MetaXineramaScreenInfo*
1651meta_screen_get_xinerama_for_window (MetaScreen *screen,
1652 MetaWindow *window)
1653{
1654 MetaRectangle window_rect;
1655
1656 meta_window_get_outer_rect (window, &window_rect);
1657
1658 return meta_screen_get_xinerama_for_rect (screen, &window_rect);
1659}
1660
1661const MetaXineramaScreenInfo*
1662meta_screen_get_xinerama_neighbor (MetaScreen *screen,
1663 int which_xinerama,
1664 MetaScreenDirection direction)
1665{
1666 MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
1667 MetaXineramaScreenInfo* current;
1668 int i;
1669
1670 for (i = 0; i < screen->n_xinerama_infos; i++)
1671 {
1672 current = screen->xinerama_infos + i;
1673
1674 if ((direction == META_SCREEN_RIGHT &&
1675 current->rect.x == input->rect.x + input->rect.width &&
1676 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1677 (direction == META_SCREEN_LEFT &&
1678 input->rect.x == current->rect.x + current->rect.width &&
1679 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1680 (direction == META_SCREEN_UP &&
1681 input->rect.y == current->rect.y + current->rect.height &&
1682 meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
1683 (direction == META_SCREEN_DOWN &&
1684 current->rect.y == input->rect.y + input->rect.height &&
1685 meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
1686 {
1687 return current;
1688 }
1689 }
1690
1691 return NULL((void*)0);
1692}
1693
1694void
1695meta_screen_get_natural_xinerama_list (MetaScreen *screen,
1696 int** xineramas_list,
1697 int* n_xineramas)
1698{
1699 const MetaXineramaScreenInfo* current;
1700 const MetaXineramaScreenInfo* tmp;
1701 GQueue* xinerama_queue;
1702 int* visited;
1703 int cur = 0;
1704 int i;
1705
1706 *n_xineramas = screen->n_xinerama_infos;
1707 *xineramas_list = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1708
1709 /* we calculate a natural ordering by which to choose xineramas for
1710 * window placement. We start at the current xinerama, and perform
1711 * a breadth-first search of the xineramas starting from that
1712 * xinerama. We choose preferentially left, then right, then down,
1713 * then up. The visitation order produced by this traversal is the
1714 * natural xinerama ordering.
1715 */
1716
1717 visited = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1718 for (i = 0; i < screen->n_xinerama_infos; i++)
1
Assuming 'i' is < field 'n_xinerama_infos'
2
Loop condition is true. Entering loop body
3
Assuming 'i' is < field 'n_xinerama_infos'
4
Loop condition is true. Entering loop body
5
Assuming 'i' is < field 'n_xinerama_infos'
6
Loop condition is true. Entering loop body
7
Assuming 'i' is >= field 'n_xinerama_infos'
8
Loop condition is false. Execution continues on line 1723
1719 {
1720 visited[i] = FALSE(0);
1721 }
1722
1723 current = meta_screen_get_current_xinerama (screen);
1724 xinerama_queue = g_queue_new ();
1725 g_queue_push_tail (xinerama_queue, (gpointer) current);
1726 visited[current->number] = TRUE(!(0));
1727
1728 while (!g_queue_is_empty (xinerama_queue))
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
15
Assuming the condition is false
16
Loop condition is false. Execution continues on line 1777
1729 {
1730 current = (const MetaXineramaScreenInfo*)
1731 g_queue_pop_head (xinerama_queue);
1732
1733 (*xineramas_list)[cur++] = current->number;
1734
1735 /* enqueue each of the directions */
1736 tmp = meta_screen_get_xinerama_neighbor (screen,
1737 current->number,
1738 META_SCREEN_LEFT);
1739 if (tmp && !visited[tmp->number])
11
Assuming 'tmp' is null
1740 {
1741 g_queue_push_tail (xinerama_queue,
1742 (MetaXineramaScreenInfo*) tmp);
1743 visited[tmp->number] = TRUE(!(0));
1744 }
1745 tmp = meta_screen_get_xinerama_neighbor (screen,
1746 current->number,
1747 META_SCREEN_RIGHT);
1748 if (tmp && !visited[tmp->number])
12
Assuming 'tmp' is null
1749 {
1750 g_queue_push_tail (xinerama_queue,
1751 (MetaXineramaScreenInfo*) tmp);
1752 visited[tmp->number] = TRUE(!(0));
1753 }
1754 tmp = meta_screen_get_xinerama_neighbor (screen,
1755 current->number,
1756 META_SCREEN_UP);
1757 if (tmp && !visited[tmp->number])
13
Assuming 'tmp' is null
1758 {
1759 g_queue_push_tail (xinerama_queue,
1760 (MetaXineramaScreenInfo*) tmp);
1761 visited[tmp->number] = TRUE(!(0));
1762 }
1763 tmp = meta_screen_get_xinerama_neighbor (screen,
1764 current->number,
1765 META_SCREEN_DOWN);
1766 if (tmp && !visited[tmp->number])
14
Assuming 'tmp' is null
1767 {
1768 g_queue_push_tail (xinerama_queue,
1769 (MetaXineramaScreenInfo*) tmp);
1770 visited[tmp->number] = TRUE(!(0));
1771 }
1772 }
1773
1774 /* in case we somehow missed some set of xineramas, go through the
1775 * visited list and add in any xineramas that were missed
1776 */
1777 for (i = 0; i < screen->n_xinerama_infos; i++)
17
Assuming 'i' is < field 'n_xinerama_infos'
18
Loop condition is true. Entering loop body
21
Assuming 'i' is < field 'n_xinerama_infos'
22
Loop condition is true. Entering loop body
25
Assuming 'i' is < field 'n_xinerama_infos'
26
Loop condition is true. Entering loop body
29
Assuming 'i' is < field 'n_xinerama_infos'
30
Loop condition is true. Entering loop body
1778 {
1779 if (visited[i] == FALSE(0))
19
Assuming the condition is false
20
Taking false branch
23
Assuming the condition is false
24
Taking false branch
27
Assuming the condition is false
28
Taking false branch
31
Out of bound memory access (access exceeds upper limit of memory block)
1780 {
1781 (*xineramas_list)[cur++] = i;
1782 }
1783 }
1784
1785 g_free (visited);
1786 g_queue_free (xinerama_queue);
1787}
1788
1789const MetaXineramaScreenInfo*
1790meta_screen_get_current_xinerama (MetaScreen *screen)
1791{
1792 if (screen->n_xinerama_infos == 1)
1793 return &screen->xinerama_infos[0];
1794
1795 /* Sadly, we have to do it this way. Yuck.
1796 */
1797
1798 if (screen->display->xinerama_cache_invalidated)
1799 {
1800 Window root_return, child_return;
1801 int win_x_return, win_y_return;
1802 unsigned int mask_return;
1803 int i;
1804 MetaRectangle pointer_position;
1805
1806 screen->display->xinerama_cache_invalidated = FALSE(0);
1807
1808 pointer_position.width = pointer_position.height = 1;
1809 XQueryPointer (screen->display->xdisplay,
1810 screen->xroot,
1811 &root_return,
1812 &child_return,
1813 &pointer_position.x,
1814 &pointer_position.y,
1815 &win_x_return,
1816 &win_y_return,
1817 &mask_return);
1818
1819 screen->last_xinerama_index = 0;
1820 for (i = 0; i < screen->n_xinerama_infos; i++)
1821 {
1822 if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
1823 &pointer_position))
1824 {
1825 screen->last_xinerama_index = i;
1826 break;
1827 }
1828 }
1829
1830 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
1831 "Rechecked current Xinerama, now %d\n",
1832 screen->last_xinerama_index);
1833 }
1834
1835 return &screen->xinerama_infos[screen->last_xinerama_index];
1836}
1837
1838#define _NET_WM_ORIENTATION_HORZ0 0
1839#define _NET_WM_ORIENTATION_VERT1 1
1840
1841#define _NET_WM_TOPLEFT0 0
1842#define _NET_WM_TOPRIGHT1 1
1843#define _NET_WM_BOTTOMRIGHT2 2
1844#define _NET_WM_BOTTOMLEFT3 3
1845
1846void
1847meta_screen_update_workspace_layout (MetaScreen *screen)
1848{
1849 gulong *list;
1850 int n_items;
1851
1852 list = NULL((void*)0);
1853 n_items = 0;
1854
1855 if (meta_prop_get_cardinal_list (screen->display,
1856 screen->xroot,
1857 screen->display->atom__NET_DESKTOP_LAYOUT,
1858 &list, &n_items))
1859 {
1860 if (n_items == 3 || n_items == 4)
1861 {
1862 int cols, rows;
1863
1864 switch (list[0])
1865 {
1866 case _NET_WM_ORIENTATION_HORZ0:
1867 screen->vertical_workspaces = FALSE(0);
1868 break;
1869 case _NET_WM_ORIENTATION_VERT1:
1870 screen->vertical_workspaces = TRUE(!(0));
1871 break;
1872 default:
1873 meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
1874 break;
1875 }
1876
1877 cols = list[1];
1878 rows = list[2];
1879
1880 if (rows <= 0 && cols <= 0)
1881 {
1882 meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
1883 }
1884 else
1885 {
1886 if (rows > 0)
1887 screen->rows_of_workspaces = rows;
1888 else
1889 screen->rows_of_workspaces = -1;
1890
1891 if (cols > 0)
1892 screen->columns_of_workspaces = cols;
1893 else
1894 screen->columns_of_workspaces = -1;
1895 }
1896
1897 if (n_items == 4)
1898 {
1899 switch (list[3])
1900 {
1901 case _NET_WM_TOPLEFT0:
1902 screen->starting_corner = META_SCREEN_TOPLEFT;
1903 break;
1904 case _NET_WM_TOPRIGHT1:
1905 screen->starting_corner = META_SCREEN_TOPRIGHT;
1906 break;
1907 case _NET_WM_BOTTOMRIGHT2:
1908 screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
1909 break;
1910 case _NET_WM_BOTTOMLEFT3:
1911 screen->starting_corner = META_SCREEN_BOTTOMLEFT;
1912 break;
1913 default:
1914 meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
1915 break;
1916 }
1917 }
1918 else
1919 screen->starting_corner = META_SCREEN_TOPLEFT;
1920 }
1921 else
1922 {
1923 meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
1924 "(3 is accepted for backwards compat)\n", n_items);
1925 }
1926
1927 meta_XFree (list)do { if ((list)) XFree ((list)); } while (0);
1928 }
1929
1930 meta_verbosemeta_verbose_real ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
1931 screen->rows_of_workspaces,
1932 screen->columns_of_workspaces,
1933 screen->vertical_workspaces,
1934 screen->starting_corner);
1935}
1936
1937static void
1938set_workspace_names (MetaScreen *screen)
1939{
1940 /* This updates names on root window when the pref changes,
1941 * note we only get prefs change notify if things have
1942 * really changed.
1943 */
1944 GString *flattened;
1945 int i;
1946 int n_spaces;
1947
1948 /* flatten to nul-separated list */
1949 n_spaces = meta_screen_get_n_workspaces (screen);
1950 flattened = g_string_new ("");
1951 i = 0;
1952 while (i < n_spaces)
1953 {
1954 const char *name;
1955
1956 name = meta_prefs_get_workspace_name (i);
1957
1958 if (name)
1959 g_string_append_len (flattened, name,g_string_append_len_inline (flattened, name, strlen (name) + 1
)
1960 strlen (name) + 1)g_string_append_len_inline (flattened, name, strlen (name) + 1
)
;
1961 else
1962 g_string_append_len (flattened, "", 1)g_string_append_len_inline (flattened, "", 1);
1963
1964 ++i;
1965 }
1966
1967 meta_error_trap_push (screen->display);
1968 XChangeProperty (screen->display->xdisplay,
1969 screen->xroot,
1970 screen->display->atom__NET_DESKTOP_NAMES,
1971 screen->display->atom_UTF8_STRING,
1972 8, PropModeReplace0,
1973 (unsigned char *)flattened->str, flattened->len);
1974 meta_error_trap_pop (screen->display, FALSE(0));
1975
1976 g_string_free (flattened, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(flattened), ((!(0)))) : g_string_free_and_steal (flattened))
: (g_string_free) ((flattened), ((!(0)))))
;
1977}
1978
1979void
1980meta_screen_update_workspace_names (MetaScreen *screen)
1981{
1982 char **names;
1983 int n_names;
1984 int i;
1985
1986 /* this updates names in prefs when the root window property changes,
1987 * iff the new property contents don't match what's already in prefs
1988 */
1989
1990 names = NULL((void*)0);
1991 n_names = 0;
1992 if (!meta_prop_get_utf8_list (screen->display,
1993 screen->xroot,
1994 screen->display->atom__NET_DESKTOP_NAMES,
1995 &names, &n_names))
1996 {
1997 meta_verbosemeta_verbose_real ("Failed to get workspace names from root window %d\n",
1998 screen->number);
1999 return;
2000 }
2001
2002 i = 0;
2003 while (i < n_names)
2004 {
2005 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2006 "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
2007 i, names[i] ? names[i] : "null");
2008 meta_prefs_change_workspace_name (i, names[i]);
2009
2010 ++i;
2011 }
2012
2013 g_strfreev (names);
2014}
2015
2016Window
2017meta_create_offscreen_window (Display *xdisplay,
2018 Window parent,
2019 long valuemask)
2020{
2021 XSetWindowAttributes attrs;
2022
2023 /* we want to be override redirect because sometimes we
2024 * create a window on a screen we aren't managing.
2025 * (but on a display we are managing at least one screen for)
2026 */
2027 attrs.override_redirect = True1;
2028 attrs.event_mask = valuemask;
2029
2030 return XCreateWindow (xdisplay,
2031 parent,
2032 -100, -100, 1, 1,
2033 0,
2034 CopyFromParent0L,
2035 CopyFromParent0L,
2036 (Visual *)CopyFromParent0L,
2037 CWOverrideRedirect(1L<<9) | CWEventMask(1L<<11),
2038 &attrs);
2039}
2040
2041static void
2042set_workspace_work_area_hint (MetaWorkspace *workspace,
2043 MetaScreen *screen)
2044{
2045 unsigned long *data;
2046 unsigned long *tmp;
2047 int i;
2048 gchar *workarea_name;
2049 Atom workarea_atom;
2050
2051 data = g_new (unsigned long, screen->n_xinerama_infos * 4)((unsigned long *) g_malloc_n ((screen->n_xinerama_infos *
4), sizeof (unsigned long)))
;
2052 tmp = data;
2053
2054 for (i = 0; i < screen->n_xinerama_infos; i++)
2055 {
2056 MetaRectangle area;
2057
2058 meta_workspace_get_work_area_for_xinerama (workspace, i, &area);
2059
2060 tmp[0] = area.x;
2061 tmp[1] = area.y;
2062 tmp[2] = area.width;
2063 tmp[3] = area.height;
2064
2065 tmp += 4;
2066 }
2067
2068 workarea_name = g_strdup_printf ("_GTK_WORKAREAS_D%d",
2069 meta_workspace_index (workspace));
2070
2071 workarea_atom = XInternAtom (screen->display->xdisplay, workarea_name, False0);
2072 g_free (workarea_name);
2073
2074 meta_error_trap_push (screen->display);
2075 XChangeProperty (screen->display->xdisplay, screen->xroot, workarea_atom,
2076 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2077 (guchar*) data, screen->n_xinerama_infos * 4);
2078 meta_error_trap_pop (screen->display, TRUE(!(0)));
2079
2080 g_free (data);
2081}
2082
2083static void
2084set_work_area_hint (MetaScreen *screen)
2085{
2086 int num_workspaces;
2087 GList *tmp_list;
2088 unsigned long *data, *tmp;
2089 MetaRectangle area;
2090
2091 num_workspaces = meta_screen_get_n_workspaces (screen);
2092 data = g_new (unsigned long, num_workspaces * 4)((unsigned long *) g_malloc_n ((num_workspaces * 4), sizeof (
unsigned long)))
;
2093 tmp_list = screen->workspaces;
2094 tmp = data;
2095
2096 while (tmp_list != NULL((void*)0))
2097 {
2098 MetaWorkspace *workspace = tmp_list->data;
2099
2100 if (workspace->screen == screen)
2101 {
2102 meta_workspace_get_work_area_all_xineramas (workspace, &area);
2103 set_workspace_work_area_hint (workspace, screen);
2104 tmp[0] = area.x;
2105 tmp[1] = area.y;
2106 tmp[2] = area.width;
2107 tmp[3] = area.height;
2108
2109 tmp += 4;
2110 }
2111
2112 tmp_list = tmp_list->next;
2113 }
2114
2115 meta_error_trap_push (screen->display);
2116 XChangeProperty (screen->display->xdisplay, screen->xroot,
2117 screen->display->atom__NET_WORKAREA,
2118 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2119 (guchar*) data, num_workspaces*4);
2120 g_free (data);
2121 meta_error_trap_pop (screen->display, FALSE(0));
2122}
2123
2124static gboolean
2125set_work_area_idle_func (MetaScreen *screen)
2126{
2127 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2128 "Running work area idle function\n");
2129
2130 screen->work_area_idle = 0;
2131
2132 set_work_area_hint (screen);
2133
2134 return FALSE(0);
2135}
2136
2137void
2138meta_screen_queue_workarea_recalc (MetaScreen *screen)
2139{
2140 /* Recompute work area in an idle */
2141 if (screen->work_area_idle == 0)
2142 {
2143 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2144 "Adding work area hint idle function\n");
2145 screen->work_area_idle =
2146 g_idle_add_full (META_PRIORITY_WORK_AREA_HINT(200 + 15),
2147 (GSourceFunc) set_work_area_idle_func,
2148 screen,
2149 NULL((void*)0));
2150 }
2151}
2152
2153#ifdef WITH_VERBOSE_MODE1
2154static char *
2155meta_screen_corner_to_string (MetaScreenCorner corner)
2156{
2157 switch (corner)
2158 {
2159 case META_SCREEN_TOPLEFT:
2160 return "TopLeft";
2161 case META_SCREEN_TOPRIGHT:
2162 return "TopRight";
2163 case META_SCREEN_BOTTOMLEFT:
2164 return "BottomLeft";
2165 case META_SCREEN_BOTTOMRIGHT:
2166 return "BottomRight";
2167 }
2168
2169 return "Unknown";
2170}
2171#endif /* WITH_VERBOSE_MODE */
2172
2173void
2174meta_screen_calc_workspace_layout (MetaScreen *screen,
2175 int num_workspaces,
2176 int current_space,
2177 MetaWorkspaceLayout *layout)
2178{
2179 int rows, cols;
2180 int grid_area;
2181 int *grid;
2182 int i, r, c;
2183 int current_row, current_col;
2184
2185 rows = screen->rows_of_workspaces;
2186 cols = screen->columns_of_workspaces;
2187 if (rows <= 0 && cols <= 0)
2188 cols = num_workspaces;
2189
2190 if (rows <= 0)
2191 rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
2192 if (cols <= 0)
2193 cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
2194
2195 /* paranoia */
2196 if (rows < 1)
2197 rows = 1;
2198 if (cols < 1)
2199 cols = 1;
2200
2201 g_assert (rows != 0 && cols != 0)do { if (rows != 0 && cols != 0) ; else g_assertion_message_expr
("marco", "core/screen.c", 2201, ((const char*) (__func__)),
"rows != 0 && cols != 0"); } while (0)
;
2202
2203 grid_area = rows * cols;
2204
2205 meta_verbosemeta_verbose_real ("Getting layout rows = %d cols = %d current = %d "
2206 "num_spaces = %d vertical = %s corner = %s\n",
2207 rows, cols, current_space, num_workspaces,
2208 screen->vertical_workspaces ? "(true)" : "(false)",
2209 meta_screen_corner_to_string (screen->starting_corner));
2210
2211 /* ok, we want to setup the distances in the workspace array to go
2212 * in each direction. Remember, there are many ways that a workspace
2213 * array can be setup.
2214 * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
2215 * and look at the _NET_DESKTOP_LAYOUT section for details.
2216 * For instance:
2217 */
2218 /* starting_corner = META_SCREEN_TOPLEFT
2219 * vertical_workspaces = 0 vertical_workspaces=1
2220 * 1234 1357
2221 * 5678 2468
2222 *
2223 * starting_corner = META_SCREEN_TOPRIGHT
2224 * vertical_workspaces = 0 vertical_workspaces=1
2225 * 4321 7531
2226 * 8765 8642
2227 *
2228 * starting_corner = META_SCREEN_BOTTOMLEFT
2229 * vertical_workspaces = 0 vertical_workspaces=1
2230 * 5678 2468
2231 * 1234 1357
2232 *
2233 * starting_corner = META_SCREEN_BOTTOMRIGHT
2234 * vertical_workspaces = 0 vertical_workspaces=1
2235 * 8765 8642
2236 * 4321 7531
2237 *
2238 */
2239 /* keep in mind that we could have a ragged layout, e.g. the "8"
2240 * in the above grids could be missing
2241 */
2242
2243 grid = g_new (int, grid_area)((int *) g_malloc_n ((grid_area), sizeof (int)));
2244
2245 i = 0;
2246 switch (screen->starting_corner)
2247 {
2248 case META_SCREEN_TOPLEFT:
2249 if (screen->vertical_workspaces)
2250 {
2251 c = 0;
2252 while (c < cols)
2253 {
2254 r = 0;
2255 while (r < rows)
2256 {
2257 grid[r*cols+c] = i;
2258 ++i;
2259 ++r;
2260 }
2261 ++c;
2262 }
2263 }
2264 else
2265 {
2266 r = 0;
2267 while (r < rows)
2268 {
2269 c = 0;
2270 while (c < cols)
2271 {
2272 grid[r*cols+c] = i;
2273 ++i;
2274 ++c;
2275 }
2276 ++r;
2277 }
2278 }
2279 break;
2280 case META_SCREEN_TOPRIGHT:
2281 if (screen->vertical_workspaces)
2282 {
2283 c = cols - 1;
2284 while (c >= 0)
2285 {
2286 r = 0;
2287 while (r < rows)
2288 {
2289 grid[r*cols+c] = i;
2290 ++i;
2291 ++r;
2292 }
2293 --c;
2294 }
2295 }
2296 else
2297 {
2298 r = 0;
2299 while (r < rows)
2300 {
2301 c = cols - 1;
2302 while (c >= 0)
2303 {
2304 grid[r*cols+c] = i;
2305 ++i;
2306 --c;
2307 }
2308 ++r;
2309 }
2310 }
2311 break;
2312 case META_SCREEN_BOTTOMLEFT:
2313 if (screen->vertical_workspaces)
2314 {
2315 c = 0;
2316 while (c < cols)
2317 {
2318 r = rows - 1;
2319 while (r >= 0)
2320 {
2321 grid[r*cols+c] = i;
2322 ++i;
2323 --r;
2324 }
2325 ++c;
2326 }
2327 }
2328 else
2329 {
2330 r = rows - 1;
2331 while (r >= 0)
2332 {
2333 c = 0;
2334 while (c < cols)
2335 {
2336 grid[r*cols+c] = i;
2337 ++i;
2338 ++c;
2339 }
2340 --r;
2341 }
2342 }
2343 break;
2344 case META_SCREEN_BOTTOMRIGHT:
2345 if (screen->vertical_workspaces)
2346 {
2347 c = cols - 1;
2348 while (c >= 0)
2349 {
2350 r = rows - 1;
2351 while (r >= 0)
2352 {
2353 grid[r*cols+c] = i;
2354 ++i;
2355 --r;
2356 }
2357 --c;
2358 }
2359 }
2360 else
2361 {
2362 r = rows - 1;
2363 while (r >= 0)
2364 {
2365 c = cols - 1;
2366 while (c >= 0)
2367 {
2368 grid[r*cols+c] = i;
2369 ++i;
2370 --c;
2371 }
2372 --r;
2373 }
2374 }
2375 break;
2376 }
2377
2378 if (i != grid_area)
2379 meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
2380 G_STRFUNC((const char*) (__func__)), i);
2381
2382 current_row = 0;
2383 current_col = 0;
2384 r = 0;
2385 while (r < rows)
2386 {
2387 c = 0;
2388 while (c < cols)
2389 {
2390 if (grid[r*cols+c] == current_space)
2391 {
2392 current_row = r;
2393 current_col = c;
2394 }
2395 else if (grid[r*cols+c] >= num_workspaces)
2396 {
2397 /* flag nonexistent spaces with -1 */
2398 grid[r*cols+c] = -1;
2399 }
2400 ++c;
2401 }
2402 ++r;
2403 }
2404
2405 layout->rows = rows;
2406 layout->cols = cols;
2407 layout->grid = grid;
2408 layout->grid_area = grid_area;
2409 layout->current_row = current_row;
2410 layout->current_col = current_col;
2411
2412#ifdef WITH_VERBOSE_MODE1
2413 if (meta_is_verbose ())
2414 {
2415 r = 0;
2416 while (r < layout->rows)
2417 {
2418 meta_verbosemeta_verbose_real (" ");
2419 meta_push_no_msg_prefix ();
2420 c = 0;
2421 while (c < layout->cols)
2422 {
2423 if (r == layout->current_row &&
2424 c == layout->current_col)
2425 meta_verbosemeta_verbose_real ("*%2d ", layout->grid[r*layout->cols+c]);
2426 else
2427 meta_verbosemeta_verbose_real ("%3d ", layout->grid[r*layout->cols+c]);
2428 ++c;
2429 }
2430 meta_verbosemeta_verbose_real ("\n");
2431 meta_pop_no_msg_prefix ();
2432 ++r;
2433 }
2434 }
2435#endif /* WITH_VERBOSE_MODE */
2436}
2437
2438void
2439meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
2440{
2441 g_free (layout->grid);
2442}
2443
2444static void
2445meta_screen_resize_func (MetaScreen *screen,
2446 MetaWindow *window,
2447 void *user_data)
2448{
2449 if (window->struts)
2450 {
2451 meta_window_update_struts (window);
2452 }
2453 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2454
2455 meta_window_recalc_features (window);
2456}
2457
2458void
2459meta_screen_resize (MetaScreen *screen,
2460 int width,
2461 int height)
2462{
2463 screen->rect.width = width;
2464 screen->rect.height = height;
2465
2466 reload_xinerama_infos (screen);
2467 set_desktop_geometry_hint (screen);
2468
2469 /* Queue a resize on all the windows */
2470 meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
2471}
2472
2473void
2474meta_screen_update_showing_desktop_hint (MetaScreen *screen)
2475{
2476 unsigned long data[1];
2477
2478 data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
2479
2480 meta_error_trap_push (screen->display);
2481 XChangeProperty (screen->display->xdisplay, screen->xroot,
2482 screen->display->atom__NET_SHOWING_DESKTOP,
2483 XA_CARDINAL((Atom) 6),
2484 32, PropModeReplace0, (guchar*) data, 1);
2485 meta_error_trap_pop (screen->display, FALSE(0));
2486}
2487
2488static void
2489queue_windows_showing (MetaScreen *screen)
2490{
2491 GSList *windows;
2492 GSList *tmp;
2493
2494 /* Must operate on all windows on display instead of just on the
2495 * active_workspace's window list, because the active_workspace's
2496 * window list may not contain the on_all_workspace windows.
2497 */
2498 windows = meta_display_list_windows (screen->display);
2499
2500 tmp = windows;
2501 while (tmp != NULL((void*)0))
2502 {
2503 MetaWindow *w = tmp->data;
2504
2505 if (w->screen == screen && !meta_prefs_is_in_skip_list (w->res_class))
2506 meta_window_queue (w, META_QUEUE_CALC_SHOWING);
2507
2508 tmp = tmp->next;
2509 }
2510
2511 g_slist_free (windows);
2512}
2513
2514void
2515meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
2516 MetaWindow *keep)
2517{
2518 GList *windows;
2519 GList *tmp;
2520
2521 windows = screen->active_workspace->windows;
2522
2523 tmp = windows;
2524 while (tmp != NULL((void*)0))
2525 {
2526 MetaWindow *w = tmp->data;
2527
2528 if (w->screen == screen &&
2529 w->has_minimize_func &&
2530 w != keep)
2531 meta_window_minimize (w);
2532
2533 tmp = tmp->next;
2534 }
2535}
2536
2537void
2538meta_screen_show_desktop (MetaScreen *screen,
2539 guint32 timestamp)
2540{
2541 GList *windows;
2542
2543 if (screen->active_workspace->showing_desktop)
2544 return;
2545
2546 screen->active_workspace->showing_desktop = TRUE(!(0));
2547
2548 queue_windows_showing (screen);
2549
2550 /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
2551 * see bug 159257.
2552 */
2553 windows = screen->active_workspace->mru_list;
2554 while (windows != NULL((void*)0))
2555 {
2556 MetaWindow *w = windows->data;
2557
2558 if (w->screen == screen &&
2559 w->type == META_WINDOW_DESKTOP &&
2560 !meta_prefs_is_in_skip_list (w->res_class))
2561 {
2562 meta_window_focus (w, timestamp);
2563 break;
2564 }
2565
2566 windows = windows->next;
2567 }
2568
2569 meta_screen_update_showing_desktop_hint (screen);
2570}
2571
2572void
2573meta_screen_unshow_desktop (MetaScreen *screen)
2574{
2575 if (!screen->active_workspace->showing_desktop)
2576 return;
2577
2578 screen->active_workspace->showing_desktop = FALSE(0);
2579
2580 queue_windows_showing (screen);
2581
2582 meta_screen_update_showing_desktop_hint (screen);
2583}
2584
2585#ifdef HAVE_STARTUP_NOTIFICATION
2586static gboolean startup_sequence_timeout (void *data);
2587
2588static void
2589update_startup_feedback (MetaScreen *screen)
2590{
2591 if (screen->startup_sequences != NULL((void*)0))
2592 {
2593 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2594 "Setting busy cursor\n");
2595 meta_screen_set_cursor (screen, META_CURSOR_BUSY);
2596 }
2597 else
2598 {
2599 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2600 "Setting default cursor\n");
2601 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
2602 }
2603}
2604
2605static void
2606add_sequence (MetaScreen *screen,
2607 SnStartupSequence *sequence)
2608{
2609 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2610 "Adding sequence %s\n",
2611 sn_startup_sequence_get_id (sequence));
2612 sn_startup_sequence_ref (sequence);
2613 screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
2614 sequence);
2615
2616 /* our timeout just polls every second, instead of bothering
2617 * to compute exactly when we may next time out
2618 */
2619 if (screen->startup_sequence_timeout == 0)
2620 screen->startup_sequence_timeout = g_timeout_add (1000,
2621 startup_sequence_timeout,
2622 screen);
2623
2624 update_startup_feedback (screen);
2625}
2626
2627static void
2628remove_sequence (MetaScreen *screen,
2629 SnStartupSequence *sequence)
2630{
2631 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2632 "Removing sequence %s\n",
2633 sn_startup_sequence_get_id (sequence));
2634
2635 screen->startup_sequences = g_slist_remove (screen->startup_sequences,
2636 sequence);
2637 sn_startup_sequence_unref (sequence);
2638
2639 if (screen->startup_sequences == NULL((void*)0) &&
2640 screen->startup_sequence_timeout != 0)
2641 {
2642 g_source_remove (screen->startup_sequence_timeout);
2643 screen->startup_sequence_timeout = 0;
2644 }
2645
2646 update_startup_feedback (screen);
2647}
2648
2649typedef struct
2650{
2651 GSList *list;
2652 gint64 now;
2653} CollectTimedOutData;
2654
2655/* This should be fairly long, as it should never be required unless
2656 * apps or .desktop files are buggy, and it's confusing if
2657 * OpenOffice or whatever seems to stop launching - people
2658 * might decide they need to launch it again.
2659 */
2660#define STARTUP_TIMEOUT15000 15000
2661
2662static void
2663collect_timed_out_foreach (void *element,
2664 void *data)
2665{
2666 CollectTimedOutData *ctod = data;
2667 SnStartupSequence *sequence = element;
2668 double elapsed;
2669
2670 time_t tv_sec;
2671 suseconds_t tv_usec;
2672 gint64 tv;
2673
2674 sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
2675 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
2676 elapsed = (ctod->now - tv) / 1000.0;
2677
2678 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2679 "Sequence used %g seconds vs. %g max: %s\n",
2680 elapsed, (double) STARTUP_TIMEOUT15000,
2681 sn_startup_sequence_get_id (sequence));
2682
2683 if (elapsed > STARTUP_TIMEOUT15000)
2684 ctod->list = g_slist_prepend (ctod->list, sequence);
2685}
2686
2687static gboolean
2688startup_sequence_timeout (void *data)
2689{
2690 MetaScreen *screen = data;
2691 CollectTimedOutData ctod;
2692 GSList *tmp;
2693
2694 ctod.list = NULL((void*)0);
2695
2696 ctod.now = g_get_real_time ();
2697 g_slist_foreach (screen->startup_sequences,
2698 collect_timed_out_foreach,
2699 &ctod);
2700
2701 tmp = ctod.list;
2702 while (tmp != NULL((void*)0))
2703 {
2704 SnStartupSequence *sequence = tmp->data;
2705
2706 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2707 "Timed out sequence %s\n",
2708 sn_startup_sequence_get_id (sequence));
2709
2710 sn_startup_sequence_complete (sequence);
2711
2712 tmp = tmp->next;
2713 }
2714
2715 g_slist_free (ctod.list);
2716
2717 if (screen->startup_sequences != NULL((void*)0))
2718 {
2719 return TRUE(!(0));
2720 }
2721 else
2722 {
2723 /* remove */
2724 screen->startup_sequence_timeout = 0;
2725 return FALSE(0);
2726 }
2727}
2728
2729static void
2730meta_screen_sn_event (SnMonitorEvent *event,
2731 void *user_data)
2732{
2733 MetaScreen *screen;
2734 SnStartupSequence *sequence;
2735
2736 screen = user_data;
2737
2738 sequence = sn_monitor_event_get_startup_sequence (event);
2739
2740 switch (sn_monitor_event_get_type (event))
2741 {
2742 case SN_MONITOR_EVENT_INITIATED:
2743 {
2744 const char *wmclass;
2745
2746 wmclass = sn_startup_sequence_get_wmclass (sequence);
2747
2748 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2749 "Received startup initiated for %s wmclass %s\n",
2750 sn_startup_sequence_get_id (sequence),
2751 wmclass ? wmclass : "(unset)");
2752 add_sequence (screen, sequence);
2753 }
2754 break;
2755
2756 case SN_MONITOR_EVENT_COMPLETED:
2757 {
2758 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2759 "Received startup completed for %s\n",
2760 sn_startup_sequence_get_id (sequence));
2761 remove_sequence (screen,
2762 sn_monitor_event_get_startup_sequence (event));
2763 }
2764 break;
2765
2766 case SN_MONITOR_EVENT_CHANGED:
2767 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2768 "Received startup changed for %s\n",
2769 sn_startup_sequence_get_id (sequence));
2770 break;
2771
2772 case SN_MONITOR_EVENT_CANCELED:
2773 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2774 "Received startup canceled for %s\n",
2775 sn_startup_sequence_get_id (sequence));
2776 break;
2777 }
2778}
2779#endif
2780
2781/* Sets the initial_timestamp and initial_workspace properties
2782 * of a window according to information given us by the
2783 * startup-notification library.
2784 *
2785 * Returns TRUE if startup properties have been applied, and
2786 * FALSE if they have not (for example, if they had already
2787 * been applied.)
2788 */
2789gboolean
2790meta_screen_apply_startup_properties (MetaScreen *screen,
2791 MetaWindow *window)
2792{
2793#ifdef HAVE_STARTUP_NOTIFICATION
2794 const char *startup_id;
2795 GSList *tmp;
2796 SnStartupSequence *sequence;
2797
2798 /* Does the window have a startup ID stored? */
2799 startup_id = meta_window_get_startup_id (window);
2800
2801 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2802 "Applying startup props to %s id \"%s\"\n",
2803 window->desc,
2804 startup_id ? startup_id : "(none)");
2805
2806 sequence = NULL((void*)0);
2807 if (startup_id == NULL((void*)0))
2808 {
2809 /* No startup ID stored for the window. Let's ask the
2810 * startup-notification library whether there's anything
2811 * stored for the resource name or resource class hints.
2812 */
2813 tmp = screen->startup_sequences;
2814 while (tmp != NULL((void*)0))
2815 {
2816 const char *wmclass;
2817
2818 wmclass = sn_startup_sequence_get_wmclass (tmp->data);
2819
2820 if (wmclass != NULL((void*)0) &&
2821 ((window->res_class &&
2822 strcmp (wmclass, window->res_class) == 0) ||
2823 (window->res_name &&
2824 strcmp (wmclass, window->res_name) == 0)))
2825 {
2826 sequence = tmp->data;
2827
2828 g_assert (window->startup_id == NULL)do { if (window->startup_id == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 2828, ((const char*) (__func__)),
"window->startup_id == NULL"); } while (0)
;
2829 window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence))g_strdup_inline (sn_startup_sequence_get_id (sequence));
2830 startup_id = window->startup_id;
2831
2832 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2833 "Ending legacy sequence %s due to window %s\n",
2834 sn_startup_sequence_get_id (sequence),
2835 window->desc);
2836
2837 sn_startup_sequence_complete (sequence);
2838 break;
2839 }
2840
2841 tmp = tmp->next;
2842 }
2843 }
2844
2845 /* Still no startup ID? Bail. */
2846 if (startup_id == NULL((void*)0))
2847 return FALSE(0);
2848
2849 /* We might get this far and not know the sequence ID (if the window
2850 * already had a startup ID stored), so let's look for one if we don't
2851 * already know it.
2852 */
2853 if (sequence == NULL((void*)0))
2854 {
2855 tmp = screen->startup_sequences;
2856 while (tmp != NULL((void*)0))
2857 {
2858 const char *id;
2859
2860 id = sn_startup_sequence_get_id (tmp->data);
2861
2862 if (strcmp (id, startup_id) == 0)
2863 {
2864 sequence = tmp->data;
2865 break;
2866 }
2867
2868 tmp = tmp->next;
2869 }
2870 }
2871
2872 if (sequence != NULL((void*)0))
2873 {
2874 gboolean changed_something = FALSE(0);
2875
2876 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2877 "Found startup sequence for window %s ID \"%s\"\n",
2878 window->desc, startup_id);
2879
2880 if (!window->initial_workspace_set)
2881 {
2882 int space = sn_startup_sequence_get_workspace (sequence);
2883 if (space >= 0)
2884 {
2885 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2886 "Setting initial window workspace to %d based on startup info\n",
2887 space);
2888
2889 window->initial_workspace_set = TRUE(!(0));
2890 window->initial_workspace = space;
2891 changed_something = TRUE(!(0));
2892 }
2893 }
2894
2895 if (!window->initial_timestamp_set)
2896 {
2897 guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
2898 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2899 "Setting initial window timestamp to %u based on startup info\n",
2900 timestamp);
2901
2902 window->initial_timestamp_set = TRUE(!(0));
2903 window->initial_timestamp = timestamp;
2904 changed_something = TRUE(!(0));
2905 }
2906
2907 return changed_something;
2908 }
2909 else
2910 {
2911 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2912 "Did not find startup sequence for window %s ID \"%s\"\n",
2913 window->desc, startup_id);
2914 }
2915
2916#endif /* HAVE_STARTUP_NOTIFICATION */
2917
2918 return FALSE(0);
2919}
2920
2921int
2922meta_screen_get_screen_number (MetaScreen *screen)
2923{
2924 return screen->number;
2925}
2926
2927MetaDisplay *
2928meta_screen_get_display (MetaScreen *screen)
2929{
2930 return screen->display;
2931}
2932
2933Window
2934meta_screen_get_xroot (MetaScreen *screen)
2935{
2936 return screen->xroot;
2937}
2938
2939void
2940meta_screen_get_size (MetaScreen *screen,
2941 int *width,
2942 int *height)
2943{
2944 *width = screen->rect.width;
2945 *height = screen->rect.height;
2946}
2947
2948gpointer
2949meta_screen_get_compositor_data (MetaScreen *screen)
2950{
2951 return screen->compositor_data;
2952}
2953
2954void
2955meta_screen_set_compositor_data (MetaScreen *screen,
2956 gpointer compositor)
2957{
2958 screen->compositor_data = compositor;
2959}
2960
2961#ifdef HAVE_COMPOSITE_EXTENSIONS1
2962void
2963meta_screen_set_cm_selection (MetaScreen *screen)
2964{
2965 screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip (
2966 screen->display);
2967
2968 meta_verbosemeta_verbose_real ("Setting selection for screen: %d\n", screen->number);
2969 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2970 screen->wm_cm_selection_window, screen->wm_cm_timestamp);
2971}
2972
2973void
2974meta_screen_unset_cm_selection (MetaScreen *screen)
2975{
2976 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2977 None0L, screen->wm_cm_timestamp);
2978}
2979
2980gboolean
2981meta_screen_is_cm_selected (MetaScreen *screen)
2982{
2983 Window owner = XGetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom);
2984 return owner != None0L;
2985}
2986#endif /* HAVE_COMPOSITE_EXTENSIONS */
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-071a16.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-071a16.html new file mode 100644 index 00000000..003ff1ce --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-071a16.html @@ -0,0 +1,1834 @@ + + + +ui/theme-viewer.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme-viewer.c
Warning:line 895, column 15
Access to field 'name' results in a dereference of a null pointer (loaded from variable 'global_theme')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme-viewer.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme-viewer.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco theme viewer and test app main() */
4
5/*
6 * Copyright (C) 2002 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <config.h>
25#include <glib/gi18n.h>
26
27#include "util.h"
28#include "theme.h"
29#include "theme-parser.h"
30#include "preview-widget.h"
31#include <gtk/gtk.h>
32#include <time.h>
33#include <stdlib.h>
34#include <string.h>
35
36/* We need to compute all different button arrangements
37 * in terms of button location. We don't care about
38 * different arrangements in terms of button function.
39 *
40 * So if dups are allowed, from 0-4 buttons on the left, from 0-4 on
41 * the right, 5x5=25 combinations.
42 *
43 * If no dups, 0-4 on left determines the number on the right plus
44 * we have a special case for the "no buttons on either side" case.
45 */
46#ifndef ALLOW_DUPLICATE_BUTTONS
47#define BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1) (MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST + 1 + 1)
48#else
49#define BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1) ((MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST+1)*(MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST+1))
50#endif
51
52enum
53{
54 FONT_SIZE_SMALL,
55 FONT_SIZE_NORMAL,
56 FONT_SIZE_LARGE,
57 FONT_SIZE_LAST
58};
59
60static MetaTheme *global_theme = NULL((void*)0);
61static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1)] = { NULL((void*)0), };
62static double milliseconds_to_draw_frame = 0.0;
63
64static void run_theme_benchmark (void);
65
66static const gchar *xml =
67 "<interface>"
68 "<menu id='menubar'>"
69 "<submenu>"
70 "<attribute name='label'>Windows</attribute>"
71 "<section>"
72 "<item>"
73 "<attribute name='label'>Dialog</attribute>"
74 "<attribute name='action'>theme-viewer.dialog1</attribute>"
75 "<attribute name='accel'>&lt;control&gt;d</attribute>"
76 "</item>"
77 "<item>"
78 "<attribute name='label'>Modal dialog</attribute>"
79 "<attribute name='action'>theme-viewer.dialog2</attribute>"
80 "</item>"
81 "<item>"
82 "<attribute name='label'>Utility</attribute>"
83 "<attribute name='action'>theme-viewer.utility</attribute>"
84 "<attribute name='accel'>&lt;control&gt;u</attribute>"
85 "</item>"
86 "<item>"
87 "<attribute name='label'>Splashscreen</attribute>"
88 "<attribute name='action'>theme-viewer.splashscreen</attribute>"
89 "<attribute name='accel'>&lt;control&gt;s</attribute>"
90 "</item>"
91 "<item>"
92 "<attribute name='label'>Top dock</attribute>"
93 "<attribute name='action'>theme-viewer.top-dock</attribute>"
94 "</item>"
95 "<item>"
96 "<attribute name='label'>Bottom dock</attribute>"
97 "<attribute name='action'>theme-viewer.bottom-dock</attribute>"
98 "</item>"
99 "<item>"
100 "<attribute name='label'>Left dock</attribute>"
101 "<attribute name='action'>theme-viewer.left-dock</attribute>"
102 "</item>"
103 "<item>"
104 "<attribute name='label'>Right dock</attribute>"
105 "<attribute name='action'>theme-viewer.right-dock</attribute>"
106 "</item>"
107 "<item>"
108 "<attribute name='label'>All docks</attribute>"
109 "<attribute name='action'>theme-viewer.all-docks</attribute>"
110 "</item>"
111 "<item>"
112 "<attribute name='label'>Desktop</attribute>"
113 "<attribute name='action'>theme-viewer.desktop</attribute>"
114 "</item>"
115 "</section>"
116 "</submenu>"
117 "</menu>"
118 "</interface>";
119
120static GActionEntry theme_viewer_entries[] =
121{
122 /* menubar */
123 { "dialog1", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
124 { "dialog2", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
125 { "utility", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
126 { "splashscreen", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
127 { "top-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
128 { "bottom-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
129 { "left-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
130 { "right-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
131 { "all-docks", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
132 { "desktop", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
133 /* toolbar */
134 { "new", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
135 { "open", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
136 { "quit", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} }
137};
138
139static GtkWidget *
140create_toolbar (void)
141{
142 GtkWidget *toolbar;
143 GtkToolItem *item;
144
145 toolbar = gtk_toolbar_new ();
146
147 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-new", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
148 gtk_tool_item_set_tooltip_markup (item, "Open another one of these windows");
149 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.new");
150 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
151
152 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-open", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
153 gtk_tool_item_set_tooltip_markup (item, "This is a demo button with an 'open' icon");
154 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.open");
155 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
156
157 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("application-exit", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
158 gtk_tool_item_set_tooltip_markup (item, "This is a demo button with a 'quit' icon");
159 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.quit");
160 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
161
162 return toolbar;
163}
164
165static GtkWidget *
166normal_contents (void)
167{
168 GtkWidget *grid;
169 GtkWidget *statusbar;
170 GtkWidget *contents;
171 GtkWidget *sw;
172 GtkBuilder *builder;
173
174 grid = gtk_grid_new ();
175 builder = gtk_builder_new_from_string (xml, -1);
176
177 /* create menu items */
178 GMenuModel *model = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"))((((GMenuModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (builder, "menubar"))), ((g_menu_model_get_type
()))))))
;
179 GtkWidget *menubar = gtk_menu_bar_new_from_model (model);
180 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, menubar, 0, 0, 1, 1);
181 gtk_widget_set_hexpand (menubar, TRUE(!(0)));
182
183 /* Create the toolbar */
184 GtkWidget *toolbar = create_toolbar ();
185 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, toolbar, 0, 1, 1, 1);
186 gtk_widget_set_hexpand (toolbar, TRUE(!(0)));
187
188 /* Create document
189 */
190
191 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
192 gtk_widget_set_hexpand (sw, TRUE(!(0)));
193 gtk_widget_set_vexpand (sw, TRUE(!(0)));
194
195 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
196 GTK_POLICY_AUTOMATIC,
197 GTK_POLICY_AUTOMATIC);
198
199 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
200 GTK_SHADOW_IN);
201
202 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
203 sw,
204 0, 2, 1, 1);
205
206 contents = gtk_text_view_new ();
207 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (contents)((((GtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((contents)), ((gtk_text_view_get_type ()))))))
,
208 GTK_WRAP_WORD);
209
210 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
,
211 contents);
212
213 /* Create statusbar */
214
215 statusbar = gtk_statusbar_new ();
216 gtk_widget_set_hexpand (statusbar, TRUE(!(0)));
217 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
218 statusbar,
219 0, 3, 1, 1);
220
221 gtk_widget_show_all (grid);
222
223 g_object_unref (builder);
224
225 return grid;
226}
227
228static void
229update_spacings (GtkWidget *vbox,
230 GtkWidget *action_area)
231{
232 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 2);
233 gtk_box_set_spacing (GTK_BOX (action_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_box_get_type ()))))))
, 10);
234 gtk_container_set_border_width (GTK_CONTAINER (action_area)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_container_get_type ()))))))
, 5);
235}
236
237static GtkWidget*
238dialog_contents (void)
239{
240 GtkWidget *vbox;
241 GtkWidget *hbox;
242 GtkWidget *action_area;
243 GtkWidget *label;
244 GtkWidget *image;
245 GtkWidget *button;
246
247 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
248
249 action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
250
251 gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area)((((GtkButtonBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_button_box_get_type ()))))))
,
252 GTK_BUTTONBOX_END);
253
254 button = gtk_button_new_with_mnemonic (_("_OK")gettext ("_OK"));
255 gtk_button_set_image (GTK_BUTTON (button)((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((gtk_button_get_type ()))))))
, gtk_image_new_from_icon_name ("gtk-ok", GTK_ICON_SIZE_BUTTON));
256
257 gtk_box_pack_end (GTK_BOX (action_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_box_get_type ()))))))
,
258 button,
259 FALSE(0), TRUE(!(0)), 0);
260
261 gtk_box_pack_end (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, action_area,
262 FALSE(0), TRUE(!(0)), 0);
263
264 update_spacings (vbox, action_area);
265
266 label = gtk_label_new (_("This is a sample message in a sample dialog")gettext ("This is a sample message in a sample dialog"));
267 image = gtk_image_new_from_icon_name ("dialog-information",
268 GTK_ICON_SIZE_DIALOG);
269 gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
270 gtk_widget_set_valign (image, GTK_ALIGN_START);
271
272 gtk_label_set_line_wrap (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
273 gtk_label_set_selectable (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
274
275 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
276
277 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, image,
278 FALSE(0), FALSE(0), 0);
279
280 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, label,
281 TRUE(!(0)), TRUE(!(0)), 0);
282
283 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
,
284 hbox,
285 FALSE(0), FALSE(0), 0);
286
287 gtk_widget_show_all (vbox);
288
289 return vbox;
290}
291
292static GtkWidget*
293utility_contents (void)
294{
295 GtkWidget *grid;
296 GtkWidget *button;
297 int i, j;
298
299 grid = gtk_grid_new ();
300
301 i = 0;
302 while (i < 3)
303 {
304 j = 0;
305 while (j < 4)
306 {
307 char *str;
308
309 str = g_strdup_printf ("_%c", (char) ('A' + 4*i + j));
310
311 button = gtk_button_new_with_mnemonic (str);
312
313 g_free (str);
314
315 gtk_widget_set_hexpand (button, TRUE(!(0)));
316 gtk_widget_set_vexpand (button, TRUE(!(0)));
317
318 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
319 button,
320 i, j, 1, 1);
321
322 ++j;
323 }
324
325 ++i;
326 }
327
328 gtk_widget_show_all (grid);
329
330 return grid;
331}
332
333static GtkWidget*
334menu_contents (void)
335{
336 GtkWidget *vbox;
337 GtkWidget *mi;
338 int i;
339 GtkWidget *frame;
340
341 frame = gtk_frame_new (NULL((void*)0));
342 gtk_frame_set_shadow_type (GTK_FRAME (frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_frame_get_type ()))))))
,
343 GTK_SHADOW_OUT);
344
345 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
346
347 i = 0;
348 while (i < 10)
349 {
350 char *str = g_strdup_printf (_("Fake menu item %d\n")gettext ("Fake menu item %d\n"), i + 1);
351 mi = gtk_label_new (str);
352 gtk_widget_set_halign (mi, GTK_ALIGN_START);
353 gtk_widget_set_valign (mi, GTK_ALIGN_CENTER);
354 g_free (str);
355 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, mi, FALSE(0), FALSE(0), 0);
356
357 ++i;
358 }
359
360 gtk_container_add (GTK_CONTAINER (frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_container_get_type ()))))))
, vbox);
361
362 gtk_widget_show_all (frame);
363
364 return frame;
365}
366
367static void
368override_background_color (GtkWidget *widget,
369 GdkRGBA *rgba)
370{
371 gchar *css;
372 GtkCssProvider *provider;
373
374 provider = gtk_css_provider_new ();
375
376 css = g_strdup_printf ("* { background-color: %s; }",
377 gdk_rgba_to_string (rgba));
378 gtk_css_provider_load_from_data (provider, css, -1, NULL((void*)0));
379 g_free (css);
380
381 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
382 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
383 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
384 g_object_unref (provider);
385}
386
387static GtkWidget*
388border_only_contents (void)
389{
390 GtkWidget *event_box;
391 GtkWidget *vbox;
392 GtkWidget *w;
393 GdkRGBA color;
394
395 event_box = gtk_event_box_new ();
396
397 color.red = 0.6;
398 color.green = 0;
399 color.blue = 0.6;
400 color.alpha = 1.0;
401 override_background_color (event_box, &color);
402
403 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
404 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 3);
405
406 w = gtk_label_new (_("Border-only window")gettext ("Border-only window"));
407 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, w, FALSE(0), FALSE(0), 0);
408 w = gtk_button_new_with_label (_("Bar")gettext ("Bar"));
409 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, w, FALSE(0), FALSE(0), 0);
410
411 gtk_container_add (GTK_CONTAINER (event_box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((event_box)), ((gtk_container_get_type ()))))))
, vbox);
412
413 gtk_widget_show_all (event_box);
414
415 return event_box;
416}
417
418static GtkWidget*
419get_window_contents (MetaFrameType type,
420 const char **title)
421{
422 switch (type)
423 {
424 case META_FRAME_TYPE_NORMAL:
425 *title = _("Normal Application Window")gettext ("Normal Application Window");
426 return normal_contents ();
427
428 case META_FRAME_TYPE_DIALOG:
429 *title = _("Dialog Box")gettext ("Dialog Box");
430 return dialog_contents ();
431
432 case META_FRAME_TYPE_MODAL_DIALOG:
433 *title = _("Modal Dialog Box")gettext ("Modal Dialog Box");
434 return dialog_contents ();
435
436 case META_FRAME_TYPE_UTILITY:
437 *title = _("Utility Palette")gettext ("Utility Palette");
438 return utility_contents ();
439
440 case META_FRAME_TYPE_MENU:
441 *title = _("Torn-off Menu")gettext ("Torn-off Menu");
442 return menu_contents ();
443
444 case META_FRAME_TYPE_BORDER:
445 *title = _("Border")gettext ("Border");
446 return border_only_contents ();
447
448 case META_FRAME_TYPE_ATTACHED:
449 *title = _("Attached Modal Dialog")gettext ("Attached Modal Dialog");
450 return dialog_contents ();
451
452 case META_FRAME_TYPE_LAST:
453 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme-viewer.c", 453
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
454 break;
455 }
456
457 return NULL((void*)0);
458}
459
460static MetaFrameFlags
461get_window_flags (MetaFrameType type)
462{
463 MetaFrameFlags flags;
464
465 flags = META_FRAME_ALLOWS_DELETE |
466 META_FRAME_ALLOWS_MENU |
467 META_FRAME_ALLOWS_MINIMIZE |
468 META_FRAME_ALLOWS_MAXIMIZE |
469 META_FRAME_ALLOWS_VERTICAL_RESIZE |
470 META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
471 META_FRAME_HAS_FOCUS |
472 META_FRAME_ALLOWS_SHADE |
473 META_FRAME_ALLOWS_MOVE;
474
475 switch (type)
476 {
477 case META_FRAME_TYPE_NORMAL:
478 break;
479
480 case META_FRAME_TYPE_DIALOG:
481 case META_FRAME_TYPE_MODAL_DIALOG:
482 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
483 META_FRAME_ALLOWS_MAXIMIZE);
484 break;
485
486 case META_FRAME_TYPE_UTILITY:
487 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
488 META_FRAME_ALLOWS_MAXIMIZE);
489 break;
490
491 case META_FRAME_TYPE_MENU:
492 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
493 META_FRAME_ALLOWS_MAXIMIZE);
494 break;
495
496 case META_FRAME_TYPE_BORDER:
497 break;
498
499 case META_FRAME_TYPE_ATTACHED:
500 break;
501
502 case META_FRAME_TYPE_LAST:
503 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme-viewer.c", 503
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
504 break;
505 }
506
507 return flags;
508}
509
510static void
511override_font (GtkWidget *widget,
512 const gchar *font)
513{
514 gchar *css;
515 GtkCssProvider *provider;
516
517 provider = gtk_css_provider_new ();
518
519 css = g_strdup_printf ("* { font: %s; }", font);
520 gtk_css_provider_load_from_data (provider, css, -1, NULL((void*)0));
521 g_free (css);
522
523 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
524 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
525 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
526 g_object_unref (provider);
527}
528
529static GtkWidget*
530preview_collection (int font_size,
531 const PangoFontDescription *base_desc)
532{
533 GtkWidget *box;
534 GtkWidget *sw;
535 GdkRGBA desktop_color;
536 int i;
537 GtkWidget *eventbox;
538
539 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
540 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
541 GTK_POLICY_AUTOMATIC,
542 GTK_POLICY_AUTOMATIC);
543
544 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
545 gtk_box_set_spacing (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, 20);
546 gtk_container_set_border_width (GTK_CONTAINER (box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_container_get_type ()))))))
, 20);
547
548 eventbox = gtk_event_box_new ();
549 gtk_container_add (GTK_CONTAINER (eventbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox)), ((gtk_container_get_type ()))))))
, box);
550
551 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
, eventbox);
552
553 GSimpleActionGroup *action_group = g_simple_action_group_new ();
554 g_action_map_add_action_entries (G_ACTION_MAP (action_group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), ((g_action_map_get_type ()))))))
,
555 theme_viewer_entries,
556 G_N_ELEMENTS (theme_viewer_entries)(sizeof (theme_viewer_entries) / sizeof ((theme_viewer_entries
)[0]))
,
557 NULL((void*)0));
558 gtk_widget_insert_action_group (sw, "theme-viewer", G_ACTION_GROUP (action_group)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), ((g_action_group_get_type ()))))))
);
559 g_object_unref (action_group);
560
561 desktop_color.red = 0.32;
562 desktop_color.green = 0.46;
563 desktop_color.blue = 0.65;
564 desktop_color.alpha = 1.0;
565
566 override_background_color (eventbox, &desktop_color);
567
568 i = 0;
569 while (i < META_FRAME_TYPE_LAST)
570 {
571 const char *title = NULL((void*)0);
572 GtkWidget *contents;
573 GtkAlign xalign, yalign;
574 GtkWidget *eventbox2;
575 GtkWidget *preview;
576 PangoFontDescription *font_desc;
577 gchar *font_string;
578 double scale;
579
580 eventbox2 = gtk_event_box_new ();
581
582 preview = meta_preview_new ();
583
584 gtk_container_add (GTK_CONTAINER (eventbox2)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox2)), ((gtk_container_get_type ()))))))
, preview);
585
586 meta_preview_set_frame_type (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, i);
587 meta_preview_set_frame_flags (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
,
588 get_window_flags (i));
589
590 meta_preview_set_theme (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, global_theme);
591
592 contents = get_window_contents (i, &title);
593
594 meta_preview_set_title (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, title);
595
596 gtk_container_add (GTK_CONTAINER (preview)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((gtk_container_get_type ()))))))
, contents);
597
598 if (i == META_FRAME_TYPE_MENU)
599 {
600 xalign = GTK_ALIGN_START;
601 yalign = GTK_ALIGN_START;
602 }
603 else
604 {
605 xalign = GTK_ALIGN_FILL;
606 yalign = GTK_ALIGN_FILL;
607 }
608
609 gtk_widget_set_halign (eventbox2, xalign);
610 gtk_widget_set_valign (eventbox2, yalign);
611
612 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, eventbox2, TRUE(!(0)), TRUE(!(0)), 0);
613
614 switch (font_size)
615 {
616 case FONT_SIZE_SMALL:
617 scale = PANGO_SCALE_XX_SMALL((double)0.5787037037037);
618 break;
619 case FONT_SIZE_LARGE:
620 scale = PANGO_SCALE_XX_LARGE((double)1.728);
621 break;
622 default:
623 scale = 1.0;
624 break;
625 }
626
627 if (scale != 1.0)
628 {
629 font_desc = pango_font_description_new ();
630
631 pango_font_description_set_size (font_desc,
632 MAX (pango_font_description_get_size (base_desc) * scale, 1)(((pango_font_description_get_size (base_desc) * scale) > (
1)) ? (pango_font_description_get_size (base_desc) * scale) :
(1))
);
633
634 font_string = pango_font_description_to_string (font_desc);
635 override_font (preview, font_string);
636 g_free (font_string);
637
638 pango_font_description_free (font_desc);
639 }
640
641 previews[font_size*META_FRAME_TYPE_LAST + i] = preview;
642
643 ++i;
644 }
645
646 return sw;
647}
648
649static MetaButtonLayout different_layouts[BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1)];
650
651static void
652init_layouts (void)
653{
654 int i;
655
656 /* Blank out all the layouts */
657 i = 0;
658 while (i < (int) G_N_ELEMENTS (different_layouts)(sizeof (different_layouts) / sizeof ((different_layouts)[0])
)
)
659 {
660 int j;
661
662 j = 0;
663 while (j < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
664 {
665 different_layouts[i].left_buttons[j] = META_BUTTON_FUNCTION_LAST;
666 different_layouts[i].right_buttons[j] = META_BUTTON_FUNCTION_LAST;
667 ++j;
668 }
669 ++i;
670 }
671
672#ifndef ALLOW_DUPLICATE_BUTTONS
673 i = 0;
674 while (i <= MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
675 {
676 int j;
677
678 j = 0;
679 while (j < i)
680 {
681 different_layouts[i].right_buttons[j] = (MetaButtonFunction) j;
682 ++j;
683 }
684 while (j < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
685 {
686 different_layouts[i].left_buttons[j-i] = (MetaButtonFunction) j;
687 ++j;
688 }
689
690 ++i;
691 }
692
693 /* Special extra case for no buttons on either side */
694 different_layouts[i].left_buttons[0] = META_BUTTON_FUNCTION_LAST;
695 different_layouts[i].right_buttons[0] = META_BUTTON_FUNCTION_LAST;
696
697#else
698 /* FIXME this code is if we allow duplicate buttons,
699 * which we currently do not
700 */
701 int left;
702 int i;
703
704 left = 0;
705 i = 0;
706
707 while (left < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
708 {
709 int right;
710
711 right = 0;
712
713 while (right < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
714 {
715 int j;
716
717 static MetaButtonFunction left_functions[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST] = {
718 META_BUTTON_FUNCTION_MENU,
719 META_BUTTON_FUNCTION_MINIMIZE,
720 META_BUTTON_FUNCTION_MAXIMIZE,
721 META_BUTTON_FUNCTION_CLOSE
722 };
723 static MetaButtonFunction right_functions[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST] = {
724 META_BUTTON_FUNCTION_MINIMIZE,
725 META_BUTTON_FUNCTION_MAXIMIZE,
726 META_BUTTON_FUNCTION_CLOSE,
727 META_BUTTON_FUNCTION_MENU
728 };
729
730 g_assert (i < BUTTON_LAYOUT_COMBINATIONS)do { if (i < (META_BUTTON_FUNCTION_LAST + 1 + 1)) ; else g_assertion_message_expr
("marco", "ui/theme-viewer.c", 730, ((const char*) (__func__
)), "i < BUTTON_LAYOUT_COMBINATIONS"); } while (0)
;
731
732 j = 0;
733 while (j <= left)
734 {
735 different_layouts[i].left_buttons[j] = left_functions[j];
736 ++j;
737 }
738
739 j = 0;
740 while (j <= right)
741 {
742 different_layouts[i].right_buttons[j] = right_functions[j];
743 ++j;
744 }
745
746 ++i;
747
748 ++right;
749 }
750
751 ++left;
752 }
753#endif
754}
755
756static GtkWidget*
757previews_of_button_layouts (void)
758{
759 static gboolean initted = FALSE(0);
760 GtkWidget *box;
761 GtkWidget *sw;
762 GdkRGBA desktop_color;
763 int i;
764 GtkWidget *eventbox;
765
766 if (!initted)
767 {
768 init_layouts ();
769 initted = TRUE(!(0));
770 }
771
772 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
773 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
774 GTK_POLICY_AUTOMATIC,
775 GTK_POLICY_AUTOMATIC);
776
777 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
778 gtk_box_set_spacing (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, 20);
779 gtk_container_set_border_width (GTK_CONTAINER (box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_container_get_type ()))))))
, 20);
780
781 eventbox = gtk_event_box_new ();
782 gtk_container_add (GTK_CONTAINER (eventbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox)), ((gtk_container_get_type ()))))))
, box);
783
784 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
, eventbox);
785
786 desktop_color.red = 0.32;
787 desktop_color.green = 0.46;
788 desktop_color.blue = 0.65;
789 desktop_color.alpha = 1.0;
790
791 override_background_color (eventbox, &desktop_color);
792
793 i = 0;
794 while (i < BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1))
795 {
796 GtkWidget *eventbox2;
797 GtkWidget *preview;
798 char *title;
799
800 eventbox2 = gtk_event_box_new ();
801
802 preview = meta_preview_new ();
803
804 gtk_container_add (GTK_CONTAINER (eventbox2)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox2)), ((gtk_container_get_type ()))))))
, preview);
805
806 meta_preview_set_theme (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, global_theme);
807
808 title = g_strdup_printf (_("Button layout test %d")gettext ("Button layout test %d"), i+1);
809 meta_preview_set_title (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, title);
810 g_free (title);
811
812 meta_preview_set_button_layout (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
,
813 &different_layouts[i]);
814
815 gtk_widget_set_halign (eventbox2, GTK_ALIGN_FILL);
816
817 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, eventbox2, TRUE(!(0)), TRUE(!(0)), 0);
818
819 previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + i] = preview;
820
821 ++i;
822 }
823
824 return sw;
825}
826
827static GtkWidget*
828benchmark_summary (void)
829{
830 char *msg;
831 GtkWidget *label;
832
833 msg = g_strdup_printf (_("%g milliseconds to draw one window frame")gettext ("%g milliseconds to draw one window frame"),
834 milliseconds_to_draw_frame);
835 label = gtk_label_new (msg);
836 g_free (msg);
837
838 return label;
839}
840
841int
842main (int argc, char **argv)
843{
844 GtkWidget *window;
845 GtkWidget *collection;
846 GtkStyleContext *style;
847 PangoFontDescription *font_desc;
848 GError *err;
849 clock_t start, end;
850 GtkWidget *notebook;
851 int i;
852
853 bindtextdomain (GETTEXT_PACKAGE"marco", MARCO_LOCALEDIR"/usr/local/share/locale");
854 textdomain(GETTEXT_PACKAGE"marco");
855 bind_textdomain_codeset(GETTEXT_PACKAGE"marco", "UTF-8");
856
857 gtk_init (&argc, &argv);
858
859 if (g_getenv ("MARCO_DEBUG") != NULL((void*)0))
1
Assuming the condition is false
2
Taking false branch
860 {
861 meta_set_debugging (TRUE(!(0)));
862 meta_set_verbose (TRUE(!(0)));
863 }
864
865 start = clock ();
866 err = NULL((void*)0);
867 if (argc == 1)
3
Assuming 'argc' is not equal to 1
4
Taking false branch
868 global_theme = meta_theme_load ("ClearlooksRe", &err);
869 else if (argc == 2)
5
Assuming 'argc' is equal to 2
6
Taking true branch
870 global_theme = meta_theme_load (argv[1], &err);
871 else
872 {
873 g_printerr (_("Usage: marco-theme-viewer [THEMENAME]\n")gettext ("Usage: marco-theme-viewer [THEMENAME]\n"));
874 exit (1);
875 }
876 end = clock ();
877
878 if (global_theme == NULL((void*)0))
7
Assuming 'global_theme' is not equal to NULL
8
Taking false branch
879 {
880 g_printerr (_("Error loading theme: %s\n")gettext ("Error loading theme: %s\n"),
881 err->message);
882 g_error_free (err);
883 exit (1);
884 }
885
886 g_print (_("Loaded theme \"%s\" in %g seconds\n")gettext ("Loaded theme \"%s\" in %g seconds\n"),
9
Null pointer value stored to 'global_theme'
887 global_theme->name,
888 (end - start) / (double) CLOCKS_PER_SEC((__clock_t) 1000000));
889
890 run_theme_benchmark ();
891
892 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
893 gtk_window_set_default_size (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
, 350, 350);
894
895 if (strcmp (global_theme->name, global_theme->readable_name)==0)
10
Access to field 'name' results in a dereference of a null pointer (loaded from variable 'global_theme')
896 gtk_window_set_title (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
,
897 global_theme->readable_name);
898 else
899 {
900 /* The theme directory name is different from the name the theme
901 * gives itself within its file. Display both, directory name first.
902 */
903 gchar *title = g_strconcat (global_theme->name, " - ",
904 global_theme->readable_name,
905 NULL((void*)0));
906
907 gtk_window_set_title (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
,
908 title);
909
910 g_free (title);
911 }
912
913 g_signal_connect (G_OBJECT (window), "destroy",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((window)), (((GType) ((20) << (2)))
)))))), ("destroy"), (((GCallback) (gtk_main_quit))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
914 G_CALLBACK (gtk_main_quit), NULL)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((window)), (((GType) ((20) << (2)))
)))))), ("destroy"), (((GCallback) (gtk_main_quit))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
915
916 gtk_widget_realize (window);
917 style = gtk_widget_get_style_context (window);
918 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL,
919 GTK_STYLE_PROPERTY_FONT"font", &font_desc,
920 NULL((void*)0));
921
922 g_assert (style)do { if (style) ; else g_assertion_message_expr ("marco", "ui/theme-viewer.c"
, 922, ((const char*) (__func__)), "style"); } while (0)
;
923 g_assert (font_desc)do { if (font_desc) ; else g_assertion_message_expr ("marco",
"ui/theme-viewer.c", 923, ((const char*) (__func__)), "font_desc"
); } while (0)
;
924
925 notebook = gtk_notebook_new ();
926 gtk_container_add (GTK_CONTAINER (window)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_container_get_type ()))))))
, notebook);
927
928 collection = preview_collection (FONT_SIZE_NORMAL,
929 font_desc);
930 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
931 collection,
932 gtk_label_new (_("Normal Title Font")gettext ("Normal Title Font")));
933
934 collection = preview_collection (FONT_SIZE_SMALL,
935 font_desc);
936 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
937 collection,
938 gtk_label_new (_("Small Title Font")gettext ("Small Title Font")));
939
940 collection = preview_collection (FONT_SIZE_LARGE,
941 font_desc);
942 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
943 collection,
944 gtk_label_new (_("Large Title Font")gettext ("Large Title Font")));
945
946 collection = previews_of_button_layouts ();
947 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
948 collection,
949 gtk_label_new (_("Button Layouts")gettext ("Button Layouts")));
950
951 collection = benchmark_summary ();
952 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
953 collection,
954 gtk_label_new (_("Benchmark")gettext ("Benchmark")));
955
956 pango_font_description_free (font_desc);
957
958 i = 0;
959 while (i < (int) G_N_ELEMENTS (previews)(sizeof (previews) / sizeof ((previews)[0])))
960 {
961 /* preview widget likes to be realized before its size request.
962 * it's lame that way.
963 */
964 gtk_widget_realize (previews[i]);
965
966 ++i;
967 }
968
969 gtk_widget_show_all (window);
970
971 gtk_main ();
972
973 return 0;
974}
975
976static MetaFrameFlags
977get_flags (GtkWidget *widget)
978{
979 return META_FRAME_ALLOWS_DELETE |
980 META_FRAME_ALLOWS_MENU |
981 META_FRAME_ALLOWS_MINIMIZE |
982 META_FRAME_ALLOWS_MAXIMIZE |
983 META_FRAME_ALLOWS_VERTICAL_RESIZE |
984 META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
985 META_FRAME_HAS_FOCUS |
986 META_FRAME_ALLOWS_SHADE |
987 META_FRAME_ALLOWS_MOVE;
988}
989
990static int
991get_text_height (GtkWidget *widget)
992{
993 GtkStyleContext *style;
994 PangoFontDescription *font_desc;
995 int text_height;
996
997 style = gtk_widget_get_style_context (widget);
998 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL,
999 GTK_STYLE_PROPERTY_FONT"font", &font_desc,
1000 NULL((void*)0));
1001 text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget));
1002 pango_font_description_free (font_desc);
1003
1004 return text_height;
1005}
1006
1007static PangoLayout*
1008create_title_layout (GtkWidget *widget)
1009{
1010 PangoLayout *layout;
1011
1012 layout = gtk_widget_create_pango_layout (widget, _("Window Title Goes Here")gettext ("Window Title Goes Here"));
1013
1014 return layout;
1015}
1016
1017static void
1018run_theme_benchmark (void)
1019{
1020 GtkWidget* widget;
1021 cairo_surface_t *pixmap;
1022 cairo_t *cr;
1023 MetaFrameBorders borders;
1024 MetaButtonState button_states[META_BUTTON_TYPE_LAST] =
1025 {
1026 META_BUTTON_STATE_NORMAL,
1027 META_BUTTON_STATE_NORMAL,
1028 META_BUTTON_STATE_NORMAL,
1029 META_BUTTON_STATE_NORMAL
1030 };
1031 PangoLayout *layout;
1032 clock_t start;
1033 clock_t end;
1034 GTimer *timer;
1035 int i;
1036 MetaButtonLayout button_layout;
1037#define ITERATIONS 100
1038 int client_width;
1039 int client_height;
1040 int inc;
1041
1042 widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1043 gtk_widget_realize (widget);
1044
1045 meta_theme_get_frame_borders (global_theme,
1046 META_FRAME_TYPE_NORMAL,
1047 get_text_height (widget),
1048 get_flags (widget),
1049 &borders);
1050
1051 layout = create_title_layout (widget);
1052
1053 i = 0;
1054 while (i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
1055 {
1056 button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1057 button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1058 ++i;
1059 }
1060
1061 button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
1062
1063 button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
1064 button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
1065 button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
1066
1067 timer = g_timer_new ();
1068 start = clock ();
1069
1070 client_width = 50;
1071 client_height = 50;
1072 inc = 1000 / ITERATIONS; /* Increment to grow width/height,
1073 * eliminates caching effects.
1074 */
1075
1076 i = 0;
1077 while (i < ITERATIONS)
1078 {
1079 /* Creating the pixmap in the loop is right, since
1080 * GDK does the same with its double buffering.
1081 */
1082 pixmap = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
1083 CAIRO_CONTENT_COLOR,
1084 client_width + borders.total.left + borders.total.right,
1085 client_height + borders.total.top + borders.total.bottom);
1086 cr = cairo_create (pixmap);
1087
1088 meta_theme_draw_frame (global_theme,
1089 gtk_widget_get_style_context (widget),
1090 cr,
1091 META_FRAME_TYPE_NORMAL,
1092 get_flags (widget),
1093 client_width, client_height,
1094 layout,
1095 get_text_height (widget),
1096 &button_layout,
1097 button_states,
1098 meta_preview_get_mini_icon (),
1099 meta_preview_get_icon ());
1100
1101 cairo_destroy (cr);
1102 cairo_surface_destroy (pixmap);
1103
1104 ++i;
1105 client_width += inc;
1106 client_height += inc;
1107 }
1108
1109 end = clock ();
1110 g_timer_stop (timer);
1111
1112 milliseconds_to_draw_frame = (g_timer_elapsed (timer, NULL((void*)0)) / (double) ITERATIONS) * 1000;
1113
1114 g_print (_("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n")gettext ("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n"
)
,
1115 ITERATIONS,
1116 ((double)end - (double)start) / CLOCKS_PER_SEC((__clock_t) 1000000),
1117 (((double)end - (double)start) / CLOCKS_PER_SEC((__clock_t) 1000000) / (double) ITERATIONS) * 1000,
1118 g_timer_elapsed (timer, NULL((void*)0)),
1119 milliseconds_to_draw_frame);
1120
1121 g_timer_destroy (timer);
1122 g_object_unref (G_OBJECT (layout)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((layout)), (((GType) ((20) << (2))))))))
);
1123 gtk_widget_destroy (widget);
1124
1125#undef ITERATIONS
1126}
1127
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-19e9c7.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-19e9c7.html new file mode 100644 index 00000000..21c3bf66 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-19e9c7.html @@ -0,0 +1,1420 @@ + + + +core/async-getprop.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/async-getprop.c
Warning:line 448, column 28
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name async-getprop.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/async-getprop.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Asynchronous X property getting hack */
4
5/*
6 * Copyright (C) 2002 Havoc Pennington
7 * Copyright (C) 1986, 1998 The Open Group
8 *
9 * Permission to use, copy, modify, distribute, and sell this software
10 * and its documentation for any purpose is hereby granted without
11 * fee, provided that the above copyright notice appear in all copies
12 * and that both that copyright notice and this permission notice
13 * appear in supporting documentation.
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Except as contained in this notice, the name of The Open Group shall not be
27 * used in advertising or otherwise to promote the sale, use or other dealings
28 * in this Software without prior written authorization from The Open Group.
29 */
30
31#include <assert.h>
32
33#undef DEBUG_SPEW
34#ifdef DEBUG_SPEW
35#include <stdio.h>
36#endif
37
38#include "async-getprop.h"
39
40#define NEED_REPLIES
41#include <X11/Xlibint.h>
42
43#ifndef NULL((void*)0)
44#define NULL((void*)0) ((void*)0)
45#endif
46
47typedef struct _ListNode ListNode;
48typedef struct _AgPerDisplayData AgPerDisplayData;
49
50struct _ListNode
51{
52 ListNode *next;
53};
54
55struct _AgGetPropertyTask
56{
57 ListNode node;
58
59 AgPerDisplayData *dd;
60 Window window;
61 Atom property;
62
63 unsigned long request_seq;
64 int error;
65
66 Atom actual_type;
67 int actual_format;
68
69 unsigned long n_items;
70 unsigned long bytes_after;
71 char *data;
72
73 Boolint have_reply;
74};
75
76struct _AgPerDisplayData
77{
78 ListNode node;
79 _XAsyncHandler async;
80
81 Display *display;
82 ListNode *pending_tasks;
83 ListNode *pending_tasks_tail;
84 ListNode *completed_tasks;
85 ListNode *completed_tasks_tail;
86 int n_tasks_pending;
87 int n_tasks_completed;
88};
89
90static ListNode *display_datas = NULL((void*)0);
91static ListNode *display_datas_tail = NULL((void*)0);
92
93static void
94append_to_list (ListNode **head,
95 ListNode **tail,
96 ListNode *task)
97{
98 task->next = NULL((void*)0);
99
100 if (*tail == NULL((void*)0))
101 {
102 assert (*head == NULL)((void) sizeof ((*head == ((void*)0)) ? 1 : 0), __extension__
({ if (*head == ((void*)0)) ; else __assert_fail ("*head == NULL"
, "core/async-getprop.c", 102, __extension__ __PRETTY_FUNCTION__
); }))
;
103 *head = task;
104 *tail = task;
105 }
106 else
107 {
108 (*tail)->next = task;
109 *tail = task;
110 }
111}
112
113static void
114remove_from_list (ListNode **head,
115 ListNode **tail,
116 ListNode *task)
117{
118 ListNode *prev;
119 ListNode *node;
120
121 prev = NULL((void*)0);
122 node = *head;
123 while (node != NULL((void*)0))
124 {
125 if (node == task)
126 {
127 if (prev)
128 prev->next = node->next;
129 else
130 *head = node->next;
131
132 if (node == *tail)
133 *tail = prev;
134
135 break;
136 }
137
138 prev = node;
139 node = node->next;
140 }
141
142 /* can't remove what's not there */
143 assert (node != NULL)((void) sizeof ((node != ((void*)0)) ? 1 : 0), __extension__ (
{ if (node != ((void*)0)) ; else __assert_fail ("node != NULL"
, "core/async-getprop.c", 143, __extension__ __PRETTY_FUNCTION__
); }))
;
144
145 node->next = NULL((void*)0);
146}
147
148static void
149move_to_completed (AgPerDisplayData *dd,
150 AgGetPropertyTask *task)
151{
152 remove_from_list (&dd->pending_tasks,
153 &dd->pending_tasks_tail,
154 &task->node);
155
156 append_to_list (&dd->completed_tasks,
157 &dd->completed_tasks_tail,
158 &task->node);
159
160 dd->n_tasks_pending -= 1;
161 dd->n_tasks_completed += 1;
162}
163
164static AgGetPropertyTask*
165find_pending_by_request_sequence (AgPerDisplayData *dd,
166 unsigned long request_seq)
167{
168 ListNode *node;
169
170 /* if the sequence is after our last pending task, we
171 * aren't going to find a match
172 */
173 {
174 AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail;
175 if (task != NULL((void*)0))
176 {
177 if (task->request_seq < request_seq)
178 return NULL((void*)0);
179 else if (task->request_seq == request_seq)
180 return task; /* why not check this */
181 }
182 }
183
184 /* Generally we should get replies in the order we sent
185 * requests, so we should usually be using the task
186 * at the head of the list, if we use any task at all.
187 * I'm not sure this is 100% guaranteed, if it is,
188 * it would be a big speedup.
189 */
190
191 node = dd->pending_tasks;
192 while (node != NULL((void*)0))
193 {
194 AgGetPropertyTask *task = (AgGetPropertyTask*) node;
195
196 if (task->request_seq == request_seq)
197 return task;
198
199 node = node->next;
200 }
201
202 return NULL((void*)0);
203}
204
205static Boolint
206async_get_property_handler (Display *dpy,
207 xReply *rep,
208 char *buf,
209 int len,
210 XPointer data)
211{
212 xGetPropertyReply replbuf;
213 xGetPropertyReply *reply;
214 AgGetPropertyTask *task;
215 AgPerDisplayData *dd;
216 int bytes_read;
217
218 dd = (void*) data;
219
220#if 0
221 printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__,
222 dpy->last_request_read, len);
223#endif
224
225 task = find_pending_by_request_sequence (dd, dpy->last_request_read);
226
227 if (task == NULL((void*)0))
1
Assuming 'task' is not equal to NULL
2
Taking false branch
228 return False0;
229
230 assert (dpy->last_request_read == task->request_seq)((void) sizeof ((dpy->last_request_read == task->request_seq
) ? 1 : 0), __extension__ ({ if (dpy->last_request_read ==
task->request_seq) ; else __assert_fail ("dpy->last_request_read == task->request_seq"
, "core/async-getprop.c", 230, __extension__ __PRETTY_FUNCTION__
); }))
;
3
Assuming field 'last_request_read' is equal to field 'request_seq'
4
Taking true branch
231
232 task->have_reply = True1;
233 move_to_completed (dd, task);
234
235 /* read bytes so far */
236 bytes_read = SIZEOF (xReply)32;
237
238 if (rep->generic.type == X_Error0)
5
Assuming field 'type' is not equal to X_Error
6
Taking false branch
239 {
240 xError errbuf;
241
242 task->error = rep->error.errorCode;
243
244#ifdef DEBUG_SPEW
245 printf ("%s: error code = %d (ignoring error, eating %d bytes, generic.length = %ld)\n",
246 __FUNCTION__, task->error, (SIZEOF (xError)32 - bytes_read),
247 rep->generic.length);
248#endif
249
250 /* We return True (meaning we consumed the reply)
251 * because otherwise it would invoke the X error handler,
252 * and an async API is useless if you have to synchronously
253 * trap X errors. Also GetProperty can always fail, pretty
254 * much, so trapping errors is always what you want.
255 *
256 * We have to eat all the error reply data here.
257 * (kind of a charade as we know sizeof(xError) == sizeof(xReply))
258 *
259 * Passing discard = True seems to break things; I don't understand
260 * why, because there should be no extra data in an error reply,
261 * right?
262 */
263 _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
264 (SIZEOF (xError)32 - bytes_read) >> 2, /* in 32-bit words */
265 False0); /* really seems like it should be True */
266
267 return True1;
268 }
269
270#ifdef DEBUG_SPEW
271 printf ("%s: already read %d bytes reading %d more for total of %d; generic.length = %ld\n",
272 __FUNCTION__, bytes_read, (SIZEOF (xGetPropertyReply)32 - bytes_read) >> 2,
273 SIZEOF (xGetPropertyReply)32, rep->generic.length);
274#endif
275
276 /* (kind of a silly as we know sizeof(xGetPropertyReply) == sizeof(xReply)) */
277 reply = (xGetPropertyReply *) (void *)
278 _XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len,
279 (SIZEOF (xGetPropertyReply)32 - bytes_read) >> 2, /* in 32-bit words */
280 False0); /* False means expecting more data to follow,
281 * don't eat the rest of the reply
282 */
283
284 bytes_read = SIZEOF (xGetPropertyReply)32;
285
286#ifdef DEBUG_SPEW
287 printf ("%s: have reply propertyType = %ld format = %d n_items = %ld\n",
288 __FUNCTION__, reply->propertyType, reply->format, reply->nItems);
289#endif
290
291 assert (task->data == NULL)((void) sizeof ((task->data == ((void*)0)) ? 1 : 0), __extension__
({ if (task->data == ((void*)0)) ; else __assert_fail ("task->data == NULL"
, "core/async-getprop.c", 291, __extension__ __PRETTY_FUNCTION__
); }))
;
7
Assuming field 'data' is equal to null
8
Taking true branch
292
293 /* This is all copied from XGetWindowProperty(). Not sure we should
294 * LockDisplay(). Not sure I'm passing the right args to
295 * XGetAsyncData(). Not sure about a lot of things.
296 */
297
298 /* LockDisplay (dpy); */
299
300 if (reply->propertyType != None0L)
9
Assuming field 'propertyType' is not equal to None
10
Taking true branch
301 {
302 long nbytes, netbytes;
303
304 /* this alignment macro from matecorba2 */
305#define ALIGN_VALUE(this, boundary)(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)
) & (~(((unsigned long)(boundary))-1)))
\
306 (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
307
308 switch (reply->format)
11
Control jumps to 'case 8:' at line 316
309 {
310 /*
311 * One extra byte is malloced than is needed to contain the property
312 * data, but this last byte is null terminated and convenient for
313 * returning string properties, so the client doesn't then have to
314 * recopy the string to make it null terminated.
315 */
316 case 8:
317 nbytes = reply->nItems;
318 /* there's padding to word boundary */
319 netbytes = ALIGN_VALUE (nbytes, 4)(( ((unsigned long)(nbytes)) + (((unsigned long)(4)) -1)) &
(~(((unsigned long)(4))-1)))
;
320 if (nbytes + 1 > 0 &&
12
Assuming the condition is true
16
Taking true branch
321 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)malloc((size_t)(((unsigned)nbytes + 1) == 0 ? 1 : ((unsigned)
nbytes + 1)))
))
13
Assuming the condition is true
14
'?' condition is true
15
Assuming field 'data' is non-null
322 {
323#ifdef DEBUG_SPEW
324 printf ("%s: already read %d bytes using %ld, more eating %ld more\n",
325 __FUNCTION__, bytes_read, nbytes, netbytes);
326#endif
327 /* _XReadPad (dpy, (char *) task->data, netbytes); */
328 _XGetAsyncData (dpy, task->data, buf, len,
329 bytes_read, nbytes,
330 netbytes);
331 }
332 break;
17
Execution continues on line 432
333
334 case 16:
335 nbytes = reply->nItems * sizeof (short);
336 netbytes = reply->nItems << 1;
337 netbytes = ALIGN_VALUE (netbytes, 4)(( ((unsigned long)(netbytes)) + (((unsigned long)(4)) -1)) &
(~(((unsigned long)(4))-1)))
; /* align to word boundary */
338 if (nbytes + 1 > 0 &&
339 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)malloc((size_t)(((unsigned)nbytes + 1) == 0 ? 1 : ((unsigned)
nbytes + 1)))
))
340 {
341#ifdef DEBUG_SPEW
342 printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
343 __FUNCTION__, bytes_read, nbytes, netbytes);
344#endif
345 /* _XRead16Pad (dpy, (short *) task->data, netbytes); */
346 _XGetAsyncData (dpy, task->data, buf, len,
347 bytes_read, nbytes, netbytes);
348 }
349 break;
350
351 case 32:
352 /* NOTE buffer is in longs to match XGetWindowProperty() */
353 nbytes = reply->nItems * sizeof (long);
354 netbytes = reply->nItems << 2; /* wire size is always 32 bits though */
355 if (nbytes + 1 > 0 &&
356 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)malloc((size_t)(((unsigned)nbytes + 1) == 0 ? 1 : ((unsigned)
nbytes + 1)))
))
357 {
358#ifdef DEBUG_SPEW
359 printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
360 __FUNCTION__, bytes_read, nbytes, netbytes);
361#endif
362
363 /* We have to copy the XGetWindowProperty() crackrock
364 * and get format 32 as long even on 64-bit platforms.
365 */
366 if (sizeof (long) == 8)
367 {
368 char *netdata;
369 char *lptr;
370 char *end_lptr;
371
372 /* Store the 32-bit values in the end of the array */
373 netdata = task->data + nbytes / 2;
374
375 _XGetAsyncData (dpy, netdata, buf, len,
376 bytes_read, netbytes,
377 netbytes);
378
379 /* Now move the 32-bit values to the front */
380
381 lptr = task->data;
382 end_lptr = task->data + nbytes;
383 while (lptr != end_lptr)
384 {
385 *(long*) lptr = *(CARD32*) netdata;
386 lptr += sizeof (long);
387 netdata += sizeof (CARD32);
388 }
389 }
390 else
391 {
392 /* Here the wire format matches our actual format */
393 _XGetAsyncData (dpy, task->data, buf, len,
394 bytes_read, netbytes,
395 netbytes);
396 }
397 }
398 break;
399
400 default:
401 /*
402 * This part of the code should never be reached. If it is,
403 * the server sent back a property with an invalid format.
404 * This is a BadImplementation error.
405 *
406 * However this async GetProperty API doesn't report errors
407 * via the standard X mechanism, so don't do anything about
408 * it, other than store it in task->error.
409 */
410 {
411#if 0
412 xError error;
413#endif
414
415 task->error = BadImplementation17;
416
417#if 0
418 error.sequenceNumber = task->request_seq;
419 error.type = X_Error0;
420 error.majorCode = X_GetProperty20;
421 error.minorCode = 0;
422 error.errorCode = BadImplementation17;
423
424 _XError (dpy, &error);
425#endif
426 }
427
428 nbytes = netbytes = 0L;
429 break;
430 }
431
432 if (task->data
17.1
Field 'data' is not equal to NULL
== NULL((void*)0))
18
Taking false branch
433 {
434 task->error = BadAlloc11;
435
436#ifdef DEBUG_SPEW
437 printf ("%s: already read %d bytes eating %ld\n",
438 __FUNCTION__, bytes_read, netbytes);
439#endif
440 /* _XEatData (dpy, (unsigned long) netbytes); */
441 _XGetAsyncData (dpy, NULL((void*)0), buf, len,
442 bytes_read, 0, netbytes);
443
444 /* UnlockDisplay (dpy); */
445 return BadAlloc11; /* not Success */
446 }
447
448 (task->data)[nbytes] = '\0';
19
Out of bound memory access (access exceeds upper limit of memory block)
449 }
450
451#ifdef DEBUG_SPEW
452 printf ("%s: have data\n", __FUNCTION__);
453#endif
454
455 task->actual_type = reply->propertyType;
456 task->actual_format = reply->format;
457 task->n_items = reply->nItems;
458 task->bytes_after = reply->bytesAfter;
459
460 /* UnlockDisplay (dpy); */
461
462 return True1;
463}
464
465static AgPerDisplayData*
466get_display_data (Display *display,
467 Boolint create)
468{
469 ListNode *node;
470 AgPerDisplayData *dd;
471
472 node = display_datas;
473 while (node != NULL((void*)0))
474 {
475 dd = (AgPerDisplayData*) node;
476
477 if (dd->display == display)
478 return dd;
479
480 node = node->next;
481 }
482
483 if (!create)
484 return NULL((void*)0);
485
486 dd = Xcalloc (1, sizeof (AgPerDisplayData))calloc((size_t)((1) == 0 ? 1 : (1)), (size_t)(sizeof (AgPerDisplayData
)))
;
487 if (dd == NULL((void*)0))
488 return NULL((void*)0);
489
490 dd->display = display;
491 dd->async.next = display->async_handlers;
492 dd->async.handler = async_get_property_handler;
493 dd->async.data = (XPointer) dd;
494 dd->display->async_handlers = &dd->async;
495
496 append_to_list (&display_datas,
497 &display_datas_tail,
498 &dd->node);
499
500 return dd;
501}
502
503static void
504maybe_free_display_data (AgPerDisplayData *dd)
505{
506 if (dd->pending_tasks == NULL((void*)0) &&
507 dd->completed_tasks == NULL((void*)0))
508 {
509 DeqAsyncHandler (dd->display, &dd->async){ if (dd->display->async_handlers == (&dd->async
)) dd->display->async_handlers = (&dd->async)->
next; else _XDeqAsyncHandler(dd->display, &dd->async
); }
;
510 remove_from_list (&display_datas, &display_datas_tail,
511 &dd->node);
512 XFree (dd);
513 }
514}
515
516AgGetPropertyTask*
517ag_task_create (Display *dpy,
518 Window window,
519 Atom property,
520 long offset,
521 long length,
522 Boolint delete,
523 Atom req_type)
524{
525 AgGetPropertyTask *task;
526 xGetPropertyReq *req;
527 AgPerDisplayData *dd;
528
529 /* Fire up our request */
530 LockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
531
532 dd = get_display_data (dpy, True1);
533 if (dd == NULL((void*)0))
534 {
535 UnlockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
536 return NULL((void*)0);
537 }
538
539 GetReq (GetProperty, req)req = (xGetPropertyReq *) _XGetRequest(dpy, 20, 24);
540 req->window = window;
541 req->property = property;
542 req->type = req_type;
543 req->delete = delete;
544 req->longOffset = offset;
545 req->longLength = length;
546
547 /* Queue up our async task */
548 task = Xcalloc (1, sizeof (AgGetPropertyTask))calloc((size_t)((1) == 0 ? 1 : (1)), (size_t)(sizeof (AgGetPropertyTask
)))
;
549 if (task == NULL((void*)0))
550 {
551 UnlockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
552 return NULL((void*)0);
553 }
554
555 task->dd = dd;
556 task->window = window;
557 task->property = property;
558 task->request_seq = dpy->request;
559
560 append_to_list (&dd->pending_tasks,
561 &dd->pending_tasks_tail,
562 &task->node);
563 dd->n_tasks_pending += 1;
564
565 UnlockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
566
567 SyncHandle ()if (dpy->synchandler) (*dpy->synchandler)(dpy);
568
569 return task;
570}
571
572static void
573free_task (AgGetPropertyTask *task)
574{
575 remove_from_list (&task->dd->completed_tasks,
576 &task->dd->completed_tasks_tail,
577 &task->node);
578 task->dd->n_tasks_completed -= 1;
579 maybe_free_display_data (task->dd);
580 XFree (task);
581}
582
583Statusint
584ag_task_get_reply_and_free (AgGetPropertyTask *task,
585 Atom *actual_type,
586 int *actual_format,
587 unsigned long *nitems,
588 unsigned long *bytesafter,
589 unsigned char **prop)
590{
591 Display *dpy;
592
593 *prop = NULL((void*)0);
594
595 dpy = task->dd->display; /* Xlib macros require a variable named "dpy" */
596
597 if (task->error != Success0)
598 {
599 Statusint s = task->error;
600
601 free_task (task);
602
603 return s;
604 }
605
606 if (!task->have_reply)
607 {
608 free_task (task);
609
610 return BadAlloc11; /* not Success */
611 }
612
613 *actual_type = task->actual_type;
614 *actual_format = task->actual_format;
615 *nitems = task->n_items;
616 *bytesafter = task->bytes_after;
617
618 *prop = (unsigned char*) task->data; /* pass out ownership of task->data */
619
620 SyncHandle ()if (dpy->synchandler) (*dpy->synchandler)(dpy);
621
622 free_task (task);
623
624 return Success0;
625}
626
627Boolint
628ag_task_have_reply (AgGetPropertyTask *task)
629{
630 return task->have_reply;
631}
632
633Atom
634ag_task_get_property (AgGetPropertyTask *task)
635{
636 return task->property;
637}
638
639Window
640ag_task_get_window (AgGetPropertyTask *task)
641{
642 return task->window;
643}
644
645Display*
646ag_task_get_display (AgGetPropertyTask *task)
647{
648 return task->dd->display;
649}
650
651AgGetPropertyTask*
652ag_get_next_completed_task (Display *display)
653{
654 AgPerDisplayData *dd;
655
656 dd = get_display_data (display, False0);
657
658 if (dd == NULL((void*)0))
659 return NULL((void*)0);
660
661#ifdef DEBUG_SPEW
662 printf ("%d pending %d completed\n",
663 dd->n_tasks_pending,
664 dd->n_tasks_completed);
665#endif
666
667 return (AgGetPropertyTask*) dd->completed_tasks;
668}
669
670void*
671ag_Xmalloc (unsigned long bytes)
672{
673 return (void*) Xmalloc (bytes)malloc((size_t)((bytes) == 0 ? 1 : (bytes)));
674}
675
676void*
677ag_Xmalloc0 (unsigned long bytes)
678{
679 return (void*) Xcalloc (bytes, 1)calloc((size_t)((bytes) == 0 ? 1 : (bytes)), (size_t)(1));
680}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-2430c2.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-2430c2.html new file mode 100644 index 00000000..912a1acd --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-2430c2.html @@ -0,0 +1,3697 @@ + + + +ui/frames.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/frames.c
Warning:line 1702, column 16
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name frames.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/frames.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco window frame manager widget */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 * Copyright (C) 2003 Red Hat, Inc.
8 * Copyright (C) 2005, 2006 Elijah Newren
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26#include <config.h>
27#include <glib/gi18n-lib.h>
28
29#include <math.h>
30#include <string.h>
31#include "boxes.h"
32#include "frames.h"
33#include "util.h"
34#include "core.h"
35#include "menu.h"
36#include "fixedtip.h"
37#include "theme.h"
38#include "prefs.h"
39#include "ui.h"
40#include "display.h"
41
42#ifdef HAVE_SHAPE
43#include <X11/extensions/shape.h>
44#endif
45
46#include <cairo-xlib.h>
47
48G_DEFINE_TYPE (MetaFrames, meta_frames, GTK_TYPE_WINDOW)static void meta_frames_init (MetaFrames *self); static void meta_frames_class_init
(MetaFramesClass *klass); static GType meta_frames_get_type_once
(void); static gpointer meta_frames_parent_class = ((void*)0
); static gint MetaFrames_private_offset; static void meta_frames_class_intern_init
(gpointer klass) { meta_frames_parent_class = g_type_class_peek_parent
(klass); if (MetaFrames_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MetaFrames_private_offset); meta_frames_class_init
((MetaFramesClass*) klass); } __attribute__ ((__unused__)) static
inline gpointer meta_frames_get_instance_private (MetaFrames
*self) { return (((gpointer) ((guint8*) (self) + (glong) (MetaFrames_private_offset
)))); } GType meta_frames_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = meta_frames_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType meta_frames_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_window_get_type ()), g_intern_static_string ("MetaFrames"
), sizeof (MetaFramesClass), (GClassInitFunc)(void (*)(void))
meta_frames_class_intern_init, sizeof (MetaFrames), (GInstanceInitFunc
)(void (*)(void)) meta_frames_init, (GTypeFlags) 0); { {{};} }
return g_define_type_id; }
;
49
50#define DEFAULT_INNER_BUTTON_BORDER3 3
51
52static void meta_frames_class_init (MetaFramesClass *klass);
53static void meta_frames_init (MetaFrames *frames);
54static void meta_frames_destroy (GtkWidget *object);
55static void meta_frames_finalize (GObject *object);
56static void meta_frames_style_updated (GtkWidget *widget);
57
58static void meta_frames_update_prelit_control (MetaFrames *frames,
59 MetaUIFrame *frame,
60 MetaFrameControl control);
61static gboolean meta_frames_button_press_event (GtkWidget *widget,
62 GdkEventButton *event);
63static gboolean meta_frames_button_release_event (GtkWidget *widget,
64 GdkEventButton *event);
65static gboolean meta_frames_motion_notify_event (GtkWidget *widget,
66 GdkEventMotion *event);
67static gboolean meta_frames_destroy_event (GtkWidget *widget,
68 GdkEventAny *event);
69static gboolean meta_frames_draw (GtkWidget *widget,
70 cairo_t *cr);
71static gboolean meta_frames_enter_notify_event (GtkWidget *widget,
72 GdkEventCrossing *event);
73static gboolean meta_frames_leave_notify_event (GtkWidget *widget,
74 GdkEventCrossing *event);
75
76static void meta_frames_attach_style (MetaFrames *frames,
77 MetaUIFrame *frame);
78
79static void meta_frames_paint_to_drawable (MetaFrames *frames,
80 MetaUIFrame *frame,
81 cairo_t *cr);
82
83static void meta_frames_calc_geometry (MetaFrames *frames,
84 MetaUIFrame *frame,
85 MetaFrameGeometry *fgeom);
86
87static void meta_frames_ensure_layout (MetaFrames *frames,
88 MetaUIFrame *frame);
89
90static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
91 Window xwindow);
92
93static void meta_frames_font_changed (MetaFrames *frames);
94static void meta_frames_button_layout_changed (MetaFrames *frames);
95
96static GdkRectangle* control_rect (MetaFrameControl control,
97 MetaFrameGeometry *fgeom);
98static MetaFrameControl get_control (MetaFrames *frames,
99 MetaUIFrame *frame,
100 int x,
101 int y);
102static void clear_tip (MetaFrames *frames);
103static void invalidate_all_caches (MetaFrames *frames);
104static void invalidate_whole_window (MetaFrames *frames,
105 MetaUIFrame *frame);
106
107static GObject *
108meta_frames_constructor (GType gtype,
109 guint n_properties,
110 GObjectConstructParam *properties)
111{
112 GObject *object;
113 GObjectClass *gobject_class;
114
115 gobject_class = G_OBJECT_CLASS (meta_frames_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), (((GType) ((20) << (2)
)))))))
;
116 object = gobject_class->constructor (gtype, n_properties, properties);
117
118 return object;
119}
120
121static void
122meta_frames_class_init (MetaFramesClass *class)
123{
124 GObjectClass *gobject_class;
125 GtkWidgetClass *widget_class;
126
127 gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
128 widget_class = (GtkWidgetClass*) class;
129
130 gobject_class->constructor = meta_frames_constructor;
131 gobject_class->finalize = meta_frames_finalize;
132 widget_class->destroy = meta_frames_destroy;
133 widget_class->style_updated = meta_frames_style_updated;
134
135 widget_class->draw = meta_frames_draw;
136 widget_class->destroy_event = meta_frames_destroy_event;
137 widget_class->button_press_event = meta_frames_button_press_event;
138 widget_class->button_release_event = meta_frames_button_release_event;
139 widget_class->motion_notify_event = meta_frames_motion_notify_event;
140 widget_class->enter_notify_event = meta_frames_enter_notify_event;
141 widget_class->leave_notify_event = meta_frames_leave_notify_event;
142}
143
144static gint
145unsigned_long_equal (gconstpointer v1,
146 gconstpointer v2)
147{
148 return *((const gulong*) v1) == *((const gulong*) v2);
149}
150
151static guint
152unsigned_long_hash (gconstpointer v)
153{
154 gulong val = * (const gulong *) v;
155
156 /* I'm not sure this works so well. */
157#if GLIB_SIZEOF_LONG8 > 4
158 return (guint) (val ^ (val >> 32));
159#else
160 return val;
161#endif
162}
163
164static void
165prefs_changed_callback (MetaPreference pref,
166 void *data)
167{
168 switch (pref)
169 {
170 case META_PREF_TITLEBAR_FONT:
171 meta_frames_font_changed (META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
);
172 break;
173 case META_PREF_BUTTON_LAYOUT:
174 meta_frames_button_layout_changed (META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
);
175 break;
176 default:
177 break;
178 }
179}
180
181static GtkStyleContext *
182create_style_context (MetaFrames *frames,
183 const gchar *variant)
184{
185 GtkStyleContext *style;
186 GdkScreen *screen;
187 char *theme_name;
188
189 screen = gtk_widget_get_screen (GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
);
190 g_object_get (gtk_settings_get_for_screen (screen),
191 "gtk-theme-name", &theme_name,
192 NULL((void*)0));
193
194 style = gtk_style_context_new ();
195 gtk_style_context_set_path (style,
196 gtk_widget_get_path (GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
));
197
198 if (theme_name && *theme_name)
199 {
200 GtkCssProvider *provider;
201
202 provider = gtk_css_provider_get_named (theme_name, variant);
203 gtk_style_context_add_provider (style,
204 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
205 GTK_STYLE_PROVIDER_PRIORITY_SETTINGS400);
206 }
207
208 if (theme_name)
209 g_free (theme_name);
210
211 return style;
212}
213
214static GtkStyleContext *
215meta_frames_get_theme_variant (MetaFrames *frames,
216 const gchar *variant)
217{
218 GtkStyleContext *style;
219
220 style = g_hash_table_lookup (frames->style_variants, variant);
221 if (style == NULL((void*)0))
222 {
223 style = create_style_context (frames, variant);
224 g_hash_table_insert (frames->style_variants, g_strdup (variant)g_strdup_inline (variant), style);
225 }
226
227 return style;
228}
229
230static void
231update_style_contexts (MetaFrames *frames)
232{
233 GtkStyleContext *style;
234 GList *variant_list, *variant;
235
236 if (frames->normal_style)
237 g_object_unref (frames->normal_style);
238 frames->normal_style = create_style_context (frames, NULL((void*)0));
239
240 variant_list = g_hash_table_get_keys (frames->style_variants);
241 for (variant = variant_list; variant; variant = variant->next)
242 {
243 style = create_style_context (frames, (char *)variant->data);
244 g_hash_table_insert (frames->style_variants,
245 g_strdup (variant->data)g_strdup_inline (variant->data), style);
246 }
247 g_list_free (variant_list);
248}
249static void
250meta_frames_init (MetaFrames *frames)
251{
252 frames->text_heights = g_hash_table_new (NULL((void*)0), NULL((void*)0));
253
254 frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
255
256 frames->tooltip_timeout = 0;
257
258 frames->expose_delay_count = 0;
259
260 frames->invalidate_cache_timeout_id = 0;
261 frames->invalidate_frames = NULL((void*)0);
262 frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
263 frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal,
264 g_free, g_object_unref);
265 update_style_contexts (frames);
266
267 meta_prefs_add_listener (prefs_changed_callback, frames);
268}
269
270static void
271listify_func (gpointer key, gpointer value, gpointer data)
272{
273 GSList **listp;
274
275 listp = data;
276 *listp = g_slist_prepend (*listp, value);
277}
278
279static void
280meta_frames_destroy (GtkWidget *widget)
281{
282 GSList *winlist;
283 GSList *tmp;
284 MetaFrames *frames;
285
286 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
287
288 clear_tip (frames);
289
290 winlist = NULL((void*)0);
291 g_hash_table_foreach (frames->frames, listify_func, &winlist);
292
293 /* Unmanage all frames */
294 for (tmp = winlist; tmp != NULL((void*)0); tmp = tmp->next)
295 {
296 MetaUIFrame *frame;
297
298 frame = tmp->data;
299
300 meta_frames_unmanage_window (frames, frame->xwindow);
301 }
302 g_slist_free (winlist);
303
304 if (frames->normal_style)
305 {
306 g_object_unref (frames->normal_style);
307 frames->normal_style = NULL((void*)0);
308 }
309
310 if (frames->style_variants)
311 {
312 g_hash_table_destroy (frames->style_variants);
313 frames->style_variants = NULL((void*)0);
314 }
315
316 GTK_WIDGET_CLASS (meta_frames_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), ((gtk_widget_get_type ()))))
))
->destroy (widget);
317}
318
319static void
320meta_frames_finalize (GObject *object)
321{
322 MetaFrames *frames;
323
324 frames = META_FRAMES (object)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((meta_frames_get_type ()))))))
;
325
326 meta_prefs_remove_listener (prefs_changed_callback, frames);
327
328 g_hash_table_destroy (frames->text_heights);
329
330 invalidate_all_caches (frames);
331 if (frames->invalidate_cache_timeout_id)
332 g_source_remove (frames->invalidate_cache_timeout_id);
333
334 g_assert (g_hash_table_size (frames->frames) == 0)do { if (g_hash_table_size (frames->frames) == 0) ; else g_assertion_message_expr
("marco", "ui/frames.c", 334, ((const char*) (__func__)), "g_hash_table_size (frames->frames) == 0"
); } while (0)
;
335 g_hash_table_destroy (frames->frames);
336 g_hash_table_destroy (frames->cache);
337
338 G_OBJECT_CLASS (meta_frames_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), (((GType) ((20) << (2)
)))))))
->finalize (object);
339}
340
341typedef struct
342{
343 cairo_rectangle_int_t rect;
344 cairo_surface_t *pixmap;
345} CachedFramePiece;
346
347typedef struct
348{
349 /* Caches of the four rendered sides in a MetaFrame.
350 * Order: top (titlebar), left, right, bottom.
351 */
352 CachedFramePiece piece[4];
353} CachedPixels;
354
355static CachedPixels *
356get_cache (MetaFrames *frames,
357 MetaUIFrame *frame)
358{
359 CachedPixels *pixels;
360
361 pixels = g_hash_table_lookup (frames->cache, frame);
362
363 if (!pixels)
364 {
365 pixels = g_new0 (CachedPixels, 1)((CachedPixels *) g_malloc0_n ((1), sizeof (CachedPixels)));
366 g_hash_table_insert (frames->cache, frame, pixels);
367 }
368
369 return pixels;
370}
371
372static void
373invalidate_cache (MetaFrames *frames,
374 MetaUIFrame *frame)
375{
376 CachedPixels *pixels = get_cache (frames, frame);
377 int i;
378
379 for (i = 0; i < 4; i++)
380 if (pixels->piece[i].pixmap)
381 cairo_surface_destroy (pixels->piece[i].pixmap);
382
383 g_free (pixels);
384 g_hash_table_remove (frames->cache, frame);
385}
386
387static void
388invalidate_all_caches (MetaFrames *frames)
389{
390 GList *l;
391
392 for (l = frames->invalidate_frames; l; l = l->next)
393 {
394 MetaUIFrame *frame = l->data;
395
396 invalidate_cache (frames, frame);
397 }
398
399 g_list_free (frames->invalidate_frames);
400 frames->invalidate_frames = NULL((void*)0);
401}
402
403static gboolean
404invalidate_cache_timeout (gpointer data)
405{
406 MetaFrames *frames = data;
407
408 invalidate_all_caches (frames);
409 frames->invalidate_cache_timeout_id = 0;
410 return FALSE(0);
411}
412
413static void
414queue_recalc_func (gpointer key, gpointer value, gpointer data)
415{
416 MetaUIFrame *frame;
417 MetaFrames *frames;
418
419 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
420 frame = value;
421
422 invalidate_whole_window (frames, frame);
423 meta_core_queue_frame_resize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
424 frame->xwindow);
425 if (frame->text_layout)
426 {
427 /* save title to recreate layout */
428 g_free (frame->title);
429
430 frame->title = g_strdup (pango_layout_get_text (frame->text_layout))g_strdup_inline (pango_layout_get_text (frame->text_layout
))
;
431
432 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
433 }
434}
435
436static void
437meta_frames_font_changed (MetaFrames *frames)
438{
439 if (g_hash_table_size (frames->text_heights) > 0)
440 {
441 g_hash_table_destroy (frames->text_heights);
442 frames->text_heights = g_hash_table_new (NULL((void*)0), NULL((void*)0));
443 }
444
445 /* Queue a draw/resize on all frames */
446 g_hash_table_foreach (frames->frames,
447 queue_recalc_func, frames);
448
449}
450
451static void
452queue_draw_func (gpointer key, gpointer value, gpointer data)
453{
454 MetaUIFrame *frame;
455 MetaFrames *frames;
456
457 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
458 frame = value;
459
460 invalidate_whole_window (frames, frame);
461}
462
463static void
464meta_frames_button_layout_changed (MetaFrames *frames)
465{
466 g_hash_table_foreach (frames->frames,
467 queue_draw_func, frames);
468}
469
470static void
471reattach_style_func (gpointer key, gpointer value, gpointer data)
472{
473 MetaUIFrame *frame;
474 MetaFrames *frames;
475
476 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
477 frame = value;
478
479 meta_frames_attach_style (frames, frame);
480}
481
482static void
483meta_frames_style_updated (GtkWidget *widget)
484{
485 MetaFrames *frames;
486
487 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
488
489 meta_frames_font_changed (frames);
490
491 update_style_contexts (frames);
492 g_hash_table_foreach (frames->frames,
493 reattach_style_func, frames);
494
495 GTK_WIDGET_CLASS (meta_frames_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), ((gtk_widget_get_type ()))))
))
->style_updated (widget);
496}
497
498static void
499meta_frames_ensure_layout (MetaFrames *frames,
500 MetaUIFrame *frame)
501{
502 GtkWidget *widget;
503 MetaFrameFlags flags;
504 MetaFrameType type;
505 MetaFrameStyle *style;
506
507 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (frames)))do { if ((gtk_widget_get_realized (((((GtkWidget*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((frames)), ((gtk_widget_get_type ()))))))
))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "gtk_widget_get_realized (GTK_WIDGET (frames))"
); return; } } while (0)
;
508
509 widget = GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
;
510
511 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
512 META_CORE_GET_FRAME_FLAGS, &flags,
513 META_CORE_GET_FRAME_TYPE, &type,
514 META_CORE_GET_END);
515
516 style = meta_theme_get_frame_style (meta_theme_get_current (),
517 type, flags);
518
519 if (style != frame->cache_style)
520 {
521 if (frame->text_layout)
522 {
523 /* save title to recreate layout */
524 g_free (frame->title);
525
526 frame->title = g_strdup (pango_layout_get_text (frame->text_layout))g_strdup_inline (pango_layout_get_text (frame->text_layout
))
;
527
528 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
529 }
530 }
531
532 frame->cache_style = style;
533
534 if (frame->text_layout == NULL((void*)0))
535 {
536 gpointer key, value;
537 PangoFontDescription *font_desc;
538 double scale;
539 int size;
540
541 scale = meta_theme_get_title_scale (meta_theme_get_current (),
542 type,
543 flags);
544
545 frame->text_layout = gtk_widget_create_pango_layout (widget, frame->title);
546
547 pango_layout_set_ellipsize (frame->text_layout, PANGO_ELLIPSIZE_END);
548 pango_layout_set_auto_dir (frame->text_layout, FALSE(0));
549
550 pango_layout_set_single_paragraph_mode (frame->text_layout, TRUE(!(0)));
551
552 font_desc = meta_gtk_widget_get_font_desc (widget, scale,
553 meta_prefs_get_titlebar_font ());
554
555 size = pango_font_description_get_size (font_desc);
556
557 if (g_hash_table_lookup_extended (frames->text_heights,
558 GINT_TO_POINTER (size)((gpointer) (glong) (size)),
559 &key, &value))
560 {
561 frame->text_height = GPOINTER_TO_INT (value)((gint) (glong) (value));
562 }
563 else
564 {
565 frame->text_height =
566 meta_pango_font_desc_get_text_height (font_desc,
567 gtk_widget_get_pango_context (widget));
568
569 g_hash_table_replace (frames->text_heights,
570 GINT_TO_POINTER (size)((gpointer) (glong) (size)),
571 GINT_TO_POINTER (frame->text_height)((gpointer) (glong) (frame->text_height)));
572 }
573
574 pango_layout_set_font_description (frame->text_layout,
575 font_desc);
576
577 pango_font_description_free (font_desc);
578
579 /* Save some RAM */
580 g_free (frame->title);
581 frame->title = NULL((void*)0);
582 }
583}
584
585static void
586meta_frames_calc_geometry (MetaFrames *frames,
587 MetaUIFrame *frame,
588 MetaFrameGeometry *fgeom)
589{
590 int width, height, scale;
591 MetaFrameFlags flags;
592 MetaFrameType type;
593 MetaButtonLayout button_layout;
594
595 scale = gdk_window_get_scale_factor (frame->window);
596
597 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
598 META_CORE_GET_CLIENT_WIDTH, &width,
599 META_CORE_GET_CLIENT_HEIGHT, &height,
600 META_CORE_GET_FRAME_FLAGS, &flags,
601 META_CORE_GET_FRAME_TYPE, &type,
602 META_CORE_GET_END);
603
604 meta_frames_ensure_layout (frames, frame);
605
606 meta_prefs_get_button_layout (&button_layout);
607
608 meta_theme_calc_geometry (meta_theme_get_current (),
609 type,
610 frame->text_height,
611 flags,
612 width / scale, height / scale,
613 &button_layout,
614 fgeom);
615}
616
617MetaFrames*
618meta_frames_new (void)
619{
620 GdkScreen *screen;
621 MetaFrames *frames;
622
623 screen = gdk_display_get_default_screen (gdk_display_get_default ());
624
625 frames = g_object_new (META_TYPE_FRAMES(meta_frames_get_type ()),
626 "screen", screen,
627 "type", GTK_WINDOW_POPUP,
628 NULL((void*)0));
629
630 /* Put the window at an arbitrary offscreen location; the one place
631 * it can't be is at -100x-100, since the meta_window_new() will
632 * mistake it for a window created via meta_create_offscreen_window()
633 * and ignore it, and we need this window to get frame-synchronization
634 * messages so that GTK+'s style change handling works.
635 */
636 gtk_window_move (GTK_WINDOW (frames)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_window_get_type ()))))))
, -200, -200);
637 gtk_window_resize (GTK_WINDOW (frames)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_window_get_type ()))))))
, 1, 1);
638
639 return frames;
640}
641
642/* In order to use a style with a window it has to be attached to that
643 * window. Actually, the colormaps just have to match, but since GTK+
644 * already takes care of making sure that its cheap to attach a style
645 * to multiple windows with the same colormap, we can just go ahead
646 * and attach separately for each window.
647 */
648static void
649meta_frames_attach_style (MetaFrames *frames,
650 MetaUIFrame *frame)
651{
652 gboolean has_frame;
653 char *variant = NULL((void*)0);
654 if (frame->style != NULL((void*)0))
655 g_object_unref (frame->style);
656
657 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
658 frame->xwindow,
659 META_CORE_WINDOW_HAS_FRAME, &has_frame,
660 META_CORE_GET_THEME_VARIANT, &variant,
661 META_CORE_GET_END);
662
663 if (variant == NULL((void*)0) || strcmp(variant, "normal") == 0)
664 frame->style = g_object_ref (frames->normal_style)((__typeof__ (frames->normal_style)) (g_object_ref) (frames
->normal_style))
;
665 else
666 frame->style = g_object_ref (meta_frames_get_theme_variant (frames,((__typeof__ (meta_frames_get_theme_variant (frames, variant)
)) (g_object_ref) (meta_frames_get_theme_variant (frames, variant
)))
667 variant))((__typeof__ (meta_frames_get_theme_variant (frames, variant)
)) (g_object_ref) (meta_frames_get_theme_variant (frames, variant
)))
;
668}
669
670void
671meta_frames_manage_window (MetaFrames *frames,
672 Window xwindow,
673 GdkWindow *window)
674{
675 MetaUIFrame *frame;
676
677 g_assert (window)do { if (window) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 677, ((const char*) (__func__)), "window"); } while (0)
;
678
679 frame = g_new (MetaUIFrame, 1)((MetaUIFrame *) g_malloc_n ((1), sizeof (MetaUIFrame)));
680
681 frame->window = window;
682
683 gdk_window_set_user_data (frame->window, frames);
684
685 frame->style = NULL((void*)0);
686
687 /* Don't set event mask here, it's in frame.c */
688
689 frame->xwindow = xwindow;
690 frame->cache_style = NULL((void*)0);
691 frame->text_layout = NULL((void*)0);
692 frame->text_height = -1;
693 frame->title = NULL((void*)0);
694 frame->expose_delayed = FALSE(0);
695 frame->shape_applied = FALSE(0);
696 frame->prelit_control = META_FRAME_CONTROL_NONE;
697
698 meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
699
700 g_hash_table_replace (frames->frames, &frame->xwindow, frame);
701}
702
703void
704meta_frames_unmanage_window (MetaFrames *frames,
705 Window xwindow)
706{
707 MetaUIFrame *frame;
708
709 clear_tip (frames);
710
711 frame = g_hash_table_lookup (frames->frames, &xwindow);
712
713 if (frame)
714 {
715 /* invalidating all caches ensures the frame
716 * is not actually referenced anymore
717 */
718 invalidate_all_caches (frames);
719
720 /* restore the cursor */
721 meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
722 frame->xwindow,
723 META_CURSOR_DEFAULT);
724
725 gdk_window_set_user_data (frame->window, NULL((void*)0));
726
727 if (frames->last_motion_frame == frame)
728 frames->last_motion_frame = NULL((void*)0);
729
730 g_hash_table_remove (frames->frames, &frame->xwindow);
731
732 g_object_unref (frame->style);
733
734 gdk_window_destroy (frame->window);
735
736 if (frame->text_layout)
737 g_object_unref (G_OBJECT (frame->text_layout)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame->text_layout)), (((GType) ((20) << (2))))
))))
);
738
739 if (frame->title)
740 g_free (frame->title);
741
742 g_free (frame);
743 }
744 else
745 meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
746}
747
748static MetaUIFrame*
749meta_frames_lookup_window (MetaFrames *frames,
750 Window xwindow)
751{
752 MetaUIFrame *frame;
753
754 frame = g_hash_table_lookup (frames->frames, &xwindow);
755
756 return frame;
757}
758
759static void
760meta_ui_frame_get_borders (MetaFrames *frames,
761 MetaUIFrame *frame,
762 MetaFrameBorders *borders)
763{
764 MetaFrameFlags flags;
765 MetaFrameType type;
766 gint scale;
767
768 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
769 META_CORE_GET_FRAME_FLAGS, &flags,
770 META_CORE_GET_FRAME_TYPE, &type,
771 META_CORE_GET_END);
772
773 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
774
775 scale = gdk_window_get_scale_factor (frame->window);
776
777 meta_frames_ensure_layout (frames, frame);
778
779 /* We can't get the full geometry, because that depends on
780 * the client window size and probably we're being called
781 * by the core move/resize code to decide on the client
782 * window size
783 */
784 meta_theme_get_frame_borders (meta_theme_get_current (),
785 type,
786 frame->text_height,
787 flags,
788 borders);
789
790 /* Scale frame geometry to ensure proper frame position */
791 borders->visible.top *= scale;
792 borders->visible.bottom *= scale;
793 borders->visible.left *= scale;
794 borders->visible.right *= scale;
795
796 borders->invisible.top *= scale;
797 borders->invisible.bottom *= scale;
798 borders->invisible.left *= scale;
799 borders->invisible.right *= scale;
800
801 borders->total.top *= scale;
802 borders->total.bottom *= scale;
803 borders->total.left *= scale;
804 borders->total.right *= scale;
805}
806
807void
808meta_frames_get_borders (MetaFrames *frames,
809 Window xwindow,
810 MetaFrameBorders *borders)
811{
812 MetaUIFrame *frame;
813
814 frame = meta_frames_lookup_window (frames, xwindow);
815
816 if (frame == NULL((void*)0))
817 g_error ("No such frame 0x%lx\n", xwindow);
818
819 meta_ui_frame_get_borders (frames, frame, borders);
820}
821
822static void
823meta_ui_frame_get_corner_radiuses (MetaFrames *frames,
824 MetaUIFrame *frame,
825 float *top_left,
826 float *top_right,
827 float *bottom_left,
828 float *bottom_right)
829{
830 MetaFrameGeometry fgeom;
831
832 meta_frames_calc_geometry (frames, frame, &fgeom);
833
834 /* For compatibility with the code in get_visible_rect(), there's
835 * a mysterious sqrt() added to the corner radiuses:
836 *
837 * const float radius = sqrt(corner) + corner;
838 *
839 * It's unclear why the radius is calculated like this, but we
840 * need to be consistent with it.
841 */
842
843 if (top_left)
844 *top_left = fgeom.top_left_corner_rounded_radius + sqrt(fgeom.top_left_corner_rounded_radius);
845 if (top_right)
846 *top_right = fgeom.top_right_corner_rounded_radius + sqrt(fgeom.top_right_corner_rounded_radius);
847 if (bottom_left)
848 *bottom_left = fgeom.bottom_left_corner_rounded_radius + sqrt(fgeom.bottom_left_corner_rounded_radius);
849 if (bottom_right)
850 *bottom_right = fgeom.bottom_right_corner_rounded_radius + sqrt(fgeom.bottom_right_corner_rounded_radius);
851}
852
853void
854meta_frames_get_corner_radiuses (MetaFrames *frames,
855 Window xwindow,
856 float *top_left,
857 float *top_right,
858 float *bottom_left,
859 float *bottom_right)
860{
861 MetaUIFrame *frame;
862
863 frame = meta_frames_lookup_window (frames, xwindow);
864
865 meta_ui_frame_get_corner_radiuses (frames, frame, top_left, top_right,
866 bottom_left, bottom_right);
867}
868
869#ifdef HAVE_SHAPE
870static void
871apply_cairo_region_to_window (Display *display,
872 Window xwindow,
873 cairo_region_t *region,
874 int op)
875{
876 int n_rects, i;
877 XRectangle *rects;
878
879 n_rects = cairo_region_num_rectangles (region);
880 rects = g_new (XRectangle, n_rects)((XRectangle *) g_malloc_n ((n_rects), sizeof (XRectangle)));
881
882 for (i = 0; i < n_rects; i++)
883 {
884 cairo_rectangle_int_t rect;
885
886 cairo_region_get_rectangle (region, i, &rect);
887
888 rects[i].x = rect.x;
889 rects[i].y = rect.y;
890 rects[i].width = rect.width;
891 rects[i].height = rect.height;
892 }
893
894 XShapeCombineRectangles (display, xwindow,
895 ShapeBounding0, 0, 0, rects, n_rects,
896 op, YXBanded3);
897
898 g_free (rects);
899}
900#endif
901
902/* The client rectangle surrounds client window; it subtracts both
903 * the visible and invisible borders from the frame window's size.
904 */
905static void
906get_client_rect (MetaFrameGeometry *fgeom,
907 int window_width,
908 int window_height,
909 cairo_rectangle_int_t *rect)
910{
911 rect->x = fgeom->borders.total.left;
912 rect->y = fgeom->borders.total.top;
913 rect->width = window_width - fgeom->borders.total.right - rect->x;
914 rect->height = window_height - fgeom->borders.total.bottom - rect->y;
915}
916
917/* The visible frame rectangle surrounds the visible portion of the
918 * frame window; it subtracts only the invisible borders from the frame
919 * window's size.
920 */
921static void
922get_visible_frame_rect (MetaFrameGeometry *fgeom,
923 int window_width,
924 int window_height,
925 cairo_rectangle_int_t *rect)
926{
927 rect->x = fgeom->borders.invisible.left;
928 rect->y = fgeom->borders.invisible.top;
929 rect->width = window_width - fgeom->borders.invisible.right - rect->x;
930 rect->height = window_height - fgeom->borders.invisible.bottom - rect->y;
931}
932
933static cairo_region_t *
934get_visible_region (MetaFrames *frames,
935 MetaUIFrame *frame,
936 MetaFrameGeometry *fgeom,
937 int window_width,
938 int window_height)
939{
940 cairo_region_t *corners_region;
941 cairo_region_t *visible_region;
942 cairo_rectangle_int_t rect;
943 cairo_rectangle_int_t frame_rect;
944 gint scale;
945
946 corners_region = cairo_region_create ();
947 scale = gdk_window_get_scale_factor (frame->window);
948
949 fgeom->borders.invisible.top *= scale;
950 fgeom->borders.invisible.bottom *= scale;
951 fgeom->borders.invisible.left *= scale;
952 fgeom->borders.invisible.right *= scale;
953
954 get_visible_frame_rect (fgeom, window_width, window_height, &frame_rect);
955
956 if (fgeom->top_left_corner_rounded_radius != 0)
957 {
958 const int corner = fgeom->top_left_corner_rounded_radius * scale;
959 const float radius = sqrt(corner) + corner;
960 int i;
961
962 for (i=0; i<corner; i++)
963 {
964 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
965 rect.x = frame_rect.x;
966 rect.y = frame_rect.y + i;
967 rect.width = width;
968 rect.height = 1;
969
970 cairo_region_union_rectangle (corners_region, &rect);
971 }
972 }
973
974 if (fgeom->top_right_corner_rounded_radius != 0)
975 {
976 const int corner = fgeom->top_right_corner_rounded_radius * scale;
977 const float radius = sqrt(corner) + corner;
978 int i;
979
980 for (i=0; i<corner; i++)
981 {
982 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
983 rect.x = frame_rect.x + frame_rect.width - width;
984 rect.y = frame_rect.y + i;
985 rect.width = width;
986 rect.height = 1;
987
988 cairo_region_union_rectangle (corners_region, &rect);
989 }
990 }
991
992 if (fgeom->bottom_left_corner_rounded_radius != 0)
993 {
994 const int corner = fgeom->bottom_left_corner_rounded_radius * scale;
995 const float radius = sqrt(corner) + corner;
996 int i;
997
998 for (i=0; i<corner; i++)
999 {
1000 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
1001 rect.x = frame_rect.x;
1002 rect.y = frame_rect.y + frame_rect.height - i - 1;
1003 rect.width = width;
1004 rect.height = 1;
1005
1006 cairo_region_union_rectangle (corners_region, &rect);
1007 }
1008 }
1009
1010 if (fgeom->bottom_right_corner_rounded_radius != 0)
1011 {
1012 const int corner = fgeom->bottom_right_corner_rounded_radius * scale;
1013 const float radius = sqrt(corner) + corner;
1014 int i;
1015
1016 for (i=0; i<corner; i++)
1017 {
1018 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
1019 rect.x = frame_rect.x + frame_rect.width - width;
1020 rect.y = frame_rect.y + frame_rect.height - i - 1;
1021 rect.width = width;
1022 rect.height = 1;
1023
1024 cairo_region_union_rectangle (corners_region, &rect);
1025 }
1026 }
1027
1028 visible_region = cairo_region_create_rectangle (&frame_rect);
1029 cairo_region_subtract (visible_region, corners_region);
1030 cairo_region_destroy (corners_region);
1031
1032 return visible_region;
1033}
1034
1035#ifdef HAVE_SHAPE
1036static cairo_region_t *
1037get_client_region (MetaFrameGeometry *fgeom,
1038 int window_width,
1039 int window_height)
1040{
1041 cairo_rectangle_int_t rect;
1042
1043 rect.x = fgeom->borders.total.left;
1044 rect.y = fgeom->borders.total.top;
1045 rect.width = window_width - fgeom->borders.total.right - rect.x;
1046 rect.height = window_height - fgeom->borders.total.bottom - rect.y;
1047
1048 return cairo_region_create_rectangle (&rect);
1049}
1050
1051static cairo_region_t *
1052get_frame_region (int window_width,
1053 int window_height)
1054{
1055 cairo_rectangle_int_t rect;
1056
1057 rect.x = 0;
1058 rect.y = 0;
1059 rect.width = window_width;
1060 rect.height = window_height;
1061
1062 return cairo_region_create_rectangle (&rect);
1063}
1064#endif /* HAVE_SHAPE */
1065
1066void
1067meta_frames_apply_shapes (MetaFrames *frames,
1068 MetaDisplay *meta_display,
1069 Window xwindow,
1070 int new_window_width,
1071 int new_window_height,
1072 gboolean window_has_shape)
1073{
1074#ifdef HAVE_SHAPE
1075 /* Apply shapes as if window had new_window_width, new_window_height */
1076 MetaUIFrame *frame;
1077 MetaFrameGeometry fgeom;
1078 cairo_region_t *window_region;
1079 Display *display;
1080 gboolean compositing_manager;
1081
1082 frame = meta_frames_lookup_window (frames, xwindow);
1083 g_return_if_fail (frame != NULL)do { if ((frame != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "frame != NULL"); return
; } } while (0)
;
1084
1085 display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
1086
1087 if (frame->shape_applied)
1088 {
1089 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1090 "Unsetting shape mask on frame 0x%lx\n",
1091 frame->xwindow);
1092
1093 XShapeCombineMask (display, frame->xwindow,
1094 ShapeBounding0, 0, 0, None0L, ShapeSet0);
1095 frame->shape_applied = FALSE(0);
1096 }
1097
1098 meta_frames_calc_geometry (frames, frame, &fgeom);
1099
1100 compositing_manager = meta_prefs_get_compositing_manager () &&
1101 meta_display &&
1102 !!(meta_display_get_compositor (meta_display));
1103
1104 if (!window_has_shape && compositing_manager)
1105 return;
1106
1107 window_region = get_visible_region (frames,
1108 frame,
1109 &fgeom,
1110 new_window_width,
1111 new_window_height);
1112
1113 if (window_has_shape)
1114 {
1115 /* The client window is oclock or something and has a shape
1116 * mask. To avoid a round trip to get its shape region, we
1117 * create a fake window that's never mapped, build up our shape
1118 * on that, then combine. Wasting the window is assumed cheaper
1119 * than a round trip, but who really knows for sure.
1120 */
1121 XSetWindowAttributes attrs;
1122 Window shape_window;
1123 Window client_window;
1124 cairo_region_t *frame_region;
1125 cairo_region_t *client_region;
1126 cairo_region_t *tmp_region;
1127 GdkScreen *screen;
1128 int screen_number;
1129
1130 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1131 "Frame 0x%lx needs to incorporate client shape\n",
1132 frame->xwindow);
1133
1134 screen = gtk_widget_get_screen (GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
);
1135 screen_number = gdk_x11_screen_get_screen_number (screen);
1136
1137 attrs.override_redirect = True1;
1138
1139 shape_window = XCreateWindow (display,
1140 RootWindow (display, screen_number)((&((_XPrivDisplay)(display))->screens[screen_number])
->root)
,
1141 -5000, -5000,
1142 new_window_width,
1143 new_window_height,
1144 0,
1145 CopyFromParent0L,
1146 CopyFromParent0L,
1147 (Visual *)CopyFromParent0L,
1148 CWOverrideRedirect(1L<<9),
1149 &attrs);
1150
1151 /* Copy the client's shape to the temporary shape_window */
1152 meta_core_get (display, frame->xwindow,
1153 META_CORE_GET_CLIENT_XWINDOW, &client_window,
1154 META_CORE_GET_END);
1155
1156 XShapeCombineShape (display, shape_window, ShapeBounding0,
1157 fgeom.borders.total.left,
1158 fgeom.borders.total.top,
1159 client_window,
1160 ShapeBounding0,
1161 ShapeSet0);
1162
1163 /* Punch the client area out of the normal frame shape,
1164 * then union it with the shape_window's existing shape
1165 */
1166 frame_region = get_frame_region (new_window_width,
1167 new_window_height);
1168 client_region = get_client_region (&fgeom,
1169 new_window_width,
1170 new_window_height);
1171
1172 tmp_region = compositing_manager ? frame_region : window_region;
1173
1174 cairo_region_subtract (tmp_region, client_region);
1175
1176 cairo_region_destroy (client_region);
1177
1178 apply_cairo_region_to_window (display, shape_window,
1179 tmp_region, ShapeUnion1);
1180
1181 cairo_region_destroy (frame_region);
1182
1183 /* Now copy shape_window shape to the real frame */
1184 XShapeCombineShape (display, frame->xwindow, ShapeBounding0,
1185 0, 0,
1186 shape_window,
1187 ShapeBounding0,
1188 ShapeSet0);
1189
1190 XDestroyWindow (display, shape_window);
1191 }
1192 else
1193 {
1194 /* No shape on the client, so just do simple stuff */
1195
1196 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1197 "Frame 0x%lx has shaped corners\n",
1198 frame->xwindow);
1199
1200 if (!compositing_manager)
1201 apply_cairo_region_to_window (display,
1202 frame->xwindow, window_region,
1203 ShapeSet0);
1204 }
1205
1206 frame->shape_applied = TRUE(!(0));
1207
1208 cairo_region_destroy (window_region);
1209#endif /* HAVE_SHAPE */
1210}
1211
1212cairo_region_t *
1213meta_frames_get_frame_bounds (MetaFrames *frames,
1214 Window xwindow,
1215 int window_width,
1216 int window_height)
1217{
1218 MetaUIFrame *frame;
1219 MetaFrameGeometry fgeom;
1220
1221 frame = meta_frames_lookup_window (frames, xwindow);
1222 g_return_val_if_fail (frame != NULL, NULL)do { if ((frame != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "frame != NULL"); return
(((void*)0)); } } while (0)
;
1223
1224 meta_frames_calc_geometry (frames, frame, &fgeom);
1225
1226 return get_visible_region (frames,
1227 frame,
1228 &fgeom,
1229 window_width,
1230 window_height);
1231}
1232
1233void
1234meta_frames_move_resize_frame (MetaFrames *frames,
1235 Window xwindow,
1236 int x,
1237 int y,
1238 int width,
1239 int height)
1240{
1241 MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
1242 int old_width, old_height;
1243 gint scale;
1244
1245 old_width = gdk_window_get_width (frame->window);
1246 old_height = gdk_window_get_height (frame->window);
1247
1248 scale = gdk_window_get_scale_factor (frame->window);
1249
1250 gdk_window_move_resize (frame->window, x / scale, y / scale, width / scale, height / scale);
1251
1252 if (old_width != width || old_height != height)
1253 invalidate_whole_window (frames, frame);
1254}
1255
1256void
1257meta_frames_queue_draw (MetaFrames *frames,
1258 Window xwindow)
1259{
1260 MetaUIFrame *frame;
1261
1262 frame = meta_frames_lookup_window (frames, xwindow);
1263
1264 invalidate_whole_window (frames, frame);
1265}
1266
1267void
1268meta_frames_set_title (MetaFrames *frames,
1269 Window xwindow,
1270 const char *title)
1271{
1272 MetaUIFrame *frame;
1273
1274 frame = meta_frames_lookup_window (frames, xwindow);
1275
1276 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 1276, ((const char*) (__func__)), "frame"); } while (0)
;
1277
1278 g_free (frame->title);
1279 frame->title = g_strdup (title)g_strdup_inline (title);
1280
1281 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
1282
1283 invalidate_whole_window (frames, frame);
1284}
1285
1286void
1287meta_frames_update_frame_style (MetaFrames *frames,
1288 Window xwindow)
1289{
1290 MetaUIFrame *frame;
1291
1292 frame = meta_frames_lookup_window (frames, xwindow);
1293
1294 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 1294, ((const char*) (__func__)), "frame"); } while (0)
;
1295
1296 meta_frames_attach_style (frames, frame);
1297 invalidate_whole_window (frames, frame);
1298}
1299
1300void
1301meta_frames_repaint_frame (MetaFrames *frames,
1302 Window xwindow)
1303{
1304 MetaUIFrame *frame;
1305
1306 frame = meta_frames_lookup_window (frames, xwindow);
1307
1308 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 1308, ((const char*) (__func__)), "frame"); } while (0)
;
1309
1310 /* repaint everything, so the other frame don't
1311 * lag behind if they are exposed
1312 */
1313 gdk_window_process_all_updates ();
1314}
1315
1316static void
1317show_tip_now (MetaFrames *frames)
1318{
1319 const char *tiptext;
1320 MetaUIFrame *frame;
1321 int x, y, root_x, root_y;
1322 Window root, child;
1323 guint mask;
1324 MetaFrameControl control;
1325
1326 frame = frames->last_motion_frame;
1327 if (frame == NULL((void*)0))
1328 return;
1329
1330 XQueryPointer (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1331 frame->xwindow,
1332 &root, &child,
1333 &root_x, &root_y,
1334 &x, &y,
1335 &mask);
1336
1337 control = get_control (frames, frame, x, y);
1338
1339 tiptext = NULL((void*)0);
1340 switch (control)
1341 {
1342 case META_FRAME_CONTROL_TITLE:
1343 break;
1344 case META_FRAME_CONTROL_DELETE:
1345 tiptext = _("Close Window")((char *) g_dgettext ("marco", "Close Window"));
1346 break;
1347 case META_FRAME_CONTROL_MENU:
1348 tiptext = _("Window Menu")((char *) g_dgettext ("marco", "Window Menu"));
1349 break;
1350 case META_FRAME_CONTROL_APPMENU:
1351 tiptext = _("Window App Menu")((char *) g_dgettext ("marco", "Window App Menu"));
1352 break;
1353 case META_FRAME_CONTROL_MINIMIZE:
1354 tiptext = _("Minimize Window")((char *) g_dgettext ("marco", "Minimize Window"));
1355 break;
1356 case META_FRAME_CONTROL_MAXIMIZE:
1357 tiptext = _("Maximize Window")((char *) g_dgettext ("marco", "Maximize Window"));
1358 break;
1359 case META_FRAME_CONTROL_UNMAXIMIZE:
1360 tiptext = _("Restore Window")((char *) g_dgettext ("marco", "Restore Window"));
1361 break;
1362 case META_FRAME_CONTROL_SHADE:
1363 tiptext = _("Roll Up Window")((char *) g_dgettext ("marco", "Roll Up Window"));
1364 break;
1365 case META_FRAME_CONTROL_UNSHADE:
1366 tiptext = _("Unroll Window")((char *) g_dgettext ("marco", "Unroll Window"));
1367 break;
1368 case META_FRAME_CONTROL_ABOVE:
1369 tiptext = _("Keep Window On Top")((char *) g_dgettext ("marco", "Keep Window On Top"));
1370 break;
1371 case META_FRAME_CONTROL_UNABOVE:
1372 tiptext = _("Remove Window From Top")((char *) g_dgettext ("marco", "Remove Window From Top"));
1373 break;
1374 case META_FRAME_CONTROL_STICK:
1375 tiptext = _("Always On Visible Workspace")((char *) g_dgettext ("marco", "Always On Visible Workspace")
)
;
1376 break;
1377 case META_FRAME_CONTROL_UNSTICK:
1378 tiptext = _("Put Window On Only One Workspace")((char *) g_dgettext ("marco", "Put Window On Only One Workspace"
))
;
1379 break;
1380 case META_FRAME_CONTROL_RESIZE_SE:
1381 break;
1382 case META_FRAME_CONTROL_RESIZE_S:
1383 break;
1384 case META_FRAME_CONTROL_RESIZE_SW:
1385 break;
1386 case META_FRAME_CONTROL_RESIZE_N:
1387 break;
1388 case META_FRAME_CONTROL_RESIZE_NE:
1389 break;
1390 case META_FRAME_CONTROL_RESIZE_NW:
1391 break;
1392 case META_FRAME_CONTROL_RESIZE_W:
1393 break;
1394 case META_FRAME_CONTROL_RESIZE_E:
1395 break;
1396 case META_FRAME_CONTROL_NONE:
1397 break;
1398 case META_FRAME_CONTROL_CLIENT_AREA:
1399 break;
1400 }
1401
1402 if (tiptext)
1403 {
1404 MetaFrameGeometry fgeom;
1405 GdkRectangle *rect;
1406 int dx, dy, scale;
1407
1408 meta_frames_calc_geometry (frames, frame, &fgeom);
1409
1410 rect = control_rect (control, &fgeom);
1411 scale = gdk_window_get_scale_factor (frame->window);
1412
1413 /* get conversion delta for root-to-frame coords */
1414 dx = (root_x - x) / scale;
1415 dy = (root_y - y) / scale;
1416
1417 /* Align the tooltip to the button right end if RTL */
1418 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1419 dx += rect->width;
1420
1421 meta_fixed_tip_show (rect->x + dx,
1422 rect->y + rect->height + 2 + dy,
1423 tiptext);
1424 }
1425}
1426
1427static gboolean
1428tip_timeout_func (gpointer data)
1429{
1430 MetaFrames *frames;
1431
1432 frames = data;
1433
1434 show_tip_now (frames);
1435
1436 frames->tooltip_timeout = 0;
1437
1438 return FALSE(0);
1439}
1440
1441#define TIP_DELAY450 450
1442static void
1443queue_tip (MetaFrames *frames)
1444{
1445 clear_tip (frames);
1446
1447 frames->tooltip_timeout = g_timeout_add (TIP_DELAY450,
1448 tip_timeout_func,
1449 frames);
1450}
1451
1452static void
1453clear_tip (MetaFrames *frames)
1454{
1455 if (frames->tooltip_timeout)
1456 {
1457 g_source_remove (frames->tooltip_timeout);
1458 frames->tooltip_timeout = 0;
1459 }
1460 meta_fixed_tip_hide ();
1461}
1462
1463static void
1464redraw_control (MetaFrames *frames,
1465 MetaUIFrame *frame,
1466 MetaFrameControl control)
1467{
1468 MetaFrameGeometry fgeom;
1469 GdkRectangle *rect;
1470
1471 meta_frames_calc_geometry (frames, frame, &fgeom);
1472
1473 rect = control_rect (control, &fgeom);
1474
1475 gdk_window_invalidate_rect (frame->window, rect, FALSE(0));
1476 invalidate_cache (frames, frame);
1477}
1478
1479static gboolean
1480meta_frame_titlebar_event (MetaUIFrame *frame,
1481 GdkEventButton *event,
1482 int action)
1483{
1484 MetaFrameFlags flags;
1485
1486 switch (action)
1487 {
1488 case META_ACTION_TITLEBAR_TOGGLE_SHADE:
1489 {
1490 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1491 META_CORE_GET_FRAME_FLAGS, &flags,
1492 META_CORE_GET_END);
1493
1494 if (flags & META_FRAME_ALLOWS_SHADE)
1495 {
1496 if (flags & META_FRAME_SHADED)
1497 meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1498 frame->xwindow,
1499 event->time);
1500 else
1501 meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1502 frame->xwindow,
1503 event->time);
1504 }
1505 }
1506 break;
1507
1508 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE:
1509 {
1510 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1511 META_CORE_GET_FRAME_FLAGS, &flags,
1512 META_CORE_GET_END);
1513
1514 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1515 {
1516 meta_core_toggle_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1517 }
1518 }
1519 break;
1520
1521 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY:
1522 {
1523 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1524 META_CORE_GET_FRAME_FLAGS, &flags,
1525 META_CORE_GET_END);
1526
1527 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1528 {
1529 meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1530 }
1531 }
1532 break;
1533
1534 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY:
1535 {
1536 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1537 META_CORE_GET_FRAME_FLAGS, &flags,
1538 META_CORE_GET_END);
1539
1540 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1541 {
1542 meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1543 }
1544 }
1545 break;
1546
1547 case META_ACTION_TITLEBAR_MINIMIZE:
1548 {
1549 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1550 META_CORE_GET_FRAME_FLAGS, &flags,
1551 META_CORE_GET_END);
1552
1553 if (flags & META_FRAME_ALLOWS_MINIMIZE)
1554 {
1555 meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1556 }
1557 }
1558 break;
1559
1560 case META_ACTION_TITLEBAR_NONE:
1561 /* Yaay, a sane user that doesn't use that other weird crap! */
1562 break;
1563
1564 case META_ACTION_TITLEBAR_LOWER:
1565 meta_core_user_lower_and_unfocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1566 frame->xwindow,
1567 event->time);
1568 break;
1569
1570 case META_ACTION_TITLEBAR_MENU:
1571 meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1572 frame->xwindow,
1573 event->x_root,
1574 event->y_root,
1575 event->button,
1576 event->time);
1577 break;
1578
1579 case META_ACTION_TITLEBAR_LAST:
1580 break;
1581 }
1582
1583 return TRUE(!(0));
1584}
1585
1586static gboolean
1587meta_frame_double_click_event (MetaUIFrame *frame,
1588 GdkEventButton *event)
1589{
1590 int action = meta_prefs_get_action_double_click_titlebar ();
1591
1592 return meta_frame_titlebar_event (frame, event, action);
1593}
1594
1595static gboolean
1596meta_frame_middle_click_event (MetaUIFrame *frame,
1597 GdkEventButton *event)
1598{
1599 int action = meta_prefs_get_action_middle_click_titlebar();
1600
1601 return meta_frame_titlebar_event (frame, event, action);
1602}
1603
1604static gboolean
1605meta_frame_right_click_event(MetaUIFrame *frame,
1606 GdkEventButton *event)
1607{
1608 int action = meta_prefs_get_action_right_click_titlebar();
1609
1610 return meta_frame_titlebar_event (frame, event, action);
1611}
1612
1613static gboolean
1614meta_frames_button_press_event (GtkWidget *widget,
1615 GdkEventButton *event)
1616{
1617 MetaUIFrame *frame;
1618 MetaFrames *frames;
1619 MetaFrameControl control;
1620
1621 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
1622
1623 /* Remember that the display may have already done something with this event.
1624 * If so there's probably a GrabOp in effect.
1625 */
1626
1627 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
1628 if (frame == NULL((void*)0))
1629 return FALSE(0);
1630
1631 clear_tip (frames);
1632
1633 control = get_control (frames, frame, event->x, event->y);
1634
1635 /* focus on click, even if click was on client area */
1636 if (event->button == 1 &&
1637 !(control == META_FRAME_CONTROL_MINIMIZE ||
1638 control == META_FRAME_CONTROL_DELETE ||
1639 control == META_FRAME_CONTROL_MAXIMIZE))
1640 {
1641 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1642 "Focusing window with frame 0x%lx due to button 1 press\n",
1643 frame->xwindow);
1644 meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1645 frame->xwindow,
1646 event->time);
1647 }
1648
1649 /* don't do the rest of this if on client area */
1650 if (control == META_FRAME_CONTROL_CLIENT_AREA)
1651 return FALSE(0); /* not on the frame, just passed through from client */
1652
1653 /* We want to shade even if we have a GrabOp, since we'll have a move grab
1654 * if we double click the titlebar.
1655 */
1656 if (control == META_FRAME_CONTROL_TITLE &&
1657 event->button == 1 &&
1658 event->type == GDK_2BUTTON_PRESS)
1659 {
1660 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1661 return meta_frame_double_click_event (frame, event);
1662 }
1663
1664 if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))) !=
1665 META_GRAB_OP_NONE)
1666 return FALSE(0); /* already up to something */
1667
1668 if ((event->button == 1 &&
1669 (control == META_FRAME_CONTROL_MINIMIZE ||
1670 control == META_FRAME_CONTROL_DELETE ||
1671 control == META_FRAME_CONTROL_SHADE ||
1672 control == META_FRAME_CONTROL_UNSHADE ||
1673 control == META_FRAME_CONTROL_ABOVE ||
1674 control == META_FRAME_CONTROL_UNABOVE ||
1675 control == META_FRAME_CONTROL_STICK ||
1676 control == META_FRAME_CONTROL_UNSTICK ||
1677 control == META_FRAME_CONTROL_MENU)) ||
1678 (control == META_FRAME_CONTROL_MAXIMIZE ||
1679 control == META_FRAME_CONTROL_UNMAXIMIZE))
1680 {
1681 MetaGrabOp op;
1682
1683 switch (control)
1684 {
1685 case META_FRAME_CONTROL_MINIMIZE:
1686 op = META_GRAB_OP_CLICKING_MINIMIZE;
1687 break;
1688 case META_FRAME_CONTROL_MAXIMIZE:
1689 op = META_GRAB_OP_CLICKING_MAXIMIZE + event->button - 1;
1690 op = op > META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL ? META_GRAB_OP_CLICKING_MAXIMIZE : op;
1691 break;
1692 case META_FRAME_CONTROL_UNMAXIMIZE:
1693 op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
1694 break;
1695 case META_FRAME_CONTROL_DELETE:
1696 op = META_GRAB_OP_CLICKING_DELETE;
1697 break;
1698 case META_FRAME_CONTROL_MENU:
1699 op = META_GRAB_OP_CLICKING_MENU;
1700 break;
1701 case META_FRAME_CONTROL_APPMENU:
1702 op = META_GRAB_OP_CLICKING_APPMENU;
This statement is never executed
1703 break;
1704 case META_FRAME_CONTROL_SHADE:
1705 op = META_GRAB_OP_CLICKING_SHADE;
1706 break;
1707 case META_FRAME_CONTROL_UNSHADE:
1708 op = META_GRAB_OP_CLICKING_UNSHADE;
1709 break;
1710 case META_FRAME_CONTROL_ABOVE:
1711 op = META_GRAB_OP_CLICKING_ABOVE;
1712 break;
1713 case META_FRAME_CONTROL_UNABOVE:
1714 op = META_GRAB_OP_CLICKING_UNABOVE;
1715 break;
1716 case META_FRAME_CONTROL_STICK:
1717 op = META_GRAB_OP_CLICKING_STICK;
1718 break;
1719 case META_FRAME_CONTROL_UNSTICK:
1720 op = META_GRAB_OP_CLICKING_UNSTICK;
1721 break;
1722 default:
1723 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/frames.c", 1723, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1724 op = META_GRAB_OP_NONE;
1725 }
1726
1727 meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1728 frame->xwindow,
1729 op,
1730 TRUE(!(0)),
1731 TRUE(!(0)),
1732 event->button,
1733 0,
1734 event->time,
1735 event->x_root,
1736 event->y_root);
1737
1738 frame->prelit_control = control;
1739 redraw_control (frames, frame, control);
1740
1741 if (op == META_GRAB_OP_CLICKING_MENU)
1742 {
1743 MetaFrameGeometry fgeom;
1744 GdkRectangle *rect;
1745 int dx, dy;
1746
1747 meta_frames_calc_geometry (frames, frame, &fgeom);
1748
1749 rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
1750
1751 /* get delta to convert to root coords */
1752 dx = event->x_root - event->x;
1753 dy = event->y_root - event->y;
1754
1755 /* Align to the right end of the menu rectangle if RTL */
1756 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1757 dx += rect->width;
1758
1759 meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1760 frame->xwindow,
1761 rect->x + dx,
1762 rect->y + rect->height + dy,
1763 event->button,
1764 event->time);
1765 }
1766 }
1767 else if (event->button == 1 &&
1768 (control == META_FRAME_CONTROL_RESIZE_SE ||
1769 control == META_FRAME_CONTROL_RESIZE_S ||
1770 control == META_FRAME_CONTROL_RESIZE_SW ||
1771 control == META_FRAME_CONTROL_RESIZE_NE ||
1772 control == META_FRAME_CONTROL_RESIZE_N ||
1773 control == META_FRAME_CONTROL_RESIZE_NW ||
1774 control == META_FRAME_CONTROL_RESIZE_E ||
1775 control == META_FRAME_CONTROL_RESIZE_W))
1776 {
1777 MetaGrabOp op;
1778
1779 op = META_GRAB_OP_NONE;
1780
1781 switch (control)
1782 {
1783 case META_FRAME_CONTROL_RESIZE_SE:
1784 op = META_GRAB_OP_RESIZING_SE;
1785 break;
1786 case META_FRAME_CONTROL_RESIZE_S:
1787 op = META_GRAB_OP_RESIZING_S;
1788 break;
1789 case META_FRAME_CONTROL_RESIZE_SW:
1790 op = META_GRAB_OP_RESIZING_SW;
1791 break;
1792 case META_FRAME_CONTROL_RESIZE_NE:
1793 op = META_GRAB_OP_RESIZING_NE;
1794 break;
1795 case META_FRAME_CONTROL_RESIZE_N:
1796 op = META_GRAB_OP_RESIZING_N;
1797 break;
1798 case META_FRAME_CONTROL_RESIZE_NW:
1799 op = META_GRAB_OP_RESIZING_NW;
1800 break;
1801 case META_FRAME_CONTROL_RESIZE_E:
1802 op = META_GRAB_OP_RESIZING_E;
1803 break;
1804 case META_FRAME_CONTROL_RESIZE_W:
1805 op = META_GRAB_OP_RESIZING_W;
1806 break;
1807 default:
1808 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/frames.c", 1808, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1809 break;
1810 }
1811
1812 meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1813 frame->xwindow,
1814 op,
1815 TRUE(!(0)),
1816 TRUE(!(0)),
1817 event->button,
1818 0,
1819 event->time,
1820 event->x_root,
1821 event->y_root);
1822 }
1823 else if (control == META_FRAME_CONTROL_TITLE &&
1824 event->button == 1)
1825 {
1826 MetaFrameFlags flags;
1827
1828 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1829 META_CORE_GET_FRAME_FLAGS, &flags,
1830 META_CORE_GET_END);
1831
1832 if (flags & META_FRAME_ALLOWS_MOVE)
1833 {
1834 meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1835 frame->xwindow,
1836 META_GRAB_OP_MOVING,
1837 TRUE(!(0)),
1838 TRUE(!(0)),
1839 event->button,
1840 0,
1841 event->time,
1842 event->x_root,
1843 event->y_root);
1844 }
1845 }
1846 else if (event->button == 2)
1847 {
1848 return meta_frame_middle_click_event (frame, event);
1849 }
1850 else if (event->button == 3)
1851 {
1852 return meta_frame_right_click_event (frame, event);
1853 }
1854
1855 return TRUE(!(0));
1856}
1857
1858void
1859meta_frames_notify_menu_hide (MetaFrames *frames)
1860{
1861 if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))) ==
1862 META_GRAB_OP_CLICKING_MENU)
1863 {
1864 Window grab_frame;
1865
1866 grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
1867
1868 if (grab_frame != None0L)
1869 {
1870 MetaUIFrame *frame;
1871
1872 frame = meta_frames_lookup_window (frames, grab_frame);
1873
1874 if (frame)
1875 {
1876 redraw_control (frames, frame,
1877 META_FRAME_CONTROL_MENU);
1878 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), CurrentTime0L);
1879 }
1880 }
1881 }
1882}
1883
1884static gboolean
1885meta_frames_button_release_event (GtkWidget *widget,
1886 GdkEventButton *event)
1887{
1888 MetaUIFrame *frame;
1889 MetaFrames *frames;
1890 MetaGrabOp op;
1891
1892 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
1893
1894 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
1895 if (frame == NULL((void*)0))
1896 return FALSE(0);
1897
1898 clear_tip (frames);
1899
1900 op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
1901
1902 if (op == META_GRAB_OP_NONE)
1903 return FALSE(0);
1904
1905 /* We only handle the releases we handled the presses for (things
1906 * involving frame controls). Window ops that don't require a
1907 * frame are handled in the Xlib part of the code, display.c/window.c
1908 */
1909 if (frame->xwindow == meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))) &&
1910 ((int) event->button) == meta_core_get_grab_button (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))))
1911 {
1912 MetaFrameControl control;
1913
1914 control = get_control (frames, frame, event->x, event->y);
1915
1916 switch (op)
1917 {
1918 case META_GRAB_OP_CLICKING_MINIMIZE:
1919 if (control == META_FRAME_CONTROL_MINIMIZE)
1920 meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1921
1922 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1923 break;
1924
1925 case META_GRAB_OP_CLICKING_MAXIMIZE:
1926 case META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL:
1927 case META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL:
1928 if (control == META_FRAME_CONTROL_MAXIMIZE)
1929 {
1930 /* Focus the window on the maximize */
1931 meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1932 frame->xwindow,
1933 event->time);
1934
1935 if (op == META_GRAB_OP_CLICKING_MAXIMIZE)
1936 meta_core_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1937 if (op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL)
1938 meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1939 if (op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL)
1940 meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1941 }
1942 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1943 break;
1944
1945 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
1946 case META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL:
1947 case META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL:
1948 if (control == META_FRAME_CONTROL_UNMAXIMIZE) {
1949 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE)
1950 meta_core_unmaximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1951 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL)
1952 meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1953 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)
1954 meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1955 }
1956
1957 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1958 break;
1959
1960 case META_GRAB_OP_CLICKING_DELETE:
1961 if (control == META_FRAME_CONTROL_DELETE)
1962 meta_core_delete (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow, event->time);
1963
1964 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1965 break;
1966
1967 case META_GRAB_OP_CLICKING_MENU:
1968 case META_GRAB_OP_CLICKING_APPMENU:
1969 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1970 break;
1971
1972 case META_GRAB_OP_CLICKING_SHADE:
1973 if (control == META_FRAME_CONTROL_SHADE)
1974 meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow, event->time);
1975
1976 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1977 break;
1978
1979 case META_GRAB_OP_CLICKING_UNSHADE:
1980 if (control == META_FRAME_CONTROL_UNSHADE)
1981 meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow, event->time);
1982
1983 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1984 break;
1985
1986 case META_GRAB_OP_CLICKING_ABOVE:
1987 if (control == META_FRAME_CONTROL_ABOVE)
1988 meta_core_make_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1989
1990 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1991 break;
1992
1993 case META_GRAB_OP_CLICKING_UNABOVE:
1994 if (control == META_FRAME_CONTROL_UNABOVE)
1995 meta_core_unmake_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1996
1997 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1998 break;
1999
2000 case META_GRAB_OP_CLICKING_STICK:
2001 if (control == META_FRAME_CONTROL_STICK)
2002 meta_core_stick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
2003
2004 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
2005 break;
2006
2007 case META_GRAB_OP_CLICKING_UNSTICK:
2008 if (control == META_FRAME_CONTROL_UNSTICK)
2009 meta_core_unstick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
2010
2011 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
2012 break;
2013
2014 default:
2015 break;
2016 }
2017
2018 /* Update the prelit control regardless of what button the mouse
2019 * was released over; needed so that the new button can become
2020 * prelit so to let the user know that it can now be pressed.
2021 * :)
2022 */
2023 meta_frames_update_prelit_control (frames, frame, control);
2024 }
2025
2026 return TRUE(!(0));
2027}
2028
2029static void
2030meta_frames_update_prelit_control (MetaFrames *frames,
2031 MetaUIFrame *frame,
2032 MetaFrameControl control)
2033{
2034 MetaFrameControl old_control;
2035 MetaCursor cursor;
2036
2037 meta_verbosemeta_verbose_real ("Updating prelit control from %u to %u\n",
2038 frame->prelit_control, control);
2039
2040 cursor = META_CURSOR_DEFAULT;
2041
2042 switch (control)
2043 {
2044 case META_FRAME_CONTROL_CLIENT_AREA:
2045 break;
2046 case META_FRAME_CONTROL_NONE:
2047 break;
2048 case META_FRAME_CONTROL_TITLE:
2049 break;
2050 case META_FRAME_CONTROL_DELETE:
2051 break;
2052 case META_FRAME_CONTROL_MENU:
2053 break;
2054 case META_FRAME_CONTROL_APPMENU:
2055 break;
2056 case META_FRAME_CONTROL_MINIMIZE:
2057 break;
2058 case META_FRAME_CONTROL_MAXIMIZE:
2059 break;
2060 case META_FRAME_CONTROL_UNMAXIMIZE:
2061 break;
2062 case META_FRAME_CONTROL_SHADE:
2063 break;
2064 case META_FRAME_CONTROL_UNSHADE:
2065 break;
2066 case META_FRAME_CONTROL_ABOVE:
2067 break;
2068 case META_FRAME_CONTROL_UNABOVE:
2069 break;
2070 case META_FRAME_CONTROL_STICK:
2071 break;
2072 case META_FRAME_CONTROL_UNSTICK:
2073 break;
2074 case META_FRAME_CONTROL_RESIZE_SE:
2075 cursor = META_CURSOR_SE_RESIZE;
2076 break;
2077 case META_FRAME_CONTROL_RESIZE_S:
2078 cursor = META_CURSOR_SOUTH_RESIZE;
2079 break;
2080 case META_FRAME_CONTROL_RESIZE_SW:
2081 cursor = META_CURSOR_SW_RESIZE;
2082 break;
2083 case META_FRAME_CONTROL_RESIZE_N:
2084 cursor = META_CURSOR_NORTH_RESIZE;
2085 break;
2086 case META_FRAME_CONTROL_RESIZE_NE:
2087 cursor = META_CURSOR_NE_RESIZE;
2088 break;
2089 case META_FRAME_CONTROL_RESIZE_NW:
2090 cursor = META_CURSOR_NW_RESIZE;
2091 break;
2092 case META_FRAME_CONTROL_RESIZE_W:
2093 cursor = META_CURSOR_WEST_RESIZE;
2094 break;
2095 case META_FRAME_CONTROL_RESIZE_E:
2096 cursor = META_CURSOR_EAST_RESIZE;
2097 break;
2098 }
2099
2100 /* set/unset the prelight cursor */
2101 meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
2102 frame->xwindow,
2103 cursor);
2104
2105 switch (control)
2106 {
2107 case META_FRAME_CONTROL_MENU:
2108 case META_FRAME_CONTROL_APPMENU:
2109 case META_FRAME_CONTROL_MINIMIZE:
2110 case META_FRAME_CONTROL_MAXIMIZE:
2111 case META_FRAME_CONTROL_DELETE:
2112 case META_FRAME_CONTROL_SHADE:
2113 case META_FRAME_CONTROL_UNSHADE:
2114 case META_FRAME_CONTROL_ABOVE:
2115 case META_FRAME_CONTROL_UNABOVE:
2116 case META_FRAME_CONTROL_STICK:
2117 case META_FRAME_CONTROL_UNSTICK:
2118 case META_FRAME_CONTROL_UNMAXIMIZE:
2119 /* leave control set */
2120 break;
2121 default:
2122 /* Only prelight buttons */
2123 control = META_FRAME_CONTROL_NONE;
2124 break;
2125 }
2126
2127 if (control == frame->prelit_control)
2128 return;
2129
2130 /* Save the old control so we can unprelight it */
2131 old_control = frame->prelit_control;
2132
2133 frame->prelit_control = control;
2134
2135 redraw_control (frames, frame, old_control);
2136 redraw_control (frames, frame, control);
2137}
2138
2139static gboolean
2140meta_frames_motion_notify_event (GtkWidget *widget,
2141 GdkEventMotion *event)
2142{
2143 MetaUIFrame *frame;
2144 MetaFrames *frames;
2145 MetaGrabOp grab_op;
2146
2147 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2148
2149 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2150 if (frame == NULL((void*)0))
2151 return FALSE(0);
2152
2153 clear_tip (frames);
2154
2155 frames->last_motion_frame = frame;
2156
2157 grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2158
2159 switch (grab_op)
2160 {
2161 case META_GRAB_OP_CLICKING_MENU:
2162 case META_GRAB_OP_CLICKING_APPMENU:
2163 case META_GRAB_OP_CLICKING_DELETE:
2164 case META_GRAB_OP_CLICKING_MINIMIZE:
2165 case META_GRAB_OP_CLICKING_MAXIMIZE:
2166 case META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL:
2167 case META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL:
2168 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
2169 case META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL:
2170 case META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL:
2171 case META_GRAB_OP_CLICKING_SHADE:
2172 case META_GRAB_OP_CLICKING_UNSHADE:
2173 case META_GRAB_OP_CLICKING_ABOVE:
2174 case META_GRAB_OP_CLICKING_UNABOVE:
2175 case META_GRAB_OP_CLICKING_STICK:
2176 case META_GRAB_OP_CLICKING_UNSTICK:
2177 {
2178 MetaFrameControl control;
2179 int x, y, scale;
2180
2181 gdk_window_get_device_position (frame->window, event->device,
2182 &x, &y, NULL((void*)0));
2183 scale = gdk_window_get_scale_factor (frame->window);
2184 x *= scale;
2185 y *= scale;
2186
2187 /* Control is set to none unless it matches
2188 * the current grab
2189 */
2190 control = get_control (frames, frame, x, y);
2191 if (! ((control == META_FRAME_CONTROL_MENU &&
2192 grab_op == META_GRAB_OP_CLICKING_MENU) ||
2193 (control == META_FRAME_CONTROL_APPMENU &&
2194 grab_op == META_GRAB_OP_CLICKING_APPMENU) ||
2195 (control == META_FRAME_CONTROL_DELETE &&
2196 grab_op == META_GRAB_OP_CLICKING_DELETE) ||
2197 (control == META_FRAME_CONTROL_MINIMIZE &&
2198 grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
2199 ((control == META_FRAME_CONTROL_MAXIMIZE ||
2200 control == META_FRAME_CONTROL_UNMAXIMIZE) &&
2201 (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
2202 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL ||
2203 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL ||
2204 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE ||
2205 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL ||
2206 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)) ||
2207 (control == META_FRAME_CONTROL_SHADE &&
2208 grab_op == META_GRAB_OP_CLICKING_SHADE) ||
2209 (control == META_FRAME_CONTROL_UNSHADE &&
2210 grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
2211 (control == META_FRAME_CONTROL_ABOVE &&
2212 grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
2213 (control == META_FRAME_CONTROL_UNABOVE &&
2214 grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
2215 (control == META_FRAME_CONTROL_STICK &&
2216 grab_op == META_GRAB_OP_CLICKING_STICK) ||
2217 (control == META_FRAME_CONTROL_UNSTICK &&
2218 grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
2219 control = META_FRAME_CONTROL_NONE;
2220
2221 /* Update prelit control and cursor */
2222 meta_frames_update_prelit_control (frames, frame, control);
2223
2224 /* No tooltip while in the process of clicking */
2225 }
2226 break;
2227 case META_GRAB_OP_NONE:
2228 {
2229 MetaFrameControl control;
2230 int x, y, scale;
2231
2232 gdk_window_get_device_position (frame->window, event->device,
2233 &x, &y, NULL((void*)0));
2234 scale = gdk_window_get_scale_factor (frame->window);
2235 x *= scale;
2236 y *= scale;
2237
2238 control = get_control (frames, frame, x, y);
2239
2240 /* Update prelit control and cursor */
2241 meta_frames_update_prelit_control (frames, frame, control);
2242
2243 queue_tip (frames);
2244 }
2245 break;
2246
2247 default:
2248 break;
2249 }
2250
2251 return TRUE(!(0));
2252}
2253
2254static gboolean
2255meta_frames_destroy_event (GtkWidget *widget,
2256 GdkEventAny *event)
2257{
2258 MetaUIFrame *frame;
2259 MetaFrames *frames;
2260
2261 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2262
2263 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2264 if (frame == NULL((void*)0))
2265 return FALSE(0);
2266
2267 return TRUE(!(0));
2268}
2269
2270/* Returns a pixmap with a piece of the windows frame painted on it.
2271*/
2272static cairo_surface_t *
2273generate_pixmap (MetaFrames *frames,
2274 MetaUIFrame *frame,
2275 cairo_rectangle_int_t *rect)
2276{
2277 cairo_surface_t *result;
2278 cairo_t *cr;
2279
2280 /* do not create a pixmap for nonexisting areas */
2281 if (rect->width <= 0 || rect->height <= 0)
2282 return NULL((void*)0);
2283
2284 result = gdk_window_create_similar_surface (frame->window,
2285 CAIRO_CONTENT_COLOR_ALPHA,
2286 rect->width, rect->height);
2287
2288 cr = cairo_create (result);
2289 cairo_translate (cr, -rect->x, -rect->y);
2290
2291 meta_frames_paint_to_drawable (frames, frame, cr);
2292
2293 cairo_destroy (cr);
2294
2295 return result;
2296}
2297
2298static void
2299populate_cache (MetaFrames *frames,
2300 MetaUIFrame *frame)
2301{
2302 MetaFrameBorders borders;
2303 int width, height;
2304 int frame_width, frame_height, screen_width, screen_height;
2305 CachedPixels *pixels;
2306 MetaFrameType frame_type;
2307 MetaFrameFlags frame_flags;
2308 int i;
2309
2310 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2311 META_CORE_GET_FRAME_WIDTH, &frame_width,
2312 META_CORE_GET_FRAME_HEIGHT, &frame_height,
2313 META_CORE_GET_SCREEN_WIDTH, &screen_width,
2314 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
2315 META_CORE_GET_CLIENT_WIDTH, &width,
2316 META_CORE_GET_CLIENT_HEIGHT, &height,
2317 META_CORE_GET_FRAME_TYPE, &frame_type,
2318 META_CORE_GET_FRAME_FLAGS, &frame_flags,
2319 META_CORE_GET_END);
2320
2321 /* don't cache extremely large windows */
2322 if (frame_width > 2 * screen_width ||
2323 frame_height > 2 * screen_height)
2324 {
2325 return;
2326 }
2327
2328 meta_theme_get_frame_borders (meta_theme_get_current (),
2329 frame_type,
2330 frame->text_height,
2331 frame_flags,
2332 &borders);
2333
2334 pixels = get_cache (frames, frame);
2335
2336 /* Setup the rectangles for the four visible frame borders. First top, then
2337 * left, right and bottom. Top and bottom extend to the invisible borders
2338 * while left and right snugly fit in between:
2339 * -----
2340 * | |
2341 * -----
2342 */
2343
2344 /* width and height refer to the client window's
2345 * size without any border added. */
2346
2347 /* top */
2348 pixels->piece[0].rect.x = 0;
2349 pixels->piece[0].rect.y = 0;
2350 pixels->piece[0].rect.width = width + borders.total.left + borders.total.right;
2351 pixels->piece[0].rect.height = borders.total.top;
2352
2353 /* left */
2354 pixels->piece[1].rect.x = 0;
2355 pixels->piece[1].rect.y = borders.total.top;
2356 pixels->piece[1].rect.width = borders.total.left;
2357 pixels->piece[1].rect.height = height;
2358
2359 /* right */
2360 pixels->piece[2].rect.x = borders.total.left + width;
2361 pixels->piece[2].rect.y = borders.total.top;
2362 pixels->piece[2].rect.width = borders.total.right;
2363 pixels->piece[2].rect.height = height;
2364
2365 /* bottom */
2366 pixels->piece[3].rect.x = 0;
2367 pixels->piece[3].rect.y = borders.total.top + height;
2368 pixels->piece[3].rect.width = width + borders.total.left + borders.total.right;
2369 pixels->piece[3].rect.height = borders.total.bottom;
2370
2371 for (i = 0; i < 4; i++)
2372 {
2373 CachedFramePiece *piece = &pixels->piece[i];
2374 if (!piece->pixmap)
2375 piece->pixmap = generate_pixmap (frames, frame, &piece->rect);
2376 }
2377
2378 if (frames->invalidate_cache_timeout_id)
2379 g_source_remove (frames->invalidate_cache_timeout_id);
2380
2381 frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
2382
2383 if (!g_list_find (frames->invalidate_frames, frame))
2384 frames->invalidate_frames =
2385 g_list_prepend (frames->invalidate_frames, frame);
2386}
2387
2388static void
2389clip_to_screen (cairo_region_t *region, MetaUIFrame *frame)
2390{
2391 GdkRectangle frame_area;
2392 GdkRectangle screen_area = { 0, 0, 0, 0 };
2393 cairo_region_t *tmp_region;
2394
2395 /* Chop off stuff outside the screen; this optimization
2396 * is crucial to handle huge client windows,
2397 * like "xterm -geometry 1000x1000"
2398 */
2399 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2400 META_CORE_GET_FRAME_X, &frame_area.x,
2401 META_CORE_GET_FRAME_Y, &frame_area.y,
2402 META_CORE_GET_FRAME_WIDTH, &frame_area.width,
2403 META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
2404 META_CORE_GET_SCREEN_WIDTH, &screen_area.width,
2405 META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
2406 META_CORE_GET_END);
2407
2408 cairo_region_translate (region, frame_area.x, frame_area.y);
2409
2410 tmp_region = cairo_region_create_rectangle (&frame_area);
2411 cairo_region_intersect (region, tmp_region);
2412 cairo_region_destroy (tmp_region);
2413
2414 cairo_region_translate (region, - frame_area.x, - frame_area.y);
2415}
2416
2417static void
2418subtract_client_area (cairo_region_t *region,
2419 MetaUIFrame *frame)
2420{
2421 cairo_rectangle_int_t area;
2422 MetaFrameFlags flags;
2423 MetaFrameType type;
2424 MetaFrameBorders borders;
2425 cairo_region_t *tmp_region;
2426 Display *display;
2427 gint scale;
2428
2429 display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
2430 scale = gdk_window_get_scale_factor (frame->window);
2431
2432 meta_core_get (display, frame->xwindow,
2433 META_CORE_GET_FRAME_FLAGS, &flags,
2434 META_CORE_GET_FRAME_TYPE, &type,
2435 META_CORE_GET_CLIENT_WIDTH, &area.width,
2436 META_CORE_GET_CLIENT_HEIGHT, &area.height,
2437 META_CORE_GET_END);
2438 meta_theme_get_frame_borders (meta_theme_get_current (),
2439 type, frame->text_height, flags,
2440 &borders);
2441
2442 area.width /= scale;
2443 area.height /= scale;
2444 area.x = borders.total.left / scale;
2445 area.y = borders.total.top / scale;
2446
2447 tmp_region = cairo_region_create_rectangle (&area);
2448 cairo_region_subtract (region, tmp_region);
2449 cairo_region_destroy (tmp_region);
2450}
2451
2452static void
2453cached_pixels_draw (CachedPixels *pixels,
2454 cairo_t *cr,
2455 cairo_region_t *region)
2456{
2457 cairo_region_t *region_piece;
2458 int i;
2459
2460 for (i = 0; i < 4; i++)
2461 {
2462 CachedFramePiece *piece;
2463 piece = &pixels->piece[i];
2464
2465 if (piece->pixmap)
2466 {
2467 cairo_set_source_surface (cr, piece->pixmap,
2468 piece->rect.x, piece->rect.y);
2469 cairo_paint (cr);
2470
2471 region_piece = cairo_region_create_rectangle (&piece->rect);
2472 cairo_region_subtract (region, region_piece);
2473 cairo_region_destroy (region_piece);
2474 }
2475 }
2476}
2477
2478static MetaUIFrame *
2479find_frame_to_draw (MetaFrames *frames,
2480 cairo_t *cr)
2481{
2482 GHashTableIter iter;
2483 MetaUIFrame *frame;
2484
2485 g_hash_table_iter_init (&iter, frames->frames);
2486 while (g_hash_table_iter_next (&iter, NULL((void*)0), (gpointer *) &frame))
2487 if (gtk_cairo_should_draw_window (cr, frame->window))
2488 return frame;
2489
2490 return NULL((void*)0);
2491}
2492
2493static gboolean
2494meta_frames_draw (GtkWidget *widget,
2495 cairo_t *cr)
2496{
2497 MetaUIFrame *frame;
2498 MetaFrames *frames;
2499 CachedPixels *pixels;
2500 cairo_region_t *region;
2501 cairo_rectangle_int_t clip;
2502 int i, n_areas;
2503
2504 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2505 gdk_cairo_get_clip_rectangle (cr, &clip);
2506
2507 frame = find_frame_to_draw (frames, cr);
2508
2509 if (frame == NULL((void*)0))
2510 return FALSE(0);
2511
2512 if (frames->expose_delay_count > 0)
2513 {
2514 /* Redraw this entire frame later */
2515 frame->expose_delayed = TRUE(!(0));
2516 return TRUE(!(0));
2517 }
2518
2519 populate_cache (frames, frame);
2520
2521 region = cairo_region_create_rectangle (&clip);
2522
2523 pixels = get_cache (frames, frame);
2524
2525 cached_pixels_draw (pixels, cr, region);
2526
2527 clip_to_screen (region, frame);
2528 subtract_client_area (region, frame);
2529
2530 n_areas = cairo_region_num_rectangles (region);
2531
2532 for (i = 0; i < n_areas; i++)
2533 {
2534 cairo_rectangle_int_t area;
2535
2536 cairo_region_get_rectangle (region, i, &area);
2537
2538 cairo_save (cr);
2539
2540 cairo_rectangle (cr, area.x, area.y, area.width, area.height);
2541 cairo_clip (cr);
2542
2543 cairo_push_group (cr);
2544
2545 meta_frames_paint_to_drawable (frames, frame, cr);
2546
2547 cairo_pop_group_to_source (cr);
2548 cairo_paint (cr);
2549
2550 cairo_restore (cr);
2551 }
2552
2553 cairo_region_destroy (region);
2554
2555 return TRUE(!(0));
2556}
2557
2558/* How far off the screen edge the window decorations should
2559 * be drawn. Used only in meta_frames_paint_to_drawable, below.
2560 */
2561#define DECORATING_BORDER100 100
2562
2563static void
2564meta_frames_paint_to_drawable (MetaFrames *frames,
2565 MetaUIFrame *frame,
2566 cairo_t *cr)
2567{
2568 MetaFrameFlags flags;
2569 MetaFrameType type;
2570 GdkPixbuf *mini_icon;
2571 GdkPixbuf *icon;
2572 int w, h, scale;
2573 MetaButtonState button_states[META_BUTTON_TYPE_LAST];
2574 Window grab_frame;
2575 int i;
2576 MetaButtonLayout button_layout;
2577 MetaGrabOp grab_op;
2578
2579 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
2580 button_states[i] = META_BUTTON_STATE_NORMAL;
2581
2582 grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2583 grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2584 if (grab_frame != frame->xwindow)
2585 grab_op = META_GRAB_OP_NONE;
2586
2587 /* Set prelight state */
2588 switch (frame->prelit_control)
2589 {
2590 case META_FRAME_CONTROL_MENU:
2591 if (grab_op == META_GRAB_OP_CLICKING_MENU)
2592 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED;
2593 else
2594 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT;
2595 break;
2596 case META_FRAME_CONTROL_APPMENU:
2597 if (grab_op == META_GRAB_OP_CLICKING_MENU)
2598 button_states[META_BUTTON_TYPE_APPMENU] = META_BUTTON_STATE_PRESSED;
2599 else
2600 button_states[META_BUTTON_TYPE_APPMENU] = META_BUTTON_STATE_PRELIGHT;
2601 break;
2602 case META_FRAME_CONTROL_MINIMIZE:
2603 if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE)
2604 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED;
2605 else
2606 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT;
2607 break;
2608 case META_FRAME_CONTROL_MAXIMIZE:
2609 if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL ||
2610 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL)
2611 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2612 else
2613 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2614 break;
2615 case META_FRAME_CONTROL_UNMAXIMIZE:
2616 if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE || grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL ||
2617 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)
2618 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2619 else
2620 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2621 break;
2622 case META_FRAME_CONTROL_SHADE:
2623 if (grab_op == META_GRAB_OP_CLICKING_SHADE)
2624 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
2625 else
2626 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
2627 break;
2628 case META_FRAME_CONTROL_UNSHADE:
2629 if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
2630 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
2631 else
2632 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
2633 break;
2634 case META_FRAME_CONTROL_ABOVE:
2635 if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
2636 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
2637 else
2638 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
2639 break;
2640 case META_FRAME_CONTROL_UNABOVE:
2641 if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
2642 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
2643 else
2644 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
2645 break;
2646 case META_FRAME_CONTROL_STICK:
2647 if (grab_op == META_GRAB_OP_CLICKING_STICK)
2648 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
2649 else
2650 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
2651 break;
2652 case META_FRAME_CONTROL_UNSTICK:
2653 if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
2654 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
2655 else
2656 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
2657 break;
2658 case META_FRAME_CONTROL_DELETE:
2659 if (grab_op == META_GRAB_OP_CLICKING_DELETE)
2660 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
2661 else
2662 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT;
2663 break;
2664 default:
2665 break;
2666 }
2667
2668 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2669 META_CORE_GET_FRAME_FLAGS, &flags,
2670 META_CORE_GET_FRAME_TYPE, &type,
2671 META_CORE_GET_MINI_ICON, &mini_icon,
2672 META_CORE_GET_ICON, &icon,
2673 META_CORE_GET_CLIENT_WIDTH, &w,
2674 META_CORE_GET_CLIENT_HEIGHT, &h,
2675 META_CORE_GET_END);
2676
2677 meta_frames_ensure_layout (frames, frame);
2678
2679 meta_prefs_get_button_layout (&button_layout);
2680
2681 scale = gdk_window_get_scale_factor (frame->window);
2682 meta_theme_draw_frame (meta_theme_get_current (),
2683 frame->style,
2684 cr,
2685 type,
2686 flags,
2687 w / scale,
2688 h / scale,
2689 frame->text_layout,
2690 frame->text_height,
2691 &button_layout,
2692 button_states,
2693 mini_icon,
2694 icon);
2695}
2696
2697static gboolean
2698meta_frames_enter_notify_event (GtkWidget *widget,
2699 GdkEventCrossing *event)
2700{
2701 MetaUIFrame *frame;
2702 MetaFrames *frames;
2703 MetaFrameControl control;
2704
2705 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2706
2707 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2708 if (frame == NULL((void*)0))
2709 return FALSE(0);
2710
2711 control = get_control (frames, frame, event->x, event->y);
2712 meta_frames_update_prelit_control (frames, frame, control);
2713
2714 return TRUE(!(0));
2715}
2716
2717static gboolean
2718meta_frames_leave_notify_event (GtkWidget *widget,
2719 GdkEventCrossing *event)
2720{
2721 MetaUIFrame *frame;
2722 MetaFrames *frames;
2723
2724 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2725
2726 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2727 if (frame == NULL((void*)0))
2728 return FALSE(0);
2729
2730 meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
2731
2732 clear_tip (frames);
2733
2734 return TRUE(!(0));
2735}
2736
2737static GdkRectangle*
2738control_rect (MetaFrameControl control,
2739 MetaFrameGeometry *fgeom)
2740{
2741 GdkRectangle *rect;
2742
2743 rect = NULL((void*)0);
2744 switch (control)
2745 {
2746 case META_FRAME_CONTROL_TITLE:
2747 rect = &fgeom->title_rect;
2748 break;
2749 case META_FRAME_CONTROL_DELETE:
2750 rect = &fgeom->close_rect.visible;
2751 break;
2752 case META_FRAME_CONTROL_MENU:
2753 rect = &fgeom->menu_rect.visible;
2754 break;
2755 case META_FRAME_CONTROL_APPMENU:
2756 rect = &fgeom->appmenu_rect.visible;
2757 break;
2758 case META_FRAME_CONTROL_MINIMIZE:
2759 rect = &fgeom->min_rect.visible;
2760 break;
2761 case META_FRAME_CONTROL_MAXIMIZE:
2762 case META_FRAME_CONTROL_UNMAXIMIZE:
2763 rect = &fgeom->max_rect.visible;
2764 break;
2765 case META_FRAME_CONTROL_SHADE:
2766 rect = &fgeom->shade_rect.visible;
2767 break;
2768 case META_FRAME_CONTROL_UNSHADE:
2769 rect = &fgeom->unshade_rect.visible;
2770 break;
2771 case META_FRAME_CONTROL_ABOVE:
2772 rect = &fgeom->above_rect.visible;
2773 break;
2774 case META_FRAME_CONTROL_UNABOVE:
2775 rect = &fgeom->unabove_rect.visible;
2776 break;
2777 case META_FRAME_CONTROL_STICK:
2778 rect = &fgeom->stick_rect.visible;
2779 break;
2780 case META_FRAME_CONTROL_UNSTICK:
2781 rect = &fgeom->unstick_rect.visible;
2782 break;
2783 case META_FRAME_CONTROL_RESIZE_SE:
2784 break;
2785 case META_FRAME_CONTROL_RESIZE_S:
2786 break;
2787 case META_FRAME_CONTROL_RESIZE_SW:
2788 break;
2789 case META_FRAME_CONTROL_RESIZE_N:
2790 break;
2791 case META_FRAME_CONTROL_RESIZE_NE:
2792 break;
2793 case META_FRAME_CONTROL_RESIZE_NW:
2794 break;
2795 case META_FRAME_CONTROL_RESIZE_W:
2796 break;
2797 case META_FRAME_CONTROL_RESIZE_E:
2798 break;
2799 case META_FRAME_CONTROL_NONE:
2800 break;
2801 case META_FRAME_CONTROL_CLIENT_AREA:
2802 break;
2803 }
2804
2805 return rect;
2806}
2807
2808#define RESIZE_EXTENDS15 15
2809#define TOP_RESIZE_HEIGHT4 4
2810static MetaFrameControl
2811get_control (MetaFrames *frames,
2812 MetaUIFrame *frame,
2813 int x, int y)
2814{
2815 MetaFrameGeometry fgeom;
2816 MetaFrameFlags flags;
2817 gboolean has_vert, has_horiz;
2818 GdkRectangle client;
2819 gint scale;
2820
2821 scale = gdk_window_get_scale_factor (frame->window);
2822 x /= scale;
2823 y /= scale;
2824
2825 meta_frames_calc_geometry (frames, frame, &fgeom);
2826 get_client_rect (&fgeom, fgeom.width, fgeom.height, &client);
2827
2828 if (POINT_IN_RECT (x, y, client)((x) >= (client).x && (x) < ((client).x + (client
).width) && (y) >= (client).y && (y) < (
(client).y + (client).height))
)
2829 return META_FRAME_CONTROL_CLIENT_AREA;
2830
2831 if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable)((x) >= (fgeom.close_rect.clickable).x && (x) <
((fgeom.close_rect.clickable).x + (fgeom.close_rect.clickable
).width) && (y) >= (fgeom.close_rect.clickable).y &&
(y) < ((fgeom.close_rect.clickable).y + (fgeom.close_rect
.clickable).height))
)
2832 return META_FRAME_CONTROL_DELETE;
2833
2834 if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable)((x) >= (fgeom.min_rect.clickable).x && (x) < (
(fgeom.min_rect.clickable).x + (fgeom.min_rect.clickable).width
) && (y) >= (fgeom.min_rect.clickable).y &&
(y) < ((fgeom.min_rect.clickable).y + (fgeom.min_rect.clickable
).height))
)
2835 return META_FRAME_CONTROL_MINIMIZE;
2836
2837 if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable)((x) >= (fgeom.menu_rect.clickable).x && (x) < (
(fgeom.menu_rect.clickable).x + (fgeom.menu_rect.clickable).width
) && (y) >= (fgeom.menu_rect.clickable).y &&
(y) < ((fgeom.menu_rect.clickable).y + (fgeom.menu_rect.clickable
).height))
)
2838 return META_FRAME_CONTROL_MENU;
2839
2840 if (POINT_IN_RECT (x, y, fgeom.appmenu_rect.clickable)((x) >= (fgeom.appmenu_rect.clickable).x && (x) <
((fgeom.appmenu_rect.clickable).x + (fgeom.appmenu_rect.clickable
).width) && (y) >= (fgeom.appmenu_rect.clickable).
y && (y) < ((fgeom.appmenu_rect.clickable).y + (fgeom
.appmenu_rect.clickable).height))
)
2841 return META_FRAME_CONTROL_APPMENU;
2842
2843 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2844 META_CORE_GET_FRAME_FLAGS, &flags,
2845 META_CORE_GET_END);
2846
2847 has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
2848 has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
2849
2850 if (POINT_IN_RECT (x, y, fgeom.title_rect)((x) >= (fgeom.title_rect).x && (x) < ((fgeom.title_rect
).x + (fgeom.title_rect).width) && (y) >= (fgeom.title_rect
).y && (y) < ((fgeom.title_rect).y + (fgeom.title_rect
).height))
)
2851 {
2852 if (has_vert && y <= TOP_RESIZE_HEIGHT4 * scale)
2853 return META_FRAME_CONTROL_RESIZE_N;
2854 else
2855 return META_FRAME_CONTROL_TITLE;
2856 }
2857
2858 if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable)((x) >= (fgeom.max_rect.clickable).x && (x) < (
(fgeom.max_rect.clickable).x + (fgeom.max_rect.clickable).width
) && (y) >= (fgeom.max_rect.clickable).y &&
(y) < ((fgeom.max_rect.clickable).y + (fgeom.max_rect.clickable
).height))
)
2859 {
2860 if (flags & META_FRAME_MAXIMIZED)
2861 return META_FRAME_CONTROL_UNMAXIMIZE;
2862 else
2863 return META_FRAME_CONTROL_MAXIMIZE;
2864 }
2865
2866 if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable)((x) >= (fgeom.shade_rect.clickable).x && (x) <
((fgeom.shade_rect.clickable).x + (fgeom.shade_rect.clickable
).width) && (y) >= (fgeom.shade_rect.clickable).y &&
(y) < ((fgeom.shade_rect.clickable).y + (fgeom.shade_rect
.clickable).height))
)
2867 {
2868 return META_FRAME_CONTROL_SHADE;
2869 }
2870
2871 if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable)((x) >= (fgeom.unshade_rect.clickable).x && (x) <
((fgeom.unshade_rect.clickable).x + (fgeom.unshade_rect.clickable
).width) && (y) >= (fgeom.unshade_rect.clickable).
y && (y) < ((fgeom.unshade_rect.clickable).y + (fgeom
.unshade_rect.clickable).height))
)
2872 {
2873 return META_FRAME_CONTROL_UNSHADE;
2874 }
2875
2876 if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable)((x) >= (fgeom.above_rect.clickable).x && (x) <
((fgeom.above_rect.clickable).x + (fgeom.above_rect.clickable
).width) && (y) >= (fgeom.above_rect.clickable).y &&
(y) < ((fgeom.above_rect.clickable).y + (fgeom.above_rect
.clickable).height))
)
2877 {
2878 return META_FRAME_CONTROL_ABOVE;
2879 }
2880
2881 if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable)((x) >= (fgeom.unabove_rect.clickable).x && (x) <
((fgeom.unabove_rect.clickable).x + (fgeom.unabove_rect.clickable
).width) && (y) >= (fgeom.unabove_rect.clickable).
y && (y) < ((fgeom.unabove_rect.clickable).y + (fgeom
.unabove_rect.clickable).height))
)
2882 {
2883 return META_FRAME_CONTROL_UNABOVE;
2884 }
2885
2886 if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable)((x) >= (fgeom.stick_rect.clickable).x && (x) <
((fgeom.stick_rect.clickable).x + (fgeom.stick_rect.clickable
).width) && (y) >= (fgeom.stick_rect.clickable).y &&
(y) < ((fgeom.stick_rect.clickable).y + (fgeom.stick_rect
.clickable).height))
)
2887 {
2888 return META_FRAME_CONTROL_STICK;
2889 }
2890
2891 if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable)((x) >= (fgeom.unstick_rect.clickable).x && (x) <
((fgeom.unstick_rect.clickable).x + (fgeom.unstick_rect.clickable
).width) && (y) >= (fgeom.unstick_rect.clickable).
y && (y) < ((fgeom.unstick_rect.clickable).y + (fgeom
.unstick_rect.clickable).height))
)
2892 {
2893 return META_FRAME_CONTROL_UNSTICK;
2894 }
2895
2896 /* South resize always has priority over north resize,
2897 * in case of overlap.
2898 */
2899
2900 if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15) &&
2901 x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2902 {
2903 if (has_vert && has_horiz)
2904 return META_FRAME_CONTROL_RESIZE_SE;
2905 else if (has_vert)
2906 return META_FRAME_CONTROL_RESIZE_S;
2907 else if (has_horiz)
2908 return META_FRAME_CONTROL_RESIZE_E;
2909 }
2910 else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15) &&
2911 x <= (fgeom.borders.total.left + RESIZE_EXTENDS15))
2912 {
2913 if (has_vert && has_horiz)
2914 return META_FRAME_CONTROL_RESIZE_SW;
2915 else if (has_vert)
2916 return META_FRAME_CONTROL_RESIZE_S;
2917 else if (has_horiz)
2918 return META_FRAME_CONTROL_RESIZE_W;
2919 }
2920 else if (y < (fgeom.borders.invisible.top + RESIZE_EXTENDS15) &&
2921 x <= (fgeom.borders.total.left + RESIZE_EXTENDS15))
2922 {
2923 if (has_vert && has_horiz)
2924 return META_FRAME_CONTROL_RESIZE_NW;
2925 else if (has_vert)
2926 return META_FRAME_CONTROL_RESIZE_N;
2927 else if (has_horiz)
2928 return META_FRAME_CONTROL_RESIZE_W;
2929 }
2930 else if (y < (fgeom.borders.invisible.top + RESIZE_EXTENDS15) &&
2931 x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2932 {
2933 if (has_vert && has_horiz)
2934 return META_FRAME_CONTROL_RESIZE_NE;
2935 else if (has_vert)
2936 return META_FRAME_CONTROL_RESIZE_N;
2937 else if (has_horiz)
2938 return META_FRAME_CONTROL_RESIZE_E;
2939 }
2940 else if (y < (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT4 * scale))
2941 {
2942 if (has_vert)
2943 return META_FRAME_CONTROL_RESIZE_N;
2944 }
2945 else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15))
2946 {
2947 if (has_vert)
2948 return META_FRAME_CONTROL_RESIZE_S;
2949 }
2950 else if (x <= fgeom.borders.total.left + RESIZE_EXTENDS15)
2951 {
2952 if (has_horiz)
2953 return META_FRAME_CONTROL_RESIZE_W;
2954 }
2955 else if (x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2956 {
2957 if (has_horiz)
2958 return META_FRAME_CONTROL_RESIZE_E;
2959 }
2960
2961 if (y >= fgeom.borders.total.top)
2962 return META_FRAME_CONTROL_NONE;
2963 else
2964 return META_FRAME_CONTROL_TITLE;
2965}
2966
2967void
2968meta_frames_push_delay_exposes (MetaFrames *frames)
2969{
2970 if (frames->expose_delay_count == 0)
2971 {
2972 /* Make sure we've repainted things */
2973 gdk_window_process_all_updates ();
2974 XFlush (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2975 }
2976
2977 frames->expose_delay_count += 1;
2978}
2979
2980static void
2981queue_pending_exposes_func (gpointer key, gpointer value, gpointer data)
2982{
2983 MetaUIFrame *frame;
2984 MetaFrames *frames;
2985
2986 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
2987 frame = value;
2988
2989 if (frame->expose_delayed)
2990 {
2991 invalidate_whole_window (frames, frame);
2992 frame->expose_delayed = FALSE(0);
2993 }
2994}
2995
2996void
2997meta_frames_pop_delay_exposes (MetaFrames *frames)
2998{
2999 g_return_if_fail (frames->expose_delay_count > 0)do { if ((frames->expose_delay_count > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "frames->expose_delay_count > 0"
); return; } } while (0)
;
3000
3001 frames->expose_delay_count -= 1;
3002
3003 if (frames->expose_delay_count == 0)
3004 {
3005 g_hash_table_foreach (frames->frames,
3006 queue_pending_exposes_func,
3007 frames);
3008 }
3009}
3010
3011static void
3012invalidate_whole_window (MetaFrames *frames,
3013 MetaUIFrame *frame)
3014{
3015 gdk_window_invalidate_rect (frame->window, NULL((void*)0), FALSE(0));
3016 invalidate_cache (frames, frame);
3017}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-29575a.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-29575a.html new file mode 100644 index 00000000..650e00cf --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-29575a.html @@ -0,0 +1,1346 @@ + + + +core/main.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/main.c
Warning:line 408, column 18
Using a fixed address is not portable because that address will probably not be valid in all environments or platforms
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name main.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/main.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco main() */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 * Copyright (C) 2006 Elijah Newren
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25/**
26 * \file
27 * Program startup.
28 * Functions which parse the command-line arguments, create the display,
29 * kick everything off and then close down Marco when it's time to go.
30 */
31
32/**
33 * \mainpage
34 * Marco - a boring window manager for the adult in you
35 *
36 * Many window managers are like Marshmallow Froot Loops; Marco
37 * is like Cheerios.
38 *
39 * The best way to get a handle on how the whole system fits together
40 * is discussed in doc/code-overview.txt; if you're looking for functions
41 * to investigate, read main(), meta_display_open(), and event_callback().
42 */
43
44#define _GNU_SOURCE
45#define _XOPEN_SOURCE700 /* for putenv() and some signal-related functions */
46
47#include <config.h>
48#include <glib/gi18n-lib.h>
49
50#include "main.h"
51#include "util.h"
52#include "display-private.h"
53#include "errors.h"
54#include "keybindings.h"
55#include "ui.h"
56#include "session.h"
57#include "prefs.h"
58#include "core.h"
59
60#include <glib-object.h>
61#include <glib/gprintf.h>
62
63#include <stdlib.h>
64#include <sys/types.h>
65#include <sys/wait.h>
66#include <stdio.h>
67#include <string.h>
68#include <signal.h>
69#include <unistd.h>
70#include <errno(*__errno_location ()).h>
71#include <fcntl.h>
72#include <locale.h>
73#include <time.h>
74#include <unistd.h>
75
76/**
77 * The exit code we'll return to our parent process when we eventually die.
78 */
79static MetaExitCode meta_exit_code = META_EXIT_SUCCESS;
80
81/**
82 * Handle on the main loop, so that we have an easy way of shutting Marco
83 * down.
84 */
85static GMainLoop *meta_main_loop = NULL((void*)0);
86
87/**
88 * If set, Marco will spawn an identical copy of itself immediately
89 * before quitting.
90 */
91static gboolean meta_restart_after_quit = FALSE(0);
92
93static void prefs_changed_callback (MetaPreference pref,
94 gpointer data);
95
96/**
97 * Prints log messages. If Marco was compiled with backtrace support,
98 * also prints a backtrace (see meta_print_backtrace()).
99 *
100 * \param log_domain the domain the error occurred in (we ignore this)
101 * \param log_level the log level so that we can filter out less
102 * important messages
103 * \param message the message to log
104 * \param user_data arbitrary data (we ignore this)
105 */
106static void
107log_handler (const gchar *log_domain,
108 GLogLevelFlags log_level,
109 const gchar *message,
110 gpointer user_data)
111{
112 meta_warning ("Log level %d: %s\n", log_level, message);
113 meta_print_backtrace ();
114}
115
116/**
117 * Prints a list of which configure script options were used to
118 * build this copy of Marco. This is actually always called
119 * on startup, but it's all no-op unless we're in verbose mode
120 * (see meta_set_verbose).
121 */
122static void
123meta_print_compilation_info (void)
124{
125#ifdef HAVE_SHAPE
126 meta_verbosemeta_verbose_real ("Compiled with shape extension\n");
127#else
128 meta_verbosemeta_verbose_real ("Compiled without shape extension\n");
129#endif
130#ifdef HAVE_XINERAMA
131 meta_topicmeta_topic_real (META_DEBUG_XINERAMA, "Compiled with Xinerama extension\n");
132#else
133 meta_topicmeta_topic_real (META_DEBUG_XINERAMA, "Compiled without Xinerama extension\n");
134#endif
135#ifdef HAVE_XFREE_XINERAMA
136 meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (using XFree86 Xinerama)\n");
137#else
138 meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (not using XFree86 Xinerama)\n");
139#endif
140#ifdef HAVE_SOLARIS_XINERAMA
141 meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (using Solaris Xinerama)\n");
142#else
143 meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (not using Solaris Xinerama)\n");
144#endif
145#ifdef HAVE_XSYNC
146 meta_verbosemeta_verbose_real ("Compiled with sync extension\n");
147#else
148 meta_verbosemeta_verbose_real ("Compiled without sync extension\n");
149#endif
150#ifdef HAVE_RANDR
151 meta_verbosemeta_verbose_real ("Compiled with randr extension\n");
152#else
153 meta_verbosemeta_verbose_real ("Compiled without randr extension\n");
154#endif
155#ifdef HAVE_STARTUP_NOTIFICATION
156 meta_verbosemeta_verbose_real ("Compiled with startup notification\n");
157#else
158 meta_verbosemeta_verbose_real ("Compiled without startup notification\n");
159#endif
160#ifdef HAVE_COMPOSITE_EXTENSIONS1
161 meta_verbosemeta_verbose_real ("Compiled with composite extensions\n");
162#else
163 meta_verbosemeta_verbose_real ("Compiled without composite extensions\n");
164#endif
165}
166
167/**
168 * Prints the version number, the current timestamp (not the
169 * build date), the locale, the character encoding, and a list
170 * of configure script options that were used to build this
171 * copy of Marco. This is actually always called
172 * on startup, but it's all no-op unless we're in verbose mode
173 * (see meta_set_verbose).
174 */
175static void
176meta_print_self_identity (void)
177{
178 char buf[256];
179 GDate d;
180 const char *charset;
181
182 /* Version and current date. */
183 g_date_clear (&d, 1);
184 g_date_set_time_t (&d, time (NULL((void*)0)));
185 g_date_strftime (buf, sizeof (buf), "%x", &d);
186 meta_verbosemeta_verbose_real ("Marco version %s running on %s\n",
187 VERSION"1.28.1", buf);
188
189 /* Locale and encoding. */
190 g_get_charset (&charset);
191 meta_verbosemeta_verbose_real ("Running in locale \"%s\" with encoding \"%s\"\n",
192 setlocale (LC_ALL6, NULL((void*)0)), charset);
193
194 /* Compilation settings. */
195 meta_print_compilation_info ();
196}
197
198/**
199 * The set of possible options that can be set on Marco's
200 * command line. This type exists so that meta_parse_options() can
201 * write to an instance of it.
202 */
203typedef struct
204{
205 gchar *save_file;
206 gchar *display_name;
207 gchar *client_id;
208 gboolean replace_wm;
209 gboolean disable_sm;
210 gboolean print_version;
211 gboolean sync;
212 gboolean composite;
213 gboolean no_composite;
214 gboolean no_force_fullscreen;
215 gboolean no_keybindings;
216} MetaArguments;
217
218#ifdef HAVE_COMPOSITE_EXTENSIONS1
219#define COMPOSITE_OPTS_FLAGS0 0
220#else /* HAVE_COMPOSITE_EXTENSIONS */
221/* No compositor, so don't show the arguments in --help */
222#define COMPOSITE_OPTS_FLAGS0 G_OPTION_FLAG_HIDDEN
223#endif /* HAVE_COMPOSITE_EXTENSIONS */
224
225/**
226 * Parses argc and argv and returns the
227 * arguments that Marco understands in meta_args.
228 *
229 * The strange call signature has to be written like it is so
230 * that g_option_context_parse() gets a chance to modify argc and
231 * argv.
232 *
233 * \param argc Pointer to the number of arguments Marco was given
234 * \param argv Pointer to the array of arguments Marco was given
235 * \param meta_args The result of parsing the arguments.
236 **/
237static void
238meta_parse_options (int *argc, char ***argv,
239 MetaArguments *meta_args)
240{
241 MetaArguments my_args = {NULL((void*)0), NULL((void*)0), NULL((void*)0),
242 FALSE(0), FALSE(0), FALSE(0), FALSE(0), FALSE(0)};
243 GOptionEntry options[] = {
244 {
245 "sm-disable", 0, 0, G_OPTION_ARG_NONE,
246 &my_args.disable_sm,
247 N_("Disable connection to session manager")("Disable connection to session manager"),
248 NULL((void*)0)
249 },
250 {
251 "replace", 0, 0, G_OPTION_ARG_NONE,
252 &my_args.replace_wm,
253 N_("Replace the running window manager with Marco")("Replace the running window manager with Marco"),
254 NULL((void*)0)
255 },
256 {
257 "sm-client-id", 0, 0, G_OPTION_ARG_STRING,
258 &my_args.client_id,
259 N_("Specify session management ID")("Specify session management ID"),
260 "ID"
261 },
262 {
263 "display", 'd', 0, G_OPTION_ARG_STRING,
264 &my_args.display_name, N_("X Display to use")("X Display to use"),
265 "DISPLAY"
266 },
267 {
268 "sm-save-file", 0, 0, G_OPTION_ARG_FILENAME,
269 &my_args.save_file,
270 N_("Initialize session from savefile")("Initialize session from savefile"),
271 "FILE"
272 },
273 {
274 "version", 'v', 0, G_OPTION_ARG_NONE,
275 &my_args.print_version,
276 N_("Print version")("Print version"),
277 NULL((void*)0)
278 },
279 {
280 "sync", 0, 0, G_OPTION_ARG_NONE,
281 &my_args.sync,
282 N_("Make X calls synchronous")("Make X calls synchronous"),
283 NULL((void*)0)
284 },
285 {
286 "composite", 'c', COMPOSITE_OPTS_FLAGS0, G_OPTION_ARG_NONE,
287 &my_args.composite,
288 N_("Turn compositing on")("Turn compositing on"),
289 NULL((void*)0)
290 },
291 {
292 "no-composite", 0, COMPOSITE_OPTS_FLAGS0, G_OPTION_ARG_NONE,
293 &my_args.no_composite,
294 N_("Turn compositing off")("Turn compositing off"),
295 NULL((void*)0)
296 },
297 {
298 "no-force-fullscreen", 0, COMPOSITE_OPTS_FLAGS0, G_OPTION_ARG_NONE,
299 &my_args.no_force_fullscreen,
300 N_("Don't make fullscreen windows that are maximized and have no decorations")("Don't make fullscreen windows that are maximized and have no decorations"
)
,
301 NULL((void*)0)
302 },
303 {
304 "no-keybindings", 0, 0, G_OPTION_ARG_NONE,
305 &my_args.no_keybindings,
306 N_("Have all keybindings disabled on startup")("Have all keybindings disabled on startup"),
307 NULL((void*)0)
308 },
309 {NULL((void*)0)}
310 };
311 GOptionContext *ctx;
312 GError *error = NULL((void*)0);
313
314 ctx = g_option_context_new (NULL((void*)0));
315 g_option_context_add_main_entries (ctx, options, "marco");
316 if (!g_option_context_parse (ctx, argc, argv, &error))
317 {
318 g_print ("marco: %s\n", error->message);
319 exit(1);
320 }
321 g_option_context_free (ctx);
322 /* Return the parsed options through the meta_args param. */
323 *meta_args = my_args;
324}
325
326/**
327 * Selects which display Marco should use. It first tries to use
328 * display_name as the display. If display_name is NULL then
329 * try to use the environment variable MARCO_DISPLAY. If that
330 * also is NULL, use the default - :0.0
331 */
332static void
333meta_select_display (gchar *display_name)
334{
335 gchar *envVar = "";
336 if (display_name)
337 envVar = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
338 else if (g_getenv ("MARCO_DISPLAY"))
339 envVar = g_strconcat ("DISPLAY=",
340 g_getenv ("MARCO_DISPLAY"), NULL((void*)0));
341 /* DO NOT FREE envVar, putenv() sucks */
342 putenv (envVar);
343}
344
345static void
346meta_finalize (void)
347{
348 MetaDisplay *display = meta_get_display();
349 if (display)
350 meta_display_close (display,
351 CurrentTime0L); /* I doubt correct timestamps matter here */
352
353 meta_session_shutdown ();
354}
355
356static int sigterm_pipe_fds[2] = { -1, -1 };
357
358static void
359sigterm_handler (int signum)
360{
361 if (sigterm_pipe_fds[1] >= 0)
362 {
363 G_GNUC_UNUSED__attribute__ ((__unused__)) int dummy;
364
365 dummy = write (sigterm_pipe_fds[1], "", 1);
366 close (sigterm_pipe_fds[1]);
367 sigterm_pipe_fds[1] = -1;
368 }
369}
370
371static gboolean
372on_sigterm (GIOChannel *source,
373 GIOCondition condition,
374 gpointer user_data)
375{
376 meta_quit (META_EXIT_SUCCESS);
377 return FALSE(0);
378}
379
380/**
381 * This is where the story begins. It parses commandline options and
382 * environment variables, sets up the screen, hands control off to
383 * GTK, and cleans up afterwards.
384 *
385 * \param argc Number of arguments (as usual)
386 * \param argv Array of arguments (as usual)
387 *
388 * \bug It's a bit long. It would be good to split it out into separate
389 * functions.
390 */
391int
392main (int argc, char **argv)
393{
394 struct sigaction act;
395 sigset_t empty_mask;
396 MetaArguments meta_args;
397 const gchar *log_domains[] = {
398 NULL((void*)0), G_LOG_DOMAIN"marco", "Gtk", "Gdk", "GLib",
399 "Pango", "GLib-GObject", "GThread"
400 };
401 guint i;
402 GIOChannel *channel;
403
404 if (setlocale (LC_ALL6, "") == NULL((void*)0))
1
Assuming the condition is false
2
Taking false branch
405 meta_warning ("Locale not understood by C library, internationalization will not work\n");
406
407 sigemptyset (&empty_mask);
408 act.sa_handler__sigaction_handler.sa_handler = SIG_IGN((__sighandler_t) 1);
3
Using a fixed address is not portable because that address will probably not be valid in all environments or platforms
409 act.sa_mask = empty_mask;
410 act.sa_flags = 0;
411 if (sigaction (SIGPIPE13, &act, NULL((void*)0)) < 0)
412 g_printerr ("Failed to register SIGPIPE handler: %s\n",
413 g_strerror (errno(*__errno_location ())));
414#ifdef SIGXFSZ25
415 if (sigaction (SIGXFSZ25, &act, NULL((void*)0)) < 0)
416 g_printerr ("Failed to register SIGXFSZ handler: %s\n",
417 g_strerror (errno(*__errno_location ())));
418#endif
419
420 if (pipe (sigterm_pipe_fds) != 0)
421 g_printerr ("Failed to create SIGTERM pipe: %s\n",
422 g_strerror (errno(*__errno_location ())));
423
424 channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
425 g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL((void*)0));
426 g_io_add_watch (channel, G_IO_IN, on_sigterm, NULL((void*)0));
427 g_io_channel_set_close_on_unref (channel, TRUE(!(0)));
428 g_io_channel_unref (channel);
429
430 act.sa_handler__sigaction_handler.sa_handler = &sigterm_handler;
431 if (sigaction (SIGTERM15, &act, NULL((void*)0)) < 0)
432 g_printerr ("Failed to register SIGTERM handler: %s\n",
433 g_strerror (errno(*__errno_location ())));
434
435 if (g_getenv ("MARCO_VERBOSE"))
436 meta_set_verbose (TRUE(!(0)));
437 if (g_getenv ("MARCO_DEBUG"))
438 meta_set_debugging (TRUE(!(0)));
439
440 if (g_get_home_dir ())
441 if (chdir (g_get_home_dir ()) < 0)
442 meta_warning ("Could not change to home directory %s.\n",
443 g_get_home_dir ());
444
445 meta_print_self_identity ();
446
447 bindtextdomain (GETTEXT_PACKAGE"marco", MARCO_LOCALEDIR"/usr/local/share/locale");
448 bind_textdomain_codeset (GETTEXT_PACKAGE"marco", "UTF-8");
449 textdomain (GETTEXT_PACKAGE"marco");
450
451 /* Parse command line arguments.*/
452 meta_parse_options (&argc, &argv, &meta_args);
453
454 meta_set_syncing (meta_args.sync || (g_getenv ("MARCO_SYNC") != NULL((void*)0)));
455
456 if (meta_args.print_version)
457 {
458 g_print ("%s\n", PACKAGE_STRING"marco 1.28.1");
459 exit (EXIT_SUCCESS0);
460 }
461
462 meta_select_display (meta_args.display_name);
463
464 if (meta_args.replace_wm)
465 meta_set_replace_current_wm (TRUE(!(0)));
466
467 if (meta_args.save_file && meta_args.client_id)
468 meta_fatal ("Can't specify both SM save file and SM client id\n");
469
470 meta_main_loop = g_main_loop_new (NULL((void*)0), FALSE(0));
471
472 meta_ui_init (&argc, &argv);
473
474 /* Load prefs */
475 meta_prefs_init ();
476 meta_prefs_add_listener (prefs_changed_callback, NULL((void*)0));
477
478#if 1
479
480 for (i=0; i<G_N_ELEMENTS(log_domains)(sizeof (log_domains) / sizeof ((log_domains)[0])); i++)
481 g_log_set_handler (log_domains[i],
482 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
483 log_handler, NULL((void*)0));
484
485#endif
486
487 if (g_getenv ("MARCO_G_FATAL_WARNINGS") != NULL((void*)0))
488 g_log_set_always_fatal (G_LOG_LEVEL_MASK);
489
490 meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE(0));
491
492 /* Try to find some theme that'll work if the theme preference
493 * doesn't exist. First try Simple (the default theme) then just
494 * try anything in the themes directory.
495 */
496 if (!meta_ui_have_a_theme ())
497 meta_ui_set_current_theme ("Simple", FALSE(0));
498
499 if (!meta_ui_have_a_theme ())
500 {
501 const char *dir_entry = NULL((void*)0);
502 GError *err = NULL((void*)0);
503 GDir *themes_dir = NULL((void*)0);
504
505 if (!(themes_dir = g_dir_open (MARCO_DATADIR"/usr/local/share""/themes", 0, &err)))
506 {
507 meta_fatal (_("Failed to scan themes directory: %s\n")((char *) g_dgettext ("marco", "Failed to scan themes directory: %s\n"
))
, err->message);
508 g_error_free (err);
509 }
510 else
511 {
512 while (((dir_entry = g_dir_read_name (themes_dir)) != NULL((void*)0)) &&
513 (!meta_ui_have_a_theme ()))
514 {
515 meta_ui_set_current_theme (dir_entry, FALSE(0));
516 }
517
518 g_dir_close (themes_dir);
519 }
520 }
521
522 if (!meta_ui_have_a_theme ())
523 meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n")((char *) g_dgettext ("marco", "Could not find a theme! Be sure %s exists and contains the usual themes.\n"
))
,
524 MARCO_DATADIR"/usr/local/share""/themes");
525
526 /* Connect to SM as late as possible - but before managing display,
527 * or we might try to manage a window before we have the session
528 * info
529 */
530 if (!meta_args.disable_sm)
531 {
532 if (meta_args.client_id == NULL((void*)0))
533 {
534 const gchar *desktop_autostart_id;
535
536 desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
537
538 if (desktop_autostart_id != NULL((void*)0))
539 meta_args.client_id = g_strdup (desktop_autostart_id)g_strdup_inline (desktop_autostart_id);
540 }
541
542 /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
543 * use the same client id. */
544 g_unsetenv ("DESKTOP_AUTOSTART_ID");
545
546 meta_session_init (meta_args.client_id, meta_args.save_file);
547 }
548 /* Free memory possibly allocated by the argument parsing which are
549 * no longer needed.
550 */
551 g_free (meta_args.save_file);
552 g_free (meta_args.display_name);
553 g_free (meta_args.client_id);
554
555 if (meta_args.composite || meta_args.no_composite)
556 meta_prefs_set_force_compositing_manager (meta_args.composite);
557
558 if (meta_args.no_force_fullscreen)
559 meta_prefs_set_force_fullscreen (FALSE(0));
560
561 if (meta_args.no_keybindings)
562 meta_set_keybindings_disabled (TRUE(!(0)));
563
564 if (!meta_display_open ())
565 meta_exit (META_EXIT_ERROR);
566
567 g_main_loop_run (meta_main_loop);
568
569 meta_finalize ();
570
571 if (meta_restart_after_quit)
572 {
573 GError *err;
574
575 err = NULL((void*)0);
576 if (!g_spawn_async (NULL((void*)0),
577 argv,
578 NULL((void*)0),
579 G_SPAWN_SEARCH_PATH,
580 NULL((void*)0),
581 NULL((void*)0),
582 NULL((void*)0),
583 &err))
584 {
585 meta_fatal (_("Failed to restart: %s\n")((char *) g_dgettext ("marco", "Failed to restart: %s\n")),
586 err->message);
587 g_error_free (err); /* not reached anyhow */
588 meta_exit_code = META_EXIT_ERROR;
589 }
590 }
591
592 return meta_exit_code;
593}
594
595/**
596 * Stops Marco. This tells the event loop to stop processing; it is rather
597 * dangerous to use this rather than meta_restart() because this will leave
598 * the user with no window manager. We generally do this only if, for example,
599 * the session manager asks us to; we assume the session manager knows what
600 * it's talking about.
601 *
602 * \param code The success or failure code to return to the calling process.
603 */
604void
605meta_quit (MetaExitCode code)
606{
607 meta_exit_code = code;
608
609 if (g_main_loop_is_running (meta_main_loop))
610 g_main_loop_quit (meta_main_loop);
611}
612
613/**
614 * Restarts Marco. In practice, this tells the event loop to stop
615 * processing, having first set the meta_restart_after_quit flag which
616 * tells Marco to spawn an identical copy of itself before quitting.
617 * This happens on receipt of a _MARCO_RESTART_MESSAGE client event.
618 */
619void
620meta_restart (void)
621{
622 meta_restart_after_quit = TRUE(!(0));
623 meta_quit (META_EXIT_SUCCESS);
624}
625
626/**
627 * Called on pref changes. (One of several functions of its kind and purpose.)
628 *
629 * \bug Why are these particular prefs handled in main.c and not others?
630 * Should they be?
631 *
632 * \param pref Which preference has changed
633 * \param data Arbitrary data (which we ignore)
634 */
635static void
636prefs_changed_callback (MetaPreference pref,
637 gpointer data)
638{
639 switch (pref)
640 {
641 case META_PREF_THEME:
642 meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE(0));
643 meta_display_retheme_all ();
644 break;
645
646 case META_PREF_CURSOR_THEME:
647 case META_PREF_CURSOR_SIZE:
648 meta_display_set_cursor_theme (meta_prefs_get_cursor_theme (),
649 meta_prefs_get_cursor_size ());
650 break;
651 case META_PREF_ICON_SIZE:
652 meta_invalidate_all_icons();
653 break;
654 default:
655 /* handled elsewhere or otherwise */
656 break;
657 }
658}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3ed76c.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3ed76c.html new file mode 100644 index 00000000..9eca8a3a --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3ed76c.html @@ -0,0 +1,1416 @@ + + + +core/async-getprop.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/async-getprop.c
Warning:line 385, column 39
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name async-getprop.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/async-getprop.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Asynchronous X property getting hack */
4
5/*
6 * Copyright (C) 2002 Havoc Pennington
7 * Copyright (C) 1986, 1998 The Open Group
8 *
9 * Permission to use, copy, modify, distribute, and sell this software
10 * and its documentation for any purpose is hereby granted without
11 * fee, provided that the above copyright notice appear in all copies
12 * and that both that copyright notice and this permission notice
13 * appear in supporting documentation.
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Except as contained in this notice, the name of The Open Group shall not be
27 * used in advertising or otherwise to promote the sale, use or other dealings
28 * in this Software without prior written authorization from The Open Group.
29 */
30
31#include <assert.h>
32
33#undef DEBUG_SPEW
34#ifdef DEBUG_SPEW
35#include <stdio.h>
36#endif
37
38#include "async-getprop.h"
39
40#define NEED_REPLIES
41#include <X11/Xlibint.h>
42
43#ifndef NULL((void*)0)
44#define NULL((void*)0) ((void*)0)
45#endif
46
47typedef struct _ListNode ListNode;
48typedef struct _AgPerDisplayData AgPerDisplayData;
49
50struct _ListNode
51{
52 ListNode *next;
53};
54
55struct _AgGetPropertyTask
56{
57 ListNode node;
58
59 AgPerDisplayData *dd;
60 Window window;
61 Atom property;
62
63 unsigned long request_seq;
64 int error;
65
66 Atom actual_type;
67 int actual_format;
68
69 unsigned long n_items;
70 unsigned long bytes_after;
71 char *data;
72
73 Boolint have_reply;
74};
75
76struct _AgPerDisplayData
77{
78 ListNode node;
79 _XAsyncHandler async;
80
81 Display *display;
82 ListNode *pending_tasks;
83 ListNode *pending_tasks_tail;
84 ListNode *completed_tasks;
85 ListNode *completed_tasks_tail;
86 int n_tasks_pending;
87 int n_tasks_completed;
88};
89
90static ListNode *display_datas = NULL((void*)0);
91static ListNode *display_datas_tail = NULL((void*)0);
92
93static void
94append_to_list (ListNode **head,
95 ListNode **tail,
96 ListNode *task)
97{
98 task->next = NULL((void*)0);
99
100 if (*tail == NULL((void*)0))
101 {
102 assert (*head == NULL)((void) sizeof ((*head == ((void*)0)) ? 1 : 0), __extension__
({ if (*head == ((void*)0)) ; else __assert_fail ("*head == NULL"
, "core/async-getprop.c", 102, __extension__ __PRETTY_FUNCTION__
); }))
;
103 *head = task;
104 *tail = task;
105 }
106 else
107 {
108 (*tail)->next = task;
109 *tail = task;
110 }
111}
112
113static void
114remove_from_list (ListNode **head,
115 ListNode **tail,
116 ListNode *task)
117{
118 ListNode *prev;
119 ListNode *node;
120
121 prev = NULL((void*)0);
122 node = *head;
123 while (node != NULL((void*)0))
124 {
125 if (node == task)
126 {
127 if (prev)
128 prev->next = node->next;
129 else
130 *head = node->next;
131
132 if (node == *tail)
133 *tail = prev;
134
135 break;
136 }
137
138 prev = node;
139 node = node->next;
140 }
141
142 /* can't remove what's not there */
143 assert (node != NULL)((void) sizeof ((node != ((void*)0)) ? 1 : 0), __extension__ (
{ if (node != ((void*)0)) ; else __assert_fail ("node != NULL"
, "core/async-getprop.c", 143, __extension__ __PRETTY_FUNCTION__
); }))
;
144
145 node->next = NULL((void*)0);
146}
147
148static void
149move_to_completed (AgPerDisplayData *dd,
150 AgGetPropertyTask *task)
151{
152 remove_from_list (&dd->pending_tasks,
153 &dd->pending_tasks_tail,
154 &task->node);
155
156 append_to_list (&dd->completed_tasks,
157 &dd->completed_tasks_tail,
158 &task->node);
159
160 dd->n_tasks_pending -= 1;
161 dd->n_tasks_completed += 1;
162}
163
164static AgGetPropertyTask*
165find_pending_by_request_sequence (AgPerDisplayData *dd,
166 unsigned long request_seq)
167{
168 ListNode *node;
169
170 /* if the sequence is after our last pending task, we
171 * aren't going to find a match
172 */
173 {
174 AgGetPropertyTask *task = (AgGetPropertyTask*) dd->pending_tasks_tail;
175 if (task != NULL((void*)0))
176 {
177 if (task->request_seq < request_seq)
178 return NULL((void*)0);
179 else if (task->request_seq == request_seq)
180 return task; /* why not check this */
181 }
182 }
183
184 /* Generally we should get replies in the order we sent
185 * requests, so we should usually be using the task
186 * at the head of the list, if we use any task at all.
187 * I'm not sure this is 100% guaranteed, if it is,
188 * it would be a big speedup.
189 */
190
191 node = dd->pending_tasks;
192 while (node != NULL((void*)0))
193 {
194 AgGetPropertyTask *task = (AgGetPropertyTask*) node;
195
196 if (task->request_seq == request_seq)
197 return task;
198
199 node = node->next;
200 }
201
202 return NULL((void*)0);
203}
204
205static Boolint
206async_get_property_handler (Display *dpy,
207 xReply *rep,
208 char *buf,
209 int len,
210 XPointer data)
211{
212 xGetPropertyReply replbuf;
213 xGetPropertyReply *reply;
214 AgGetPropertyTask *task;
215 AgPerDisplayData *dd;
216 int bytes_read;
217
218 dd = (void*) data;
219
220#if 0
221 printf ("%s: seeing request seq %ld buflen %d\n", __FUNCTION__,
222 dpy->last_request_read, len);
223#endif
224
225 task = find_pending_by_request_sequence (dd, dpy->last_request_read);
226
227 if (task == NULL((void*)0))
1
Assuming 'task' is not equal to NULL
2
Taking false branch
228 return False0;
229
230 assert (dpy->last_request_read == task->request_seq)((void) sizeof ((dpy->last_request_read == task->request_seq
) ? 1 : 0), __extension__ ({ if (dpy->last_request_read ==
task->request_seq) ; else __assert_fail ("dpy->last_request_read == task->request_seq"
, "core/async-getprop.c", 230, __extension__ __PRETTY_FUNCTION__
); }))
;
3
Assuming field 'last_request_read' is equal to field 'request_seq'
4
Taking true branch
231
232 task->have_reply = True1;
233 move_to_completed (dd, task);
234
235 /* read bytes so far */
236 bytes_read = SIZEOF (xReply)32;
237
238 if (rep->generic.type == X_Error0)
5
Assuming field 'type' is not equal to X_Error
6
Taking false branch
239 {
240 xError errbuf;
241
242 task->error = rep->error.errorCode;
243
244#ifdef DEBUG_SPEW
245 printf ("%s: error code = %d (ignoring error, eating %d bytes, generic.length = %ld)\n",
246 __FUNCTION__, task->error, (SIZEOF (xError)32 - bytes_read),
247 rep->generic.length);
248#endif
249
250 /* We return True (meaning we consumed the reply)
251 * because otherwise it would invoke the X error handler,
252 * and an async API is useless if you have to synchronously
253 * trap X errors. Also GetProperty can always fail, pretty
254 * much, so trapping errors is always what you want.
255 *
256 * We have to eat all the error reply data here.
257 * (kind of a charade as we know sizeof(xError) == sizeof(xReply))
258 *
259 * Passing discard = True seems to break things; I don't understand
260 * why, because there should be no extra data in an error reply,
261 * right?
262 */
263 _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
264 (SIZEOF (xError)32 - bytes_read) >> 2, /* in 32-bit words */
265 False0); /* really seems like it should be True */
266
267 return True1;
268 }
269
270#ifdef DEBUG_SPEW
271 printf ("%s: already read %d bytes reading %d more for total of %d; generic.length = %ld\n",
272 __FUNCTION__, bytes_read, (SIZEOF (xGetPropertyReply)32 - bytes_read) >> 2,
273 SIZEOF (xGetPropertyReply)32, rep->generic.length);
274#endif
275
276 /* (kind of a silly as we know sizeof(xGetPropertyReply) == sizeof(xReply)) */
277 reply = (xGetPropertyReply *) (void *)
278 _XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len,
279 (SIZEOF (xGetPropertyReply)32 - bytes_read) >> 2, /* in 32-bit words */
280 False0); /* False means expecting more data to follow,
281 * don't eat the rest of the reply
282 */
283
284 bytes_read = SIZEOF (xGetPropertyReply)32;
285
286#ifdef DEBUG_SPEW
287 printf ("%s: have reply propertyType = %ld format = %d n_items = %ld\n",
288 __FUNCTION__, reply->propertyType, reply->format, reply->nItems);
289#endif
290
291 assert (task->data == NULL)((void) sizeof ((task->data == ((void*)0)) ? 1 : 0), __extension__
({ if (task->data == ((void*)0)) ; else __assert_fail ("task->data == NULL"
, "core/async-getprop.c", 291, __extension__ __PRETTY_FUNCTION__
); }))
;
7
Assuming field 'data' is equal to null
8
Taking true branch
292
293 /* This is all copied from XGetWindowProperty(). Not sure we should
294 * LockDisplay(). Not sure I'm passing the right args to
295 * XGetAsyncData(). Not sure about a lot of things.
296 */
297
298 /* LockDisplay (dpy); */
299
300 if (reply->propertyType != None0L)
9
Assuming field 'propertyType' is not equal to None
10
Taking true branch
301 {
302 long nbytes, netbytes;
303
304 /* this alignment macro from matecorba2 */
305#define ALIGN_VALUE(this, boundary)(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)
) & (~(((unsigned long)(boundary))-1)))
\
306 (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
307
308 switch (reply->format)
11
Control jumps to 'case 32:' at line 351
309 {
310 /*
311 * One extra byte is malloced than is needed to contain the property
312 * data, but this last byte is null terminated and convenient for
313 * returning string properties, so the client doesn't then have to
314 * recopy the string to make it null terminated.
315 */
316 case 8:
317 nbytes = reply->nItems;
318 /* there's padding to word boundary */
319 netbytes = ALIGN_VALUE (nbytes, 4)(( ((unsigned long)(nbytes)) + (((unsigned long)(4)) -1)) &
(~(((unsigned long)(4))-1)))
;
320 if (nbytes + 1 > 0 &&
321 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)malloc((size_t)(((unsigned)nbytes + 1) == 0 ? 1 : ((unsigned)
nbytes + 1)))
))
322 {
323#ifdef DEBUG_SPEW
324 printf ("%s: already read %d bytes using %ld, more eating %ld more\n",
325 __FUNCTION__, bytes_read, nbytes, netbytes);
326#endif
327 /* _XReadPad (dpy, (char *) task->data, netbytes); */
328 _XGetAsyncData (dpy, task->data, buf, len,
329 bytes_read, nbytes,
330 netbytes);
331 }
332 break;
333
334 case 16:
335 nbytes = reply->nItems * sizeof (short);
336 netbytes = reply->nItems << 1;
337 netbytes = ALIGN_VALUE (netbytes, 4)(( ((unsigned long)(netbytes)) + (((unsigned long)(4)) -1)) &
(~(((unsigned long)(4))-1)))
; /* align to word boundary */
338 if (nbytes + 1 > 0 &&
339 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)malloc((size_t)(((unsigned)nbytes + 1) == 0 ? 1 : ((unsigned)
nbytes + 1)))
))
340 {
341#ifdef DEBUG_SPEW
342 printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
343 __FUNCTION__, bytes_read, nbytes, netbytes);
344#endif
345 /* _XRead16Pad (dpy, (short *) task->data, netbytes); */
346 _XGetAsyncData (dpy, task->data, buf, len,
347 bytes_read, nbytes, netbytes);
348 }
349 break;
350
351 case 32:
352 /* NOTE buffer is in longs to match XGetWindowProperty() */
353 nbytes = reply->nItems * sizeof (long);
354 netbytes = reply->nItems << 2; /* wire size is always 32 bits though */
355 if (nbytes + 1 > 0 &&
12
Assuming the condition is true
16
Taking true branch
356 (task->data = (char *) Xmalloc ((unsigned)nbytes + 1)malloc((size_t)(((unsigned)nbytes + 1) == 0 ? 1 : ((unsigned)
nbytes + 1)))
))
13
Assuming the condition is true
14
'?' condition is true
15
Assuming field 'data' is non-null
357 {
358#ifdef DEBUG_SPEW
359 printf ("%s: already read %d bytes using %ld more, eating %ld more\n",
360 __FUNCTION__, bytes_read, nbytes, netbytes);
361#endif
362
363 /* We have to copy the XGetWindowProperty() crackrock
364 * and get format 32 as long even on 64-bit platforms.
365 */
366 if (sizeof (long) == 8)
17
Taking true branch
367 {
368 char *netdata;
369 char *lptr;
370 char *end_lptr;
371
372 /* Store the 32-bit values in the end of the array */
373 netdata = task->data + nbytes / 2;
374
375 _XGetAsyncData (dpy, netdata, buf, len,
376 bytes_read, netbytes,
377 netbytes);
378
379 /* Now move the 32-bit values to the front */
380
381 lptr = task->data;
382 end_lptr = task->data + nbytes;
383 while (lptr != end_lptr)
18
Loop condition is true. Entering loop body
384 {
385 *(long*) lptr = *(CARD32*) netdata;
19
Out of bound memory access (access exceeds upper limit of memory block)
386 lptr += sizeof (long);
387 netdata += sizeof (CARD32);
388 }
389 }
390 else
391 {
392 /* Here the wire format matches our actual format */
393 _XGetAsyncData (dpy, task->data, buf, len,
394 bytes_read, netbytes,
395 netbytes);
396 }
397 }
398 break;
399
400 default:
401 /*
402 * This part of the code should never be reached. If it is,
403 * the server sent back a property with an invalid format.
404 * This is a BadImplementation error.
405 *
406 * However this async GetProperty API doesn't report errors
407 * via the standard X mechanism, so don't do anything about
408 * it, other than store it in task->error.
409 */
410 {
411#if 0
412 xError error;
413#endif
414
415 task->error = BadImplementation17;
416
417#if 0
418 error.sequenceNumber = task->request_seq;
419 error.type = X_Error0;
420 error.majorCode = X_GetProperty20;
421 error.minorCode = 0;
422 error.errorCode = BadImplementation17;
423
424 _XError (dpy, &error);
425#endif
426 }
427
428 nbytes = netbytes = 0L;
429 break;
430 }
431
432 if (task->data == NULL((void*)0))
433 {
434 task->error = BadAlloc11;
435
436#ifdef DEBUG_SPEW
437 printf ("%s: already read %d bytes eating %ld\n",
438 __FUNCTION__, bytes_read, netbytes);
439#endif
440 /* _XEatData (dpy, (unsigned long) netbytes); */
441 _XGetAsyncData (dpy, NULL((void*)0), buf, len,
442 bytes_read, 0, netbytes);
443
444 /* UnlockDisplay (dpy); */
445 return BadAlloc11; /* not Success */
446 }
447
448 (task->data)[nbytes] = '\0';
449 }
450
451#ifdef DEBUG_SPEW
452 printf ("%s: have data\n", __FUNCTION__);
453#endif
454
455 task->actual_type = reply->propertyType;
456 task->actual_format = reply->format;
457 task->n_items = reply->nItems;
458 task->bytes_after = reply->bytesAfter;
459
460 /* UnlockDisplay (dpy); */
461
462 return True1;
463}
464
465static AgPerDisplayData*
466get_display_data (Display *display,
467 Boolint create)
468{
469 ListNode *node;
470 AgPerDisplayData *dd;
471
472 node = display_datas;
473 while (node != NULL((void*)0))
474 {
475 dd = (AgPerDisplayData*) node;
476
477 if (dd->display == display)
478 return dd;
479
480 node = node->next;
481 }
482
483 if (!create)
484 return NULL((void*)0);
485
486 dd = Xcalloc (1, sizeof (AgPerDisplayData))calloc((size_t)((1) == 0 ? 1 : (1)), (size_t)(sizeof (AgPerDisplayData
)))
;
487 if (dd == NULL((void*)0))
488 return NULL((void*)0);
489
490 dd->display = display;
491 dd->async.next = display->async_handlers;
492 dd->async.handler = async_get_property_handler;
493 dd->async.data = (XPointer) dd;
494 dd->display->async_handlers = &dd->async;
495
496 append_to_list (&display_datas,
497 &display_datas_tail,
498 &dd->node);
499
500 return dd;
501}
502
503static void
504maybe_free_display_data (AgPerDisplayData *dd)
505{
506 if (dd->pending_tasks == NULL((void*)0) &&
507 dd->completed_tasks == NULL((void*)0))
508 {
509 DeqAsyncHandler (dd->display, &dd->async){ if (dd->display->async_handlers == (&dd->async
)) dd->display->async_handlers = (&dd->async)->
next; else _XDeqAsyncHandler(dd->display, &dd->async
); }
;
510 remove_from_list (&display_datas, &display_datas_tail,
511 &dd->node);
512 XFree (dd);
513 }
514}
515
516AgGetPropertyTask*
517ag_task_create (Display *dpy,
518 Window window,
519 Atom property,
520 long offset,
521 long length,
522 Boolint delete,
523 Atom req_type)
524{
525 AgGetPropertyTask *task;
526 xGetPropertyReq *req;
527 AgPerDisplayData *dd;
528
529 /* Fire up our request */
530 LockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->lock_display
)(dpy)
;
531
532 dd = get_display_data (dpy, True1);
533 if (dd == NULL((void*)0))
534 {
535 UnlockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
536 return NULL((void*)0);
537 }
538
539 GetReq (GetProperty, req)req = (xGetPropertyReq *) _XGetRequest(dpy, 20, 24);
540 req->window = window;
541 req->property = property;
542 req->type = req_type;
543 req->delete = delete;
544 req->longOffset = offset;
545 req->longLength = length;
546
547 /* Queue up our async task */
548 task = Xcalloc (1, sizeof (AgGetPropertyTask))calloc((size_t)((1) == 0 ? 1 : (1)), (size_t)(sizeof (AgGetPropertyTask
)))
;
549 if (task == NULL((void*)0))
550 {
551 UnlockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
552 return NULL((void*)0);
553 }
554
555 task->dd = dd;
556 task->window = window;
557 task->property = property;
558 task->request_seq = dpy->request;
559
560 append_to_list (&dd->pending_tasks,
561 &dd->pending_tasks_tail,
562 &task->node);
563 dd->n_tasks_pending += 1;
564
565 UnlockDisplay (dpy)if ((dpy)->lock_fns) (*(dpy)->lock_fns->unlock_display
)(dpy)
;
566
567 SyncHandle ()if (dpy->synchandler) (*dpy->synchandler)(dpy);
568
569 return task;
570}
571
572static void
573free_task (AgGetPropertyTask *task)
574{
575 remove_from_list (&task->dd->completed_tasks,
576 &task->dd->completed_tasks_tail,
577 &task->node);
578 task->dd->n_tasks_completed -= 1;
579 maybe_free_display_data (task->dd);
580 XFree (task);
581}
582
583Statusint
584ag_task_get_reply_and_free (AgGetPropertyTask *task,
585 Atom *actual_type,
586 int *actual_format,
587 unsigned long *nitems,
588 unsigned long *bytesafter,
589 unsigned char **prop)
590{
591 Display *dpy;
592
593 *prop = NULL((void*)0);
594
595 dpy = task->dd->display; /* Xlib macros require a variable named "dpy" */
596
597 if (task->error != Success0)
598 {
599 Statusint s = task->error;
600
601 free_task (task);
602
603 return s;
604 }
605
606 if (!task->have_reply)
607 {
608 free_task (task);
609
610 return BadAlloc11; /* not Success */
611 }
612
613 *actual_type = task->actual_type;
614 *actual_format = task->actual_format;
615 *nitems = task->n_items;
616 *bytesafter = task->bytes_after;
617
618 *prop = (unsigned char*) task->data; /* pass out ownership of task->data */
619
620 SyncHandle ()if (dpy->synchandler) (*dpy->synchandler)(dpy);
621
622 free_task (task);
623
624 return Success0;
625}
626
627Boolint
628ag_task_have_reply (AgGetPropertyTask *task)
629{
630 return task->have_reply;
631}
632
633Atom
634ag_task_get_property (AgGetPropertyTask *task)
635{
636 return task->property;
637}
638
639Window
640ag_task_get_window (AgGetPropertyTask *task)
641{
642 return task->window;
643}
644
645Display*
646ag_task_get_display (AgGetPropertyTask *task)
647{
648 return task->dd->display;
649}
650
651AgGetPropertyTask*
652ag_get_next_completed_task (Display *display)
653{
654 AgPerDisplayData *dd;
655
656 dd = get_display_data (display, False0);
657
658 if (dd == NULL((void*)0))
659 return NULL((void*)0);
660
661#ifdef DEBUG_SPEW
662 printf ("%d pending %d completed\n",
663 dd->n_tasks_pending,
664 dd->n_tasks_completed);
665#endif
666
667 return (AgGetPropertyTask*) dd->completed_tasks;
668}
669
670void*
671ag_Xmalloc (unsigned long bytes)
672{
673 return (void*) Xmalloc (bytes)malloc((size_t)((bytes) == 0 ? 1 : (bytes)));
674}
675
676void*
677ag_Xmalloc0 (unsigned long bytes)
678{
679 return (void*) Xcalloc (bytes, 1)calloc((size_t)((bytes) == 0 ? 1 : (bytes)), (size_t)(1));
680}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3eecf0.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3eecf0.html new file mode 100644 index 00000000..21e0631b --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-3eecf0.html @@ -0,0 +1,816 @@ + + + +test-size-hints.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:wm-tester/test-size-hints.c
Warning:line 92, column 11
Value stored to 'y' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name test-size-hints.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src/wm-tester -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src/wm-tester -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c test-size-hints.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1#include <X11/Xlib.h>
2#include <X11/Xutil.h>
3#include <stdlib.h>
4#include <glib.h>
5
6static Boolint
7all_events (Display *display,
8 XEvent *event,
9 XPointer arg)
10{
11 return True1;
12}
13
14#if 0
15static void
16get_size (Display *d, Drawable draw,
17 int *xp, int *yp, int *widthp, int *heightp)
18{
19 int x, y;
20 unsigned int width, height, border, depth;
21 Window root;
22
23 XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth);
24
25 if (xp)
26 *xp = x;
27 if (yp)
28 *yp = y;
29 if (widthp)
30 *widthp = width;
31 if (*heightp)
32 *heightp = height;
33}
34#endif
35
36int
37main (int argc, char **argv)
38{
39 Display *d;
40 Window zero_min_size;
41 XSizeHints hints;
42 int screen;
43 XEvent ev;
44 int x, y, width, height;
45 Pixmap pix;
46 GC gc;
47 XGCValues gc_vals;
48 gboolean redraw_pending;
49
50 d = XOpenDisplay (NULL((void*)0));
51
52 screen = DefaultScreen (d)(((_XPrivDisplay)(d))->default_screen);
53
54 x = 0;
55 y = 0;
56 width = 100;
57 height = 100;
58
59 zero_min_size = XCreateSimpleWindow (d, RootWindow (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root),
60 x, y, width, height, 0,
61 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
62 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
63
64 XSelectInput (d, zero_min_size,
65 ButtonPressMask(1L<<2) | ExposureMask(1L<<15) | StructureNotifyMask(1L<<17));
66
67 hints.flags = PMinSize(1L << 4);
68
69 hints.min_width = 0;
70 hints.min_height = 0;
71
72 XSetWMNormalHints (d, zero_min_size, &hints);
73 XMapWindow (d, zero_min_size);
74
75 redraw_pending = FALSE(0);
76 while (1)
77 {
78 XNextEvent (d, &ev);
79
80 switch (ev.xany.type)
81 {
82 case ButtonPress4:
83 if (ev.xbutton.button == 1)
84 {
85 g_print ("Exiting on button 1 press\n");
86 exit (0);
87 }
88 break;
89
90 case ConfigureNotify22:
91 x = ev.xconfigure.x;
92 y = ev.xconfigure.y;
Value stored to 'y' is never read
93 width = ev.xconfigure.width;
94 height = ev.xconfigure.height;
95
96 redraw_pending = TRUE(!(0));
97 break;
98
99 case Expose12:
100 redraw_pending = TRUE(!(0));
101 break;
102
103 default:
104 break;
105 }
106
107 /* Primitive event compression */
108 if (XCheckIfEvent (d, &ev, all_events, NULL((void*)0)))
109 {
110 XPutBackEvent (d, &ev);
111 }
112 else if (redraw_pending)
113 {
114 pix = XCreatePixmap (d, zero_min_size, width, height,
115 DefaultDepth (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root_depth
)
);
116
117 gc_vals.foreground = WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
;
118
119 gc = XCreateGC (d, pix, GCForeground(1L<<2), &gc_vals);
120
121 XFillRectangle (d, pix, gc, 0, 0, width, height);
122
123 XCopyArea (d, pix, zero_min_size, gc, 0, 0, width, height, 0, 0);
124
125 XFreePixmap (d, pix);
126 XFreeGC (d, gc);
127
128 redraw_pending = FALSE(0);
129 }
130 }
131
132 /* This program has an infinite loop above so a return statement would
133 * just cause compiler warnings.
134 */
135}
136
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-58a7de.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-58a7de.html new file mode 100644 index 00000000..85df0acf --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-58a7de.html @@ -0,0 +1,937 @@ + + + +test-resizing.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:wm-tester/test-resizing.c
Warning:line 138, column 3
Value stored to 'mask' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name test-resizing.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src/wm-tester -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src/wm-tester -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c test-resizing.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1#include <X11/Xlib.h>
2#include <X11/Xutil.h>
3#include <stdlib.h>
4#include <glib.h>
5
6static void
7calc_rects (XRectangle *rects, int width, int height)
8{
9 int w = (width - 21) / 3;
10 int h = (height - 21) / 3;
11 int i;
12
13 i = 0;
14 while (i < 9)
15 {
16 rects[i].width = w;
17 rects[i].height = h;
18 ++i;
19 }
20
21 /* NW */
22 rects[0].x = 0;
23 rects[0].y = 0;
24
25 /* N */
26 rects[1].x = width / 2 - w / 2;
27 rects[1].y = 0;
28
29 /* NE */
30 rects[2].x = width - w;
31 rects[2].y = 0;
32
33 /* E */
34 rects[3].x = width - w;
35 rects[3].y = height / 2 - h / 2;
36
37 /* SE */
38 rects[4].x = width - w;
39 rects[4].y = height - h;
40
41 /* S */
42 rects[5].x = width / 2 - w / 2;
43 rects[5].y = height - h;
44
45 /* SW */
46 rects[6].x = 0;
47 rects[6].y = height - h;
48
49 /* W */
50 rects[7].x = 0;
51 rects[7].y = height / 2 - h / 2;
52
53 /* Center */
54 rects[8].x = width / 2 - w / 2;
55 rects[8].y = height / 2 - h / 2;
56}
57
58static Boolint
59all_events (Display *display,
60 XEvent *event,
61 XPointer arg)
62{
63 return True1;
64}
65
66static void
67get_size (Display *d, Drawable draw,
68 int *xp, int *yp, int *widthp, int *heightp)
69{
70 int x, y;
71 unsigned int width=0, height=0, border=0, depth=0;
72 Window root;
73
74 XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth);
75
76 if (xp)
77 *xp = x;
78 if (yp)
79 *yp = y;
80 if (widthp)
81 *widthp = width;
82 if (heightp)
83 *heightp = height;
84}
85
86int
87main (int argc, char **argv)
88{
89 Display *d;
90 Window w, cw;
91 XSizeHints hints;
92 int screen;
93 XEvent ev;
94 int x, y, width, height;
95 Pixmap pix;
96 GC gc;
97 XGCValues gc_vals;
98 XSetWindowAttributes set_attrs;
99 XWindowChanges changes;
100 XRectangle rects[9];
101 gboolean redraw_pending;
102 unsigned int mask;
103
104 d = XOpenDisplay (NULL((void*)0));
105
106 screen = DefaultScreen (d)(((_XPrivDisplay)(d))->default_screen);
107
108 /* Print some debug spew to show how StaticGravity works */
109 w = XCreateSimpleWindow (d, RootWindow (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root),
110 0, 0, 100, 100, 0,
111 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
112 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
113 cw = XCreateSimpleWindow (d, w,
114 0, 0, 100, 100, 0,
115 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
116 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
117 set_attrs.win_gravity = StaticGravity10;
118
119 XChangeWindowAttributes (d, cw,
120 CWWinGravity(1L<<5),
121 &set_attrs);
122
123 get_size (d, w, &x, &y, &width, &height);
124
125 g_print ("Parent is %d,%d %d x %d before configuring parent\n",
126 x, y, width, height);
127
128 get_size (d, cw, &x, &y, &width, &height);
129
130 g_print ("Child is %d,%d %d x %d before configuring parent\n",
131 x, y, width, height);
132
133 changes.x = 10;
134 changes.y = 10;
135 changes.width = 110;
136 changes.height = 110;
137 /* last mask wins */
138 mask = CWX(1<<0) | CWY(1<<1);
Value stored to 'mask' is never read
139 mask = CWWidth(1<<2) | CWHeight(1<<3);
140 mask = CWX(1<<0) | CWY(1<<1) | CWWidth(1<<2) | CWHeight(1<<3);
141
142 XConfigureWindow (d, w, mask, &changes);
143 XSync (d, False0);
144
145 get_size (d, w, &x, &y, &width, &height);
146
147 g_print ("Parent is %d,%d %d x %d after configuring parent\n",
148 x, y, width, height);
149
150 get_size (d, cw, &x, &y, &width, &height);
151
152 g_print ("Child is %d,%d %d x %d after configuring parent\n",
153 x, y, width, height);
154
155 XDestroyWindow (d, w);
156
157 /* The window that gets displayed */
158
159 x = 20;
160 y = 20;
161 width = 100;
162 height = 100;
163
164 calc_rects (rects, width, height);
165
166 w = XCreateSimpleWindow (d, RootWindow (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root),
167 x, y, width, height, 0,
168 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
169 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
170
171 set_attrs.bit_gravity = StaticGravity10;
172
173 XChangeWindowAttributes (d, w,
174 CWBitGravity(1L<<4),
175 &set_attrs);
176
177 XSelectInput (d, w,
178 ButtonPressMask(1L<<2) | ExposureMask(1L<<15) | StructureNotifyMask(1L<<17));
179
180 hints.flags = PMinSize(1L << 4);
181
182 hints.min_width = 100;
183 hints.min_height = 100;
184
185 XSetWMNormalHints (d, w, &hints);
186 XMapWindow (d, w);
187
188 redraw_pending = FALSE(0);
189 while (1)
190 {
191 XNextEvent (d, &ev);
192
193 switch (ev.xany.type)
194 {
195 case ButtonPress4:
196 if (ev.xbutton.button == 3)
197 {
198 g_print ("Exiting on button 3 press\n");
199 exit (0);
200 }
201 break;
202
203 case ConfigureNotify22:
204 x = ev.xconfigure.x;
205 y = ev.xconfigure.y;
206 width = ev.xconfigure.width;
207 height = ev.xconfigure.height;
208
209 redraw_pending = TRUE(!(0));
210 break;
211
212 case Expose12:
213 redraw_pending = TRUE(!(0));
214 break;
215
216 default:
217 break;
218 }
219
220 /* Primitive event compression */
221 if (XCheckIfEvent (d, &ev, all_events, NULL((void*)0)))
222 {
223 XPutBackEvent (d, &ev);
224 }
225 else if (redraw_pending)
226 {
227 calc_rects (rects, width, height);
228
229 pix = XCreatePixmap (d, w, width, height,
230 DefaultDepth (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root_depth
)
);
231
232 gc_vals.foreground = WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
;
233
234 gc = XCreateGC (d, pix, GCForeground(1L<<2), &gc_vals);
235
236 XFillRectangle (d, pix, gc, 0, 0, width, height);
237
238 /* Draw rectangles at each gravity point */
239 gc_vals.foreground = BlackPixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->black_pixel
)
;
240 XChangeGC (d, gc, GCForeground(1L<<2), &gc_vals);
241
242 XFillRectangles (d, pix, gc, rects, G_N_ELEMENTS (rects)(sizeof (rects) / sizeof ((rects)[0])));
243
244 XCopyArea (d, pix, w, gc, 0, 0, width, height, 0, 0);
245
246 XFreePixmap (d, pix);
247 XFreeGC (d, gc);
248
249 redraw_pending = FALSE(0);
250 }
251 }
252
253 /* This program has an infinite loop above so a return statement would
254 * just cause compiler warnings.
255 */
256}
257
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-641a36.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-641a36.html new file mode 100644 index 00000000..0f5e3145 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-641a36.html @@ -0,0 +1,1807 @@ + + + +ui/theme-viewer.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme-viewer.c
Warning:line 896, column 5
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme-viewer.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme-viewer.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco theme viewer and test app main() */
4
5/*
6 * Copyright (C) 2002 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <config.h>
25#include <glib/gi18n.h>
26
27#include "util.h"
28#include "theme.h"
29#include "theme-parser.h"
30#include "preview-widget.h"
31#include <gtk/gtk.h>
32#include <time.h>
33#include <stdlib.h>
34#include <string.h>
35
36/* We need to compute all different button arrangements
37 * in terms of button location. We don't care about
38 * different arrangements in terms of button function.
39 *
40 * So if dups are allowed, from 0-4 buttons on the left, from 0-4 on
41 * the right, 5x5=25 combinations.
42 *
43 * If no dups, 0-4 on left determines the number on the right plus
44 * we have a special case for the "no buttons on either side" case.
45 */
46#ifndef ALLOW_DUPLICATE_BUTTONS
47#define BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1) (MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST + 1 + 1)
48#else
49#define BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1) ((MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST+1)*(MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST+1))
50#endif
51
52enum
53{
54 FONT_SIZE_SMALL,
55 FONT_SIZE_NORMAL,
56 FONT_SIZE_LARGE,
57 FONT_SIZE_LAST
58};
59
60static MetaTheme *global_theme = NULL((void*)0);
61static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1)] = { NULL((void*)0), };
62static double milliseconds_to_draw_frame = 0.0;
63
64static void run_theme_benchmark (void);
65
66static const gchar *xml =
67 "<interface>"
68 "<menu id='menubar'>"
69 "<submenu>"
70 "<attribute name='label'>Windows</attribute>"
71 "<section>"
72 "<item>"
73 "<attribute name='label'>Dialog</attribute>"
74 "<attribute name='action'>theme-viewer.dialog1</attribute>"
75 "<attribute name='accel'>&lt;control&gt;d</attribute>"
76 "</item>"
77 "<item>"
78 "<attribute name='label'>Modal dialog</attribute>"
79 "<attribute name='action'>theme-viewer.dialog2</attribute>"
80 "</item>"
81 "<item>"
82 "<attribute name='label'>Utility</attribute>"
83 "<attribute name='action'>theme-viewer.utility</attribute>"
84 "<attribute name='accel'>&lt;control&gt;u</attribute>"
85 "</item>"
86 "<item>"
87 "<attribute name='label'>Splashscreen</attribute>"
88 "<attribute name='action'>theme-viewer.splashscreen</attribute>"
89 "<attribute name='accel'>&lt;control&gt;s</attribute>"
90 "</item>"
91 "<item>"
92 "<attribute name='label'>Top dock</attribute>"
93 "<attribute name='action'>theme-viewer.top-dock</attribute>"
94 "</item>"
95 "<item>"
96 "<attribute name='label'>Bottom dock</attribute>"
97 "<attribute name='action'>theme-viewer.bottom-dock</attribute>"
98 "</item>"
99 "<item>"
100 "<attribute name='label'>Left dock</attribute>"
101 "<attribute name='action'>theme-viewer.left-dock</attribute>"
102 "</item>"
103 "<item>"
104 "<attribute name='label'>Right dock</attribute>"
105 "<attribute name='action'>theme-viewer.right-dock</attribute>"
106 "</item>"
107 "<item>"
108 "<attribute name='label'>All docks</attribute>"
109 "<attribute name='action'>theme-viewer.all-docks</attribute>"
110 "</item>"
111 "<item>"
112 "<attribute name='label'>Desktop</attribute>"
113 "<attribute name='action'>theme-viewer.desktop</attribute>"
114 "</item>"
115 "</section>"
116 "</submenu>"
117 "</menu>"
118 "</interface>";
119
120static GActionEntry theme_viewer_entries[] =
121{
122 /* menubar */
123 { "dialog1", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
124 { "dialog2", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
125 { "utility", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
126 { "splashscreen", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
127 { "top-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
128 { "bottom-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
129 { "left-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
130 { "right-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
131 { "all-docks", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
132 { "desktop", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
133 /* toolbar */
134 { "new", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
135 { "open", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
136 { "quit", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} }
137};
138
139static GtkWidget *
140create_toolbar (void)
141{
142 GtkWidget *toolbar;
143 GtkToolItem *item;
144
145 toolbar = gtk_toolbar_new ();
146
147 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-new", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
148 gtk_tool_item_set_tooltip_markup (item, "Open another one of these windows");
149 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.new");
150 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
151
152 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-open", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
153 gtk_tool_item_set_tooltip_markup (item, "This is a demo button with an 'open' icon");
154 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.open");
155 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
156
157 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("application-exit", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
158 gtk_tool_item_set_tooltip_markup (item, "This is a demo button with a 'quit' icon");
159 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.quit");
160 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
161
162 return toolbar;
163}
164
165static GtkWidget *
166normal_contents (void)
167{
168 GtkWidget *grid;
169 GtkWidget *statusbar;
170 GtkWidget *contents;
171 GtkWidget *sw;
172 GtkBuilder *builder;
173
174 grid = gtk_grid_new ();
175 builder = gtk_builder_new_from_string (xml, -1);
176
177 /* create menu items */
178 GMenuModel *model = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"))((((GMenuModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (builder, "menubar"))), ((g_menu_model_get_type
()))))))
;
179 GtkWidget *menubar = gtk_menu_bar_new_from_model (model);
180 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, menubar, 0, 0, 1, 1);
181 gtk_widget_set_hexpand (menubar, TRUE(!(0)));
182
183 /* Create the toolbar */
184 GtkWidget *toolbar = create_toolbar ();
185 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, toolbar, 0, 1, 1, 1);
186 gtk_widget_set_hexpand (toolbar, TRUE(!(0)));
187
188 /* Create document
189 */
190
191 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
192 gtk_widget_set_hexpand (sw, TRUE(!(0)));
193 gtk_widget_set_vexpand (sw, TRUE(!(0)));
194
195 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
196 GTK_POLICY_AUTOMATIC,
197 GTK_POLICY_AUTOMATIC);
198
199 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
200 GTK_SHADOW_IN);
201
202 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
203 sw,
204 0, 2, 1, 1);
205
206 contents = gtk_text_view_new ();
207 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (contents)((((GtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((contents)), ((gtk_text_view_get_type ()))))))
,
208 GTK_WRAP_WORD);
209
210 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
,
211 contents);
212
213 /* Create statusbar */
214
215 statusbar = gtk_statusbar_new ();
216 gtk_widget_set_hexpand (statusbar, TRUE(!(0)));
217 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
218 statusbar,
219 0, 3, 1, 1);
220
221 gtk_widget_show_all (grid);
222
223 g_object_unref (builder);
224
225 return grid;
226}
227
228static void
229update_spacings (GtkWidget *vbox,
230 GtkWidget *action_area)
231{
232 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 2);
233 gtk_box_set_spacing (GTK_BOX (action_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_box_get_type ()))))))
, 10);
234 gtk_container_set_border_width (GTK_CONTAINER (action_area)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_container_get_type ()))))))
, 5);
235}
236
237static GtkWidget*
238dialog_contents (void)
239{
240 GtkWidget *vbox;
241 GtkWidget *hbox;
242 GtkWidget *action_area;
243 GtkWidget *label;
244 GtkWidget *image;
245 GtkWidget *button;
246
247 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
248
249 action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
250
251 gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area)((((GtkButtonBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_button_box_get_type ()))))))
,
252 GTK_BUTTONBOX_END);
253
254 button = gtk_button_new_with_mnemonic (_("_OK")gettext ("_OK"));
255 gtk_button_set_image (GTK_BUTTON (button)((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((gtk_button_get_type ()))))))
, gtk_image_new_from_icon_name ("gtk-ok", GTK_ICON_SIZE_BUTTON));
256
257 gtk_box_pack_end (GTK_BOX (action_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_box_get_type ()))))))
,
258 button,
259 FALSE(0), TRUE(!(0)), 0);
260
261 gtk_box_pack_end (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, action_area,
262 FALSE(0), TRUE(!(0)), 0);
263
264 update_spacings (vbox, action_area);
265
266 label = gtk_label_new (_("This is a sample message in a sample dialog")gettext ("This is a sample message in a sample dialog"));
267 image = gtk_image_new_from_icon_name ("dialog-information",
268 GTK_ICON_SIZE_DIALOG);
269 gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
270 gtk_widget_set_valign (image, GTK_ALIGN_START);
271
272 gtk_label_set_line_wrap (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
273 gtk_label_set_selectable (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
274
275 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
276
277 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, image,
278 FALSE(0), FALSE(0), 0);
279
280 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, label,
281 TRUE(!(0)), TRUE(!(0)), 0);
282
283 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
,
284 hbox,
285 FALSE(0), FALSE(0), 0);
286
287 gtk_widget_show_all (vbox);
288
289 return vbox;
290}
291
292static GtkWidget*
293utility_contents (void)
294{
295 GtkWidget *grid;
296 GtkWidget *button;
297 int i, j;
298
299 grid = gtk_grid_new ();
300
301 i = 0;
302 while (i < 3)
303 {
304 j = 0;
305 while (j < 4)
306 {
307 char *str;
308
309 str = g_strdup_printf ("_%c", (char) ('A' + 4*i + j));
310
311 button = gtk_button_new_with_mnemonic (str);
312
313 g_free (str);
314
315 gtk_widget_set_hexpand (button, TRUE(!(0)));
316 gtk_widget_set_vexpand (button, TRUE(!(0)));
317
318 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
319 button,
320 i, j, 1, 1);
321
322 ++j;
323 }
324
325 ++i;
326 }
327
328 gtk_widget_show_all (grid);
329
330 return grid;
331}
332
333static GtkWidget*
334menu_contents (void)
335{
336 GtkWidget *vbox;
337 GtkWidget *mi;
338 int i;
339 GtkWidget *frame;
340
341 frame = gtk_frame_new (NULL((void*)0));
342 gtk_frame_set_shadow_type (GTK_FRAME (frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_frame_get_type ()))))))
,
343 GTK_SHADOW_OUT);
344
345 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
346
347 i = 0;
348 while (i < 10)
349 {
350 char *str = g_strdup_printf (_("Fake menu item %d\n")gettext ("Fake menu item %d\n"), i + 1);
351 mi = gtk_label_new (str);
352 gtk_widget_set_halign (mi, GTK_ALIGN_START);
353 gtk_widget_set_valign (mi, GTK_ALIGN_CENTER);
354 g_free (str);
355 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, mi, FALSE(0), FALSE(0), 0);
356
357 ++i;
358 }
359
360 gtk_container_add (GTK_CONTAINER (frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_container_get_type ()))))))
, vbox);
361
362 gtk_widget_show_all (frame);
363
364 return frame;
365}
366
367static void
368override_background_color (GtkWidget *widget,
369 GdkRGBA *rgba)
370{
371 gchar *css;
372 GtkCssProvider *provider;
373
374 provider = gtk_css_provider_new ();
375
376 css = g_strdup_printf ("* { background-color: %s; }",
377 gdk_rgba_to_string (rgba));
378 gtk_css_provider_load_from_data (provider, css, -1, NULL((void*)0));
379 g_free (css);
380
381 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
382 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
383 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
384 g_object_unref (provider);
385}
386
387static GtkWidget*
388border_only_contents (void)
389{
390 GtkWidget *event_box;
391 GtkWidget *vbox;
392 GtkWidget *w;
393 GdkRGBA color;
394
395 event_box = gtk_event_box_new ();
396
397 color.red = 0.6;
398 color.green = 0;
399 color.blue = 0.6;
400 color.alpha = 1.0;
401 override_background_color (event_box, &color);
402
403 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
404 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 3);
405
406 w = gtk_label_new (_("Border-only window")gettext ("Border-only window"));
407 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, w, FALSE(0), FALSE(0), 0);
408 w = gtk_button_new_with_label (_("Bar")gettext ("Bar"));
409 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, w, FALSE(0), FALSE(0), 0);
410
411 gtk_container_add (GTK_CONTAINER (event_box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((event_box)), ((gtk_container_get_type ()))))))
, vbox);
412
413 gtk_widget_show_all (event_box);
414
415 return event_box;
416}
417
418static GtkWidget*
419get_window_contents (MetaFrameType type,
420 const char **title)
421{
422 switch (type)
423 {
424 case META_FRAME_TYPE_NORMAL:
425 *title = _("Normal Application Window")gettext ("Normal Application Window");
426 return normal_contents ();
427
428 case META_FRAME_TYPE_DIALOG:
429 *title = _("Dialog Box")gettext ("Dialog Box");
430 return dialog_contents ();
431
432 case META_FRAME_TYPE_MODAL_DIALOG:
433 *title = _("Modal Dialog Box")gettext ("Modal Dialog Box");
434 return dialog_contents ();
435
436 case META_FRAME_TYPE_UTILITY:
437 *title = _("Utility Palette")gettext ("Utility Palette");
438 return utility_contents ();
439
440 case META_FRAME_TYPE_MENU:
441 *title = _("Torn-off Menu")gettext ("Torn-off Menu");
442 return menu_contents ();
443
444 case META_FRAME_TYPE_BORDER:
445 *title = _("Border")gettext ("Border");
446 return border_only_contents ();
447
448 case META_FRAME_TYPE_ATTACHED:
449 *title = _("Attached Modal Dialog")gettext ("Attached Modal Dialog");
450 return dialog_contents ();
451
452 case META_FRAME_TYPE_LAST:
453 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme-viewer.c", 453
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
454 break;
455 }
456
457 return NULL((void*)0);
458}
459
460static MetaFrameFlags
461get_window_flags (MetaFrameType type)
462{
463 MetaFrameFlags flags;
464
465 flags = META_FRAME_ALLOWS_DELETE |
466 META_FRAME_ALLOWS_MENU |
467 META_FRAME_ALLOWS_MINIMIZE |
468 META_FRAME_ALLOWS_MAXIMIZE |
469 META_FRAME_ALLOWS_VERTICAL_RESIZE |
470 META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
471 META_FRAME_HAS_FOCUS |
472 META_FRAME_ALLOWS_SHADE |
473 META_FRAME_ALLOWS_MOVE;
474
475 switch (type)
476 {
477 case META_FRAME_TYPE_NORMAL:
478 break;
479
480 case META_FRAME_TYPE_DIALOG:
481 case META_FRAME_TYPE_MODAL_DIALOG:
482 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
483 META_FRAME_ALLOWS_MAXIMIZE);
484 break;
485
486 case META_FRAME_TYPE_UTILITY:
487 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
488 META_FRAME_ALLOWS_MAXIMIZE);
489 break;
490
491 case META_FRAME_TYPE_MENU:
492 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
493 META_FRAME_ALLOWS_MAXIMIZE);
494 break;
495
496 case META_FRAME_TYPE_BORDER:
497 break;
498
499 case META_FRAME_TYPE_ATTACHED:
500 break;
501
502 case META_FRAME_TYPE_LAST:
503 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme-viewer.c", 503
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
504 break;
505 }
506
507 return flags;
508}
509
510static void
511override_font (GtkWidget *widget,
512 const gchar *font)
513{
514 gchar *css;
515 GtkCssProvider *provider;
516
517 provider = gtk_css_provider_new ();
518
519 css = g_strdup_printf ("* { font: %s; }", font);
520 gtk_css_provider_load_from_data (provider, css, -1, NULL((void*)0));
521 g_free (css);
522
523 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
524 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
525 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
526 g_object_unref (provider);
527}
528
529static GtkWidget*
530preview_collection (int font_size,
531 const PangoFontDescription *base_desc)
532{
533 GtkWidget *box;
534 GtkWidget *sw;
535 GdkRGBA desktop_color;
536 int i;
537 GtkWidget *eventbox;
538
539 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
540 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
541 GTK_POLICY_AUTOMATIC,
542 GTK_POLICY_AUTOMATIC);
543
544 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
545 gtk_box_set_spacing (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, 20);
546 gtk_container_set_border_width (GTK_CONTAINER (box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_container_get_type ()))))))
, 20);
547
548 eventbox = gtk_event_box_new ();
549 gtk_container_add (GTK_CONTAINER (eventbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox)), ((gtk_container_get_type ()))))))
, box);
550
551 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
, eventbox);
552
553 GSimpleActionGroup *action_group = g_simple_action_group_new ();
554 g_action_map_add_action_entries (G_ACTION_MAP (action_group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), ((g_action_map_get_type ()))))))
,
555 theme_viewer_entries,
556 G_N_ELEMENTS (theme_viewer_entries)(sizeof (theme_viewer_entries) / sizeof ((theme_viewer_entries
)[0]))
,
557 NULL((void*)0));
558 gtk_widget_insert_action_group (sw, "theme-viewer", G_ACTION_GROUP (action_group)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), ((g_action_group_get_type ()))))))
);
559 g_object_unref (action_group);
560
561 desktop_color.red = 0.32;
562 desktop_color.green = 0.46;
563 desktop_color.blue = 0.65;
564 desktop_color.alpha = 1.0;
565
566 override_background_color (eventbox, &desktop_color);
567
568 i = 0;
569 while (i < META_FRAME_TYPE_LAST)
570 {
571 const char *title = NULL((void*)0);
572 GtkWidget *contents;
573 GtkAlign xalign, yalign;
574 GtkWidget *eventbox2;
575 GtkWidget *preview;
576 PangoFontDescription *font_desc;
577 gchar *font_string;
578 double scale;
579
580 eventbox2 = gtk_event_box_new ();
581
582 preview = meta_preview_new ();
583
584 gtk_container_add (GTK_CONTAINER (eventbox2)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox2)), ((gtk_container_get_type ()))))))
, preview);
585
586 meta_preview_set_frame_type (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, i);
587 meta_preview_set_frame_flags (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
,
588 get_window_flags (i));
589
590 meta_preview_set_theme (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, global_theme);
591
592 contents = get_window_contents (i, &title);
593
594 meta_preview_set_title (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, title);
595
596 gtk_container_add (GTK_CONTAINER (preview)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((gtk_container_get_type ()))))))
, contents);
597
598 if (i == META_FRAME_TYPE_MENU)
599 {
600 xalign = GTK_ALIGN_START;
601 yalign = GTK_ALIGN_START;
602 }
603 else
604 {
605 xalign = GTK_ALIGN_FILL;
606 yalign = GTK_ALIGN_FILL;
607 }
608
609 gtk_widget_set_halign (eventbox2, xalign);
610 gtk_widget_set_valign (eventbox2, yalign);
611
612 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, eventbox2, TRUE(!(0)), TRUE(!(0)), 0);
613
614 switch (font_size)
615 {
616 case FONT_SIZE_SMALL:
617 scale = PANGO_SCALE_XX_SMALL((double)0.5787037037037);
618 break;
619 case FONT_SIZE_LARGE:
620 scale = PANGO_SCALE_XX_LARGE((double)1.728);
621 break;
622 default:
623 scale = 1.0;
624 break;
625 }
626
627 if (scale != 1.0)
628 {
629 font_desc = pango_font_description_new ();
630
631 pango_font_description_set_size (font_desc,
632 MAX (pango_font_description_get_size (base_desc) * scale, 1)(((pango_font_description_get_size (base_desc) * scale) > (
1)) ? (pango_font_description_get_size (base_desc) * scale) :
(1))
);
633
634 font_string = pango_font_description_to_string (font_desc);
635 override_font (preview, font_string);
636 g_free (font_string);
637
638 pango_font_description_free (font_desc);
639 }
640
641 previews[font_size*META_FRAME_TYPE_LAST + i] = preview;
642
643 ++i;
644 }
645
646 return sw;
647}
648
649static MetaButtonLayout different_layouts[BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1)];
650
651static void
652init_layouts (void)
653{
654 int i;
655
656 /* Blank out all the layouts */
657 i = 0;
658 while (i < (int) G_N_ELEMENTS (different_layouts)(sizeof (different_layouts) / sizeof ((different_layouts)[0])
)
)
659 {
660 int j;
661
662 j = 0;
663 while (j < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
664 {
665 different_layouts[i].left_buttons[j] = META_BUTTON_FUNCTION_LAST;
666 different_layouts[i].right_buttons[j] = META_BUTTON_FUNCTION_LAST;
667 ++j;
668 }
669 ++i;
670 }
671
672#ifndef ALLOW_DUPLICATE_BUTTONS
673 i = 0;
674 while (i <= MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
675 {
676 int j;
677
678 j = 0;
679 while (j < i)
680 {
681 different_layouts[i].right_buttons[j] = (MetaButtonFunction) j;
682 ++j;
683 }
684 while (j < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
685 {
686 different_layouts[i].left_buttons[j-i] = (MetaButtonFunction) j;
687 ++j;
688 }
689
690 ++i;
691 }
692
693 /* Special extra case for no buttons on either side */
694 different_layouts[i].left_buttons[0] = META_BUTTON_FUNCTION_LAST;
695 different_layouts[i].right_buttons[0] = META_BUTTON_FUNCTION_LAST;
696
697#else
698 /* FIXME this code is if we allow duplicate buttons,
699 * which we currently do not
700 */
701 int left;
702 int i;
703
704 left = 0;
705 i = 0;
706
707 while (left < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
708 {
709 int right;
710
711 right = 0;
712
713 while (right < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
714 {
715 int j;
716
717 static MetaButtonFunction left_functions[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST] = {
718 META_BUTTON_FUNCTION_MENU,
719 META_BUTTON_FUNCTION_MINIMIZE,
720 META_BUTTON_FUNCTION_MAXIMIZE,
721 META_BUTTON_FUNCTION_CLOSE
722 };
723 static MetaButtonFunction right_functions[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST] = {
724 META_BUTTON_FUNCTION_MINIMIZE,
725 META_BUTTON_FUNCTION_MAXIMIZE,
726 META_BUTTON_FUNCTION_CLOSE,
727 META_BUTTON_FUNCTION_MENU
728 };
729
730 g_assert (i < BUTTON_LAYOUT_COMBINATIONS)do { if (i < (META_BUTTON_FUNCTION_LAST + 1 + 1)) ; else g_assertion_message_expr
("marco", "ui/theme-viewer.c", 730, ((const char*) (__func__
)), "i < BUTTON_LAYOUT_COMBINATIONS"); } while (0)
;
731
732 j = 0;
733 while (j <= left)
734 {
735 different_layouts[i].left_buttons[j] = left_functions[j];
736 ++j;
737 }
738
739 j = 0;
740 while (j <= right)
741 {
742 different_layouts[i].right_buttons[j] = right_functions[j];
743 ++j;
744 }
745
746 ++i;
747
748 ++right;
749 }
750
751 ++left;
752 }
753#endif
754}
755
756static GtkWidget*
757previews_of_button_layouts (void)
758{
759 static gboolean initted = FALSE(0);
760 GtkWidget *box;
761 GtkWidget *sw;
762 GdkRGBA desktop_color;
763 int i;
764 GtkWidget *eventbox;
765
766 if (!initted)
767 {
768 init_layouts ();
769 initted = TRUE(!(0));
770 }
771
772 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
773 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
774 GTK_POLICY_AUTOMATIC,
775 GTK_POLICY_AUTOMATIC);
776
777 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
778 gtk_box_set_spacing (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, 20);
779 gtk_container_set_border_width (GTK_CONTAINER (box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_container_get_type ()))))))
, 20);
780
781 eventbox = gtk_event_box_new ();
782 gtk_container_add (GTK_CONTAINER (eventbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox)), ((gtk_container_get_type ()))))))
, box);
783
784 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
, eventbox);
785
786 desktop_color.red = 0.32;
787 desktop_color.green = 0.46;
788 desktop_color.blue = 0.65;
789 desktop_color.alpha = 1.0;
790
791 override_background_color (eventbox, &desktop_color);
792
793 i = 0;
794 while (i < BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1))
795 {
796 GtkWidget *eventbox2;
797 GtkWidget *preview;
798 char *title;
799
800 eventbox2 = gtk_event_box_new ();
801
802 preview = meta_preview_new ();
803
804 gtk_container_add (GTK_CONTAINER (eventbox2)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox2)), ((gtk_container_get_type ()))))))
, preview);
805
806 meta_preview_set_theme (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, global_theme);
807
808 title = g_strdup_printf (_("Button layout test %d")gettext ("Button layout test %d"), i+1);
809 meta_preview_set_title (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, title);
810 g_free (title);
811
812 meta_preview_set_button_layout (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
,
813 &different_layouts[i]);
814
815 gtk_widget_set_halign (eventbox2, GTK_ALIGN_FILL);
816
817 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, eventbox2, TRUE(!(0)), TRUE(!(0)), 0);
818
819 previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + i] = preview;
820
821 ++i;
822 }
823
824 return sw;
825}
826
827static GtkWidget*
828benchmark_summary (void)
829{
830 char *msg;
831 GtkWidget *label;
832
833 msg = g_strdup_printf (_("%g milliseconds to draw one window frame")gettext ("%g milliseconds to draw one window frame"),
834 milliseconds_to_draw_frame);
835 label = gtk_label_new (msg);
836 g_free (msg);
837
838 return label;
839}
840
841int
842main (int argc, char **argv)
843{
844 GtkWidget *window;
845 GtkWidget *collection;
846 GtkStyleContext *style;
847 PangoFontDescription *font_desc;
848 GError *err;
849 clock_t start, end;
850 GtkWidget *notebook;
851 int i;
852
853 bindtextdomain (GETTEXT_PACKAGE"marco", MARCO_LOCALEDIR"/usr/local/share/locale");
854 textdomain(GETTEXT_PACKAGE"marco");
855 bind_textdomain_codeset(GETTEXT_PACKAGE"marco", "UTF-8");
856
857 gtk_init (&argc, &argv);
858
859 if (g_getenv ("MARCO_DEBUG") != NULL((void*)0))
860 {
861 meta_set_debugging (TRUE(!(0)));
862 meta_set_verbose (TRUE(!(0)));
863 }
864
865 start = clock ();
866 err = NULL((void*)0);
867 if (argc == 1)
868 global_theme = meta_theme_load ("ClearlooksRe", &err);
869 else if (argc == 2)
870 global_theme = meta_theme_load (argv[1], &err);
871 else
872 {
873 g_printerr (_("Usage: marco-theme-viewer [THEMENAME]\n")gettext ("Usage: marco-theme-viewer [THEMENAME]\n"));
874 exit (1);
875 }
876 end = clock ();
877
878 if (global_theme == NULL((void*)0))
879 {
880 g_printerr (_("Error loading theme: %s\n")gettext ("Error loading theme: %s\n"),
881 err->message);
882 g_error_free (err);
883 exit (1);
884 }
885
886 g_print (_("Loaded theme \"%s\" in %g seconds\n")gettext ("Loaded theme \"%s\" in %g seconds\n"),
887 global_theme->name,
888 (end - start) / (double) CLOCKS_PER_SEC((__clock_t) 1000000));
889
890 run_theme_benchmark ();
891
892 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
893 gtk_window_set_default_size (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
, 350, 350);
894
895 if (strcmp (global_theme->name, global_theme->readable_name)==0)
896 gtk_window_set_title (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
,
This statement is never executed
897 global_theme->readable_name);
898 else
899 {
900 /* The theme directory name is different from the name the theme
901 * gives itself within its file. Display both, directory name first.
902 */
903 gchar *title = g_strconcat (global_theme->name, " - ",
904 global_theme->readable_name,
905 NULL((void*)0));
906
907 gtk_window_set_title (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
,
908 title);
909
910 g_free (title);
911 }
912
913 g_signal_connect (G_OBJECT (window), "destroy",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((window)), (((GType) ((20) << (2)))
)))))), ("destroy"), (((GCallback) (gtk_main_quit))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
914 G_CALLBACK (gtk_main_quit), NULL)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((window)), (((GType) ((20) << (2)))
)))))), ("destroy"), (((GCallback) (gtk_main_quit))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
915
916 gtk_widget_realize (window);
917 style = gtk_widget_get_style_context (window);
918 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL,
919 GTK_STYLE_PROPERTY_FONT"font", &font_desc,
920 NULL((void*)0));
921
922 g_assert (style)do { if (style) ; else g_assertion_message_expr ("marco", "ui/theme-viewer.c"
, 922, ((const char*) (__func__)), "style"); } while (0)
;
923 g_assert (font_desc)do { if (font_desc) ; else g_assertion_message_expr ("marco",
"ui/theme-viewer.c", 923, ((const char*) (__func__)), "font_desc"
); } while (0)
;
924
925 notebook = gtk_notebook_new ();
926 gtk_container_add (GTK_CONTAINER (window)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_container_get_type ()))))))
, notebook);
927
928 collection = preview_collection (FONT_SIZE_NORMAL,
929 font_desc);
930 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
931 collection,
932 gtk_label_new (_("Normal Title Font")gettext ("Normal Title Font")));
933
934 collection = preview_collection (FONT_SIZE_SMALL,
935 font_desc);
936 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
937 collection,
938 gtk_label_new (_("Small Title Font")gettext ("Small Title Font")));
939
940 collection = preview_collection (FONT_SIZE_LARGE,
941 font_desc);
942 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
943 collection,
944 gtk_label_new (_("Large Title Font")gettext ("Large Title Font")));
945
946 collection = previews_of_button_layouts ();
947 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
948 collection,
949 gtk_label_new (_("Button Layouts")gettext ("Button Layouts")));
950
951 collection = benchmark_summary ();
952 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
953 collection,
954 gtk_label_new (_("Benchmark")gettext ("Benchmark")));
955
956 pango_font_description_free (font_desc);
957
958 i = 0;
959 while (i < (int) G_N_ELEMENTS (previews)(sizeof (previews) / sizeof ((previews)[0])))
960 {
961 /* preview widget likes to be realized before its size request.
962 * it's lame that way.
963 */
964 gtk_widget_realize (previews[i]);
965
966 ++i;
967 }
968
969 gtk_widget_show_all (window);
970
971 gtk_main ();
972
973 return 0;
974}
975
976static MetaFrameFlags
977get_flags (GtkWidget *widget)
978{
979 return META_FRAME_ALLOWS_DELETE |
980 META_FRAME_ALLOWS_MENU |
981 META_FRAME_ALLOWS_MINIMIZE |
982 META_FRAME_ALLOWS_MAXIMIZE |
983 META_FRAME_ALLOWS_VERTICAL_RESIZE |
984 META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
985 META_FRAME_HAS_FOCUS |
986 META_FRAME_ALLOWS_SHADE |
987 META_FRAME_ALLOWS_MOVE;
988}
989
990static int
991get_text_height (GtkWidget *widget)
992{
993 GtkStyleContext *style;
994 PangoFontDescription *font_desc;
995 int text_height;
996
997 style = gtk_widget_get_style_context (widget);
998 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL,
999 GTK_STYLE_PROPERTY_FONT"font", &font_desc,
1000 NULL((void*)0));
1001 text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget));
1002 pango_font_description_free (font_desc);
1003
1004 return text_height;
1005}
1006
1007static PangoLayout*
1008create_title_layout (GtkWidget *widget)
1009{
1010 PangoLayout *layout;
1011
1012 layout = gtk_widget_create_pango_layout (widget, _("Window Title Goes Here")gettext ("Window Title Goes Here"));
1013
1014 return layout;
1015}
1016
1017static void
1018run_theme_benchmark (void)
1019{
1020 GtkWidget* widget;
1021 cairo_surface_t *pixmap;
1022 cairo_t *cr;
1023 MetaFrameBorders borders;
1024 MetaButtonState button_states[META_BUTTON_TYPE_LAST] =
1025 {
1026 META_BUTTON_STATE_NORMAL,
1027 META_BUTTON_STATE_NORMAL,
1028 META_BUTTON_STATE_NORMAL,
1029 META_BUTTON_STATE_NORMAL
1030 };
1031 PangoLayout *layout;
1032 clock_t start;
1033 clock_t end;
1034 GTimer *timer;
1035 int i;
1036 MetaButtonLayout button_layout;
1037#define ITERATIONS 100
1038 int client_width;
1039 int client_height;
1040 int inc;
1041
1042 widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1043 gtk_widget_realize (widget);
1044
1045 meta_theme_get_frame_borders (global_theme,
1046 META_FRAME_TYPE_NORMAL,
1047 get_text_height (widget),
1048 get_flags (widget),
1049 &borders);
1050
1051 layout = create_title_layout (widget);
1052
1053 i = 0;
1054 while (i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
1055 {
1056 button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1057 button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1058 ++i;
1059 }
1060
1061 button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
1062
1063 button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
1064 button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
1065 button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
1066
1067 timer = g_timer_new ();
1068 start = clock ();
1069
1070 client_width = 50;
1071 client_height = 50;
1072 inc = 1000 / ITERATIONS; /* Increment to grow width/height,
1073 * eliminates caching effects.
1074 */
1075
1076 i = 0;
1077 while (i < ITERATIONS)
1078 {
1079 /* Creating the pixmap in the loop is right, since
1080 * GDK does the same with its double buffering.
1081 */
1082 pixmap = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
1083 CAIRO_CONTENT_COLOR,
1084 client_width + borders.total.left + borders.total.right,
1085 client_height + borders.total.top + borders.total.bottom);
1086 cr = cairo_create (pixmap);
1087
1088 meta_theme_draw_frame (global_theme,
1089 gtk_widget_get_style_context (widget),
1090 cr,
1091 META_FRAME_TYPE_NORMAL,
1092 get_flags (widget),
1093 client_width, client_height,
1094 layout,
1095 get_text_height (widget),
1096 &button_layout,
1097 button_states,
1098 meta_preview_get_mini_icon (),
1099 meta_preview_get_icon ());
1100
1101 cairo_destroy (cr);
1102 cairo_surface_destroy (pixmap);
1103
1104 ++i;
1105 client_width += inc;
1106 client_height += inc;
1107 }
1108
1109 end = clock ();
1110 g_timer_stop (timer);
1111
1112 milliseconds_to_draw_frame = (g_timer_elapsed (timer, NULL((void*)0)) / (double) ITERATIONS) * 1000;
1113
1114 g_print (_("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n")gettext ("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n"
)
,
1115 ITERATIONS,
1116 ((double)end - (double)start) / CLOCKS_PER_SEC((__clock_t) 1000000),
1117 (((double)end - (double)start) / CLOCKS_PER_SEC((__clock_t) 1000000) / (double) ITERATIONS) * 1000,
1118 g_timer_elapsed (timer, NULL((void*)0)),
1119 milliseconds_to_draw_frame);
1120
1121 g_timer_destroy (timer);
1122 g_object_unref (G_OBJECT (layout)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((layout)), (((GType) ((20) << (2))))))))
);
1123 gtk_widget_destroy (widget);
1124
1125#undef ITERATIONS
1126}
1127
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-658c39.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-658c39.html new file mode 100644 index 00000000..97d0ff24 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-658c39.html @@ -0,0 +1,3169 @@ + + + +core/prefs.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/prefs.c
Warning:line 1585, column 10
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name prefs.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/prefs.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco preferences */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7 * Copyright (C) 2006 Elijah Newren
8 * Copyright (C) 2008 Thomas Thurman
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26#include <config.h>
27#include <glib/gi18n-lib.h>
28
29#include "prefs.h"
30#include "ui.h"
31#include "util.h"
32#include <gdk/gdk.h>
33#include <gio/gio.h>
34#include <string.h>
35#include <stdlib.h>
36
37#define MAX_REASONABLE_WORKSPACES36 36
38
39#define MAX_COMMANDS(32 + 2) (32 + NUM_EXTRA_COMMANDS2)
40#define NUM_EXTRA_COMMANDS2 2
41#define SCREENSHOT_COMMAND_IDX((32 + 2) - 2) (MAX_COMMANDS(32 + 2) - 2)
42#define WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1) (MAX_COMMANDS(32 + 2) - 1)
43
44/* If you add a key, it needs updating in init() and in the GSettings
45 * notify listener and of course in the .gschema file.
46 *
47 * Keys which are handled by one of the unified handlers below are
48 * not given a name here, because the purpose of the unified handlers
49 * is that keys should be referred to exactly once.
50 */
51#define KEY_GENERAL_SCHEMA"org.mate.Marco.general" "org.mate.Marco.general"
52#define KEY_GENERAL_TITLEBAR_FONT"titlebar-font" "titlebar-font"
53#define KEY_GENERAL_NUM_WORKSPACES"num-workspaces" "num-workspaces"
54#define KEY_GENERAL_COMPOSITOR"compositing-manager" "compositing-manager"
55#define KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB"compositing-fast-alt-tab" "compositing-fast-alt-tab"
56#define KEY_GENERAL_CENTER_NEW_WINDOWS"center-new-windows" "center-new-windows"
57#define KEY_GENERAL_ICON_SIZE"icon-size" "icon-size"
58#define KEY_GENERAL_ALT_TAB_MAX_COLUMNS"alt-tab-max-columns" "alt-tab-max-columns"
59#define KEY_GENERAL_ALT_TAB_RAISE_WINDOWS"alt-tab-raise-windows" "alt-tab-raise-windows"
60#define KEY_GENERAL_ALT_TAB_EXPAND_TO_FIT_TITLE"alt-tab-expand-to-fit-title" "alt-tab-expand-to-fit-title"
61
62#define KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands" "org.mate.Marco.keybinding-commands"
63#define KEY_COMMAND_PREFIX"command-" "command-"
64
65#define KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings" "org.mate.Marco.global-keybindings"
66
67#define KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings" "org.mate.Marco.window-keybindings"
68
69#define KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names" "org.mate.Marco.workspace-names"
70#define KEY_WORKSPACE_NAME_PREFIX"name-" "name-"
71
72#define KEY_MATE_INTERFACE_SCHEMA"org.mate.interface" "org.mate.interface"
73#define KEY_MATE_INTERFACE_ACCESSIBILITY"accessibility" "accessibility"
74#define KEY_MATE_INTERFACE_ENABLE_ANIMATIONS"enable-animations" "enable-animations"
75
76#define KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal" "org.mate.applications-terminal"
77#define KEY_MATE_TERMINAL_COMMAND"exec" "exec"
78
79#define KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse" "org.mate.peripherals-mouse"
80#define KEY_MATE_MOUSE_CURSOR_THEME"cursor-theme" "cursor-theme"
81#define KEY_MATE_MOUSE_CURSOR_SIZE"cursor-size" "cursor-size"
82
83#define SETTINGS(s)g_hash_table_lookup (settings_schemas, (s)) g_hash_table_lookup (settings_schemas, (s))
84
85static GSettings *settings_general;
86static GSettings *settings_command;
87static GSettings *settings_screen_bindings;
88static GSettings *settings_window_bindings;
89static GSettings *settings_workspace_names;
90static GSettings *settings_mate_interface;
91static GSettings *settings_mate_terminal;
92static GSettings *settings_mate_mouse;
93static GHashTable *settings_schemas;
94
95static GList *changes = NULL((void*)0);
96static guint changed_idle;
97static GList *listeners = NULL((void*)0);
98
99static gboolean use_system_font = FALSE(0);
100static PangoFontDescription *titlebar_font = NULL((void*)0);
101static MetaVirtualModifier mouse_button_mods = Mod1Mask(1<<3);
102static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
103static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
104static gboolean raise_on_click = TRUE(!(0));
105static gboolean attach_modal_dialogs = FALSE(0);
106static char* current_theme = NULL((void*)0);
107static int num_workspaces = 4;
108static MetaWrapStyle wrap_style = META_WRAP_NONE;
109static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
110static MetaActionTitlebar action_middle_click_titlebar = META_ACTION_TITLEBAR_LOWER;
111static MetaActionTitlebar action_right_click_titlebar = META_ACTION_TITLEBAR_MENU;
112static gboolean application_based = FALSE(0);
113static gboolean disable_workarounds = FALSE(0);
114static gboolean auto_raise = FALSE(0);
115static gboolean auto_raise_delay = 500;
116static gboolean provide_visual_bell = FALSE(0);
117static gboolean bell_is_audible = TRUE(!(0));
118static gboolean reduced_resources = FALSE(0);
119static gboolean mate_accessibility = FALSE(0);
120static gboolean mate_animations = TRUE(!(0));
121static char *cursor_theme = NULL((void*)0);
122static int cursor_size = 24;
123static int icon_size = META_DEFAULT_ICON_SIZE48;
124static int alt_tab_max_columns = META_DEFAULT_ALT_TAB_MAX_COLUMNS5;
125static gboolean alt_tab_raise_windows = META_DEFAULT_ALT_TAB_RAISE_WINDOWS(0);
126static gboolean alt_tab_expand_to_fit_title = META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE(0);
127static gboolean use_force_compositor_manager = FALSE(0);
128static gboolean force_compositor_manager = FALSE(0);
129static gboolean compositing_manager = FALSE(0);
130static gboolean compositing_fast_alt_tab = FALSE(0);
131static gboolean resize_with_right_button = FALSE(0);
132static gboolean show_tab_border = FALSE(0);
133static gboolean center_new_windows = FALSE(0);
134static gboolean force_fullscreen = TRUE(!(0));
135static gboolean allow_tiling = FALSE(0);
136static gboolean allow_top_tiling = TRUE(!(0));
137static gboolean allow_tile_cycling = TRUE(!(0));
138static GList *show_desktop_skip_list = NULL((void*)0);
139
140static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
141static MetaButtonLayout button_layout;
142
143/* The screenshot commands are at the end */
144static char *commands[MAX_COMMANDS(32 + 2)] = { NULL((void*)0), };
145
146static char *terminal_command = NULL((void*)0);
147
148static char *workspace_names[MAX_REASONABLE_WORKSPACES36] = { NULL((void*)0), };
149
150static gboolean handle_preference_update_enum (const gchar *key, GSettings *settings);
151
152static gboolean update_key_binding (const char *name,
153 gchar *value);
154static gboolean update_command (const char *name,
155 const char *value);
156static gboolean update_workspace_name (const char *name,
157 const char *value);
158
159static void change_notify (GSettings *settings,
160 gchar *key,
161 gpointer user_data);
162
163static char* settings_key_for_workspace_name (int i);
164
165static void queue_changed (MetaPreference pref);
166
167#if 0
168static void cleanup_error (GError **error);
169#endif
170
171static void maybe_give_disable_workarounds_warning (void);
172
173static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
174static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
175static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
176static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
177static void show_desktop_skip_list_handler (MetaPreference, const gchar*, gboolean*);
178
179static gboolean update_binding (MetaKeyPref *binding,
180 gchar *value);
181
182static void init_bindings (GSettings *);
183static void init_screen_bindings (void);
184static void init_window_bindings (void);
185static void init_commands (void);
186static void init_workspace_names (void);
187
188static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_AUTOMATIC;
189
190typedef struct
191{
192 MetaPrefsChangedFunc func;
193 gpointer data;
194} MetaPrefsListener;
195
196/**
197 * The details of one preference which is constrained to be
198 * one of a small number of string values-- in other words,
199 * an enumeration.
200 *
201 * We could have done this other ways. One particularly attractive
202 * possibility would have been to represent the entire symbol table
203 * as a space-separated string literal in the list of symtabs, so
204 * the focus mode enums could have been represented simply by
205 * "click sloppy mouse". However, the simplicity gained would have
206 * been outweighed by the bugs caused when the ordering of the enum
207 * strings got out of sync with the actual enum statement. Also,
208 * there is existing library code to use this kind of symbol tables.
209 *
210 * Other things we might consider doing to clean this up in the
211 * future include:
212 *
213 * - most of the keys begin with the same prefix, and perhaps we
214 * could assume it if they don't start with a slash
215 *
216 * - there are several cases where a single identifier could be used
217 * to generate an entire entry, and perhaps this could be done
218 * with a macro. (This would reduce clarity, however, and is
219 * probably a bad thing.)
220 *
221 * - these types all begin with a gchar* (and contain a MetaPreference)
222 * and we can factor out the repeated code in the handlers by taking
223 * advantage of this using some kind of union arrangement.
224 */
225typedef struct
226{
227 gchar *key;
228 gchar *schema;
229 MetaPreference pref;
230 gint *target;
231} MetaEnumPreference;
232
233typedef struct
234{
235 gchar *key;
236 gchar *schema;
237 MetaPreference pref;
238 gboolean *target;
239 gboolean becomes_true_on_destruction;
240} MetaBoolPreference;
241
242typedef struct
243{
244 gchar *key;
245 gchar *schema;
246 MetaPreference pref;
247
248 /**
249 * A handler. Many of the string preferences aren't stored as
250 * strings and need parsing; others of them have default values
251 * which can't be solved in the general case. If you include a
252 * function pointer here, it will be called before the string
253 * value is written out to the target variable.
254 *
255 * The function is passed two arguments: the preference, and
256 * the new string as a gchar*. It returns a gboolean;
257 * only if this is true, the listeners will be informed that
258 * the preference has changed.
259 *
260 * This may be NULL. If it is, see "target", below.
261 */
262 void (*handler) (MetaPreference pref,
263 const gchar *string_value,
264 gboolean *inform_listeners);
265
266 /**
267 * Where to write the incoming string.
268 *
269 * This must be NULL if the handler is non-NULL.
270 * If the incoming string is NULL, no change will be made.
271 */
272 gchar **target;
273
274} MetaStringPreference;
275
276#define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY(-2147483647 -1) G_MININT(-2147483647 -1)
277
278typedef struct
279{
280 gchar *key;
281 gchar *schema;
282 MetaPreference pref;
283 gint *target;
284 /**
285 * Minimum and maximum values of the integer.
286 * If the new value is out of bounds, it will be discarded with a warning.
287 */
288 gint minimum, maximum;
289 /**
290 * Value to use if the key is destroyed.
291 * If this is METAINTPREFERENCE_NO_CHANGE_ON_DESTROY, it will
292 * not be changed when the key is destroyed.
293 */
294 gint value_if_destroyed;
295} MetaIntPreference;
296
297/* FIXMEs: */
298/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
299/* @@@ /apps/marco/general should be assumed if first char is not / */
300/* @@@ Will it ever be possible to merge init and update? If not, why not? */
301
302static MetaEnumPreference preferences_enum[] =
303 {
304 { "focus-new-windows",
305 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
306 META_PREF_FOCUS_NEW_WINDOWS,
307 (gint *) &focus_new_windows,
308 },
309 { "focus-mode",
310 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
311 META_PREF_FOCUS_MODE,
312 (gint *) &focus_mode,
313 },
314 { "wrap-style",
315 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
316 META_PREF_WRAP_STYLE,
317 (gint *) &wrap_style,
318 },
319 { "visual-bell-type",
320 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
321 META_PREF_VISUAL_BELL_TYPE,
322 (gint *) &visual_bell_type,
323 },
324 { "action-double-click-titlebar",
325 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
326 META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
327 (gint *) &action_double_click_titlebar,
328 },
329 { "action-middle-click-titlebar",
330 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
331 META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
332 (gint *) &action_middle_click_titlebar,
333 },
334 { "action-right-click-titlebar",
335 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
336 META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
337 (gint *) &action_right_click_titlebar,
338 },
339 { "placement-mode",
340 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
341 META_PREF_PLACEMENT_MODE,
342 (gint *) &placement_mode,
343 },
344 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0) },
345 };
346
347static MetaBoolPreference preferences_bool[] =
348 {
349 { "raise-on-click",
350 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
351 META_PREF_RAISE_ON_CLICK,
352 &raise_on_click,
353 TRUE(!(0)),
354 },
355 { "titlebar-uses-system-font",
356 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
357 META_PREF_TITLEBAR_FONT, /* note! shares a pref */
358 &use_system_font,
359 TRUE(!(0)),
360 },
361 { "application-based",
362 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
363 META_PREF_APPLICATION_BASED,
364 NULL((void*)0), /* feature is known but disabled */
365 FALSE(0),
366 },
367 { "disable-workarounds",
368 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
369 META_PREF_DISABLE_WORKAROUNDS,
370 &disable_workarounds,
371 FALSE(0),
372 },
373 { "auto-raise",
374 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
375 META_PREF_AUTO_RAISE,
376 &auto_raise,
377 FALSE(0),
378 },
379 { "visual-bell",
380 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
381 META_PREF_VISUAL_BELL,
382 &provide_visual_bell, /* FIXME: change the name: it's confusing */
383 FALSE(0),
384 },
385 { "audible-bell",
386 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
387 META_PREF_AUDIBLE_BELL,
388 &bell_is_audible, /* FIXME: change the name: it's confusing */
389 FALSE(0),
390 },
391 { "reduced-resources",
392 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
393 META_PREF_REDUCED_RESOURCES,
394 &reduced_resources,
395 FALSE(0),
396 },
397 { "accessibility",
398 KEY_MATE_INTERFACE_SCHEMA"org.mate.interface",
399 META_PREF_MATE_ACCESSIBILITY,
400 &mate_accessibility,
401 FALSE(0),
402 },
403 { "enable-animations",
404 KEY_MATE_INTERFACE_SCHEMA"org.mate.interface",
405 META_PREF_MATE_ANIMATIONS,
406 &mate_animations,
407 TRUE(!(0)),
408 },
409 { KEY_GENERAL_COMPOSITOR"compositing-manager",
410 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
411 META_PREF_COMPOSITING_MANAGER,
412 &compositing_manager,
413 FALSE(0),
414 },
415 { "compositing-fast-alt-tab",
416 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
417 META_PREF_COMPOSITING_FAST_ALT_TAB,
418 &compositing_fast_alt_tab,
419 FALSE(0),
420 },
421 { "resize-with-right-button",
422 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
423 META_PREF_RESIZE_WITH_RIGHT_BUTTON,
424 &resize_with_right_button,
425 FALSE(0),
426 },
427 { "show-tab-border",
428 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
429 META_PREF_SHOW_TAB_BORDER,
430 &show_tab_border,
431 FALSE(0),
432 },
433 { "center-new-windows",
434 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
435 META_PREF_CENTER_NEW_WINDOWS,
436 &center_new_windows,
437 FALSE(0),
438 },
439 { "allow-tiling",
440 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
441 META_PREF_ALLOW_TILING,
442 &allow_tiling,
443 FALSE(0),
444 },
445 { "allow-top-tiling",
446 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
447 META_PREF_ALLOW_TOP_TILING,
448 &allow_top_tiling,
449 FALSE(0),
450 },
451 { "allow-tile-cycling",
452 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
453 META_PREF_ALLOW_TILE_CYCLING,
454 &allow_tile_cycling,
455 FALSE(0),
456 },
457 { "alt-tab-expand-to-fit-title",
458 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
459 META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE,
460 &alt_tab_expand_to_fit_title,
461 META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE(0),
462 },
463 { "alt-tab-raise-windows",
464 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
465 META_PREF_ALT_TAB_RAISE_WINDOWS,
466 &alt_tab_raise_windows,
467 META_DEFAULT_ALT_TAB_RAISE_WINDOWS(0),
468 },
469 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), FALSE(0) },
470 };
471
472static MetaStringPreference preferences_string[] =
473 {
474 { "mouse-button-modifier",
475 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
476 META_PREF_MOUSE_BUTTON_MODS,
477 mouse_button_mods_handler,
478 NULL((void*)0),
479 },
480 { "theme",
481 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
482 META_PREF_THEME,
483 theme_name_handler,
484 NULL((void*)0),
485 },
486 { KEY_GENERAL_TITLEBAR_FONT"titlebar-font",
487 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
488 META_PREF_TITLEBAR_FONT,
489 titlebar_handler,
490 NULL((void*)0),
491 },
492 { KEY_MATE_TERMINAL_COMMAND"exec",
493 KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal",
494 META_PREF_TERMINAL_COMMAND,
495 NULL((void*)0),
496 &terminal_command,
497 },
498 { "button-layout",
499 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
500 META_PREF_BUTTON_LAYOUT,
501 button_layout_handler,
502 NULL((void*)0),
503 },
504 { "cursor-theme",
505 KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse",
506 META_PREF_CURSOR_THEME,
507 NULL((void*)0),
508 &cursor_theme,
509 },
510 { "show-desktop-skip-list",
511 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
512 META_PREF_SHOW_DESKTOP_SKIP_LIST,
513 &show_desktop_skip_list_handler,
514 NULL((void*)0),
515 },
516 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), NULL((void*)0) },
517 };
518
519static MetaIntPreference preferences_int[] =
520 {
521 { "num-workspaces",
522 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
523 META_PREF_NUM_WORKSPACES,
524 &num_workspaces,
525 /* I would actually recommend we change the destroy value to 4
526 * and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
527 * -- tthurman
528 */
529 1, MAX_REASONABLE_WORKSPACES36, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY(-2147483647 -1),
530 },
531 { "auto-raise-delay",
532 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
533 META_PREF_AUTO_RAISE_DELAY,
534 &auto_raise_delay,
535 0, 10000, 0,
536 /* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
537 },
538 { "cursor-size",
539 KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse",
540 META_PREF_CURSOR_SIZE,
541 &cursor_size,
542 1, 128, 24,
543 },
544 { "icon-size",
545 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
546 META_PREF_ICON_SIZE,
547 &icon_size,
548 META_MIN_ICON_SIZE8, META_MAX_ICON_SIZE256, META_DEFAULT_ICON_SIZE48,
549 },
550 { "alt-tab-max-columns",
551 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
552 META_PREF_ALT_TAB_MAX_COLUMNS,
553 &alt_tab_max_columns,
554 META_MIN_ALT_TAB_MAX_COLUMNS1,
555 META_MAX_ALT_TAB_MAX_COLUMNS64,
556 META_DEFAULT_ALT_TAB_MAX_COLUMNS5,
557 },
558 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), 0, 0, 0, },
559 };
560
561static void
562handle_preference_init_enum (void)
563{
564 MetaEnumPreference *cursor = preferences_enum;
565
566 while (cursor->key!=NULL((void*)0))
567 {
568 gint value;
569
570 if (cursor->target==NULL((void*)0))
571 {
572 ++cursor;
573 continue;
574 }
575
576 value = g_settings_get_enum (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
577 cursor->key);
578 *cursor->target = value;
579
580 ++cursor;
581 }
582}
583
584static void
585handle_preference_init_bool (void)
586{
587 MetaBoolPreference *cursor = preferences_bool;
588
589 while (cursor->key!=NULL((void*)0))
590 {
591 if (cursor->target!=NULL((void*)0))
592 *cursor->target = g_settings_get_boolean (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)), cursor->key);
593
594 ++cursor;
595 }
596
597 maybe_give_disable_workarounds_warning ();
598}
599
600static void
601handle_preference_init_string (void)
602{
603 MetaStringPreference *cursor = preferences_string;
604
605 while (cursor->key!=NULL((void*)0))
606 {
607 gchar *value;
608 gboolean dummy = TRUE(!(0));
609
610 /* the string "value" will be newly allocated */
611 value = g_settings_get_string (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
612 cursor->key);
613
614 if (cursor->handler)
615 {
616 if (cursor->target)
617 meta_bug ("%s has both a target and a handler\n", cursor->key);
618
619 cursor->handler (cursor->pref, value, &dummy);
620
621 g_free (value);
622 }
623 else if (cursor->target)
624 {
625 if (*(cursor->target))
626 g_free (*(cursor->target));
627
628 *(cursor->target) = value;
629 }
630
631 ++cursor;
632 }
633}
634
635static void
636handle_preference_init_int (void)
637{
638 MetaIntPreference *cursor = preferences_int;
639
640 while (cursor->key!=NULL((void*)0))
641 {
642 gint value;
643
644 value = g_settings_get_int (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
645 cursor->key);
646
647 if (value < cursor->minimum || value > cursor->maximum)
648 {
649 /* FIXME: check if this can be avoided by GSettings */
650 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n")((char *) g_dgettext ("marco", "%d stored in GSettings key %s is out of range %d to %d\n"
))
,
651 value, cursor->key, cursor->minimum, cursor->maximum);
652 /* Former behaviour for out-of-range values was:
653 * - number of workspaces was clamped;
654 * - auto raise delay was always reset to zero even if too high!;
655 * - cursor size was ignored.
656 *
657 * These seem to be meaningless variations. If they did
658 * have meaning we could have put them into MetaIntPreference.
659 * The last of these is the closest to how we behave for
660 * other types, so I think we should standardise on that.
661 */
662 }
663 else if (cursor->target)
664 *cursor->target = value;
665
666 ++cursor;
667 }
668}
669
670static gboolean
671handle_preference_update_enum (const gchar *key, GSettings *settings)
672{
673 MetaEnumPreference *cursor = preferences_enum;
674 gint old_value;
675
676 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
677 ++cursor;
678
679 if (cursor->key==NULL((void*)0))
680 /* Didn't recognise that key. */
681 return FALSE(0);
682
683 /* We need to know whether the value changes, so
684 * store the current value away.
685 */
686
687 old_value = * ((gint *) cursor->target);
688
689 /* Now look it up... */
690 *cursor->target = g_settings_get_enum (settings, key);
691
692 /* Did it change? If so, tell the listeners about it. */
693
694 if (old_value != *((gint *) cursor->target))
695 queue_changed (cursor->pref);
696
697 return TRUE(!(0));
698}
699
700static gboolean
701handle_preference_update_bool (const gchar *key, GSettings *settings)
702{
703 MetaBoolPreference *cursor = preferences_bool;
704 gboolean old_value;
705
706 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
707 ++cursor;
708
709 if (cursor->key==NULL((void*)0))
710 /* Didn't recognise that key. */
711 return FALSE(0);
712
713 if (cursor->target==NULL((void*)0))
714 /* No work for us to do. */
715 return TRUE(!(0));
716
717 /* We need to know whether the value changes, so
718 * store the current value away.
719 */
720
721 old_value = * ((gboolean *) cursor->target);
722
723 /* Now look it up... */
724
725 *((gboolean *) cursor->target) = g_settings_get_boolean (settings, key);
726
727 /* Did it change? If so, tell the listeners about it. */
728
729 if (old_value != *((gboolean *) cursor->target))
730 queue_changed (cursor->pref);
731
732 if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
733 maybe_give_disable_workarounds_warning ();
734
735 return TRUE(!(0));
736}
737
738static gboolean
739handle_preference_update_string (const gchar *key, GSettings *settings)
740{
741 MetaStringPreference *cursor = preferences_string;
742 gchar *value;
743 gboolean inform_listeners = TRUE(!(0));
744
745 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
746 ++cursor;
747
748 if (cursor->key==NULL((void*)0))
749 /* Didn't recognise that key. */
750 return FALSE(0);
751
752 value = g_settings_get_string (settings, key);
753
754 if (cursor->handler)
755 cursor->handler (cursor->pref, value, &inform_listeners);
756 else if (cursor->target)
757 {
758 if (*(cursor->target))
759 g_free(*(cursor->target));
760
761 if (value!=NULL((void*)0))
762 *(cursor->target) = g_strdup (value)g_strdup_inline (value);
763 else
764 *(cursor->target) = NULL((void*)0);
765
766 inform_listeners =
767 (value==NULL((void*)0) && *(cursor->target)==NULL((void*)0)) ||
768 (value!=NULL((void*)0) && *(cursor->target)!=NULL((void*)0) &&
769 strcmp (value, *(cursor->target))==0);
770 }
771
772 if (inform_listeners)
773 queue_changed (cursor->pref);
774
775 g_free (value);
776
777 return TRUE(!(0));
778}
779
780static gboolean
781handle_preference_update_int (const gchar *key, GSettings *settings)
782{
783 MetaIntPreference *cursor = preferences_int;
784 gint value;
785
786 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
787 ++cursor;
788
789 if (cursor->key==NULL((void*)0))
790 /* Didn't recognise that key. */
791 return FALSE(0);
792
793 if (cursor->target==NULL((void*)0))
794 /* No work for us to do. */
795 return TRUE(!(0));
796
797 value = g_settings_get_int (settings, key);
798
799 if (value < cursor->minimum || value > cursor->maximum)
800 {
801 /* FIXME! GSettings, instead of MateConf, has Minimum/Maximun in schema!
802 * But some preferences depends on costants for minimum/maximum values */
803 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n")((char *) g_dgettext ("marco", "%d stored in GSettings key %s is out of range %d to %d\n"
))
,
804 value, cursor->key,
805 cursor->minimum, cursor->maximum);
806 return TRUE(!(0));
807 }
808
809 /* Did it change? If so, tell the listeners about it. */
810
811 if (*cursor->target != value)
812 {
813 *cursor->target = value;
814 queue_changed (cursor->pref);
815 }
816
817 return TRUE(!(0));
818
819}
820
821/****************************************************************************/
822/* Listeners. */
823/****************************************************************************/
824
825void
826meta_prefs_add_listener (MetaPrefsChangedFunc func,
827 gpointer data)
828{
829 MetaPrefsListener *l;
830
831 l = g_new (MetaPrefsListener, 1)((MetaPrefsListener *) g_malloc_n ((1), sizeof (MetaPrefsListener
)))
;
832 l->func = func;
833 l->data = data;
834
835 listeners = g_list_prepend (listeners, l);
836}
837
838void
839meta_prefs_remove_listener (MetaPrefsChangedFunc func,
840 gpointer data)
841{
842 GList *tmp;
843
844 tmp = listeners;
845 while (tmp != NULL((void*)0))
846 {
847 MetaPrefsListener *l = tmp->data;
848
849 if (l->func == func &&
850 l->data == data)
851 {
852 g_free (l);
853 listeners = g_list_delete_link (listeners, tmp);
854
855 return;
856 }
857
858 tmp = tmp->next;
859 }
860
861 meta_bug ("Did not find listener to remove\n");
862}
863
864static void
865emit_changed (MetaPreference pref)
866{
867 GList *tmp;
868 GList *copy;
869
870 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
871 meta_preference_to_string (pref));
872
873 copy = g_list_copy (listeners);
874
875 tmp = copy;
876
877 while (tmp != NULL((void*)0))
878 {
879 MetaPrefsListener *l = tmp->data;
880
881 (* l->func) (pref, l->data);
882
883 tmp = tmp->next;
884 }
885
886 g_list_free (copy);
887}
888
889static gboolean
890changed_idle_handler (gpointer data)
891{
892 GList *tmp;
893 GList *copy;
894
895 changed_idle = 0;
896
897 copy = g_list_copy (changes); /* reentrancy paranoia */
898
899 g_list_free (changes);
900 changes = NULL((void*)0);
901
902 tmp = copy;
903 while (tmp != NULL((void*)0))
904 {
905 MetaPreference pref = GPOINTER_TO_INT (tmp->data)((gint) (glong) (tmp->data));
906
907 emit_changed (pref);
908
909 tmp = tmp->next;
910 }
911
912 g_list_free (copy);
913
914 return FALSE(0);
915}
916
917static void
918queue_changed (MetaPreference pref)
919{
920 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Queueing change of pref %s\n",
921 meta_preference_to_string (pref));
922
923 if (g_list_find (changes, GINT_TO_POINTER (pref)((gpointer) (glong) (pref))) == NULL((void*)0))
924 changes = g_list_prepend (changes, GINT_TO_POINTER (pref)((gpointer) (glong) (pref)));
925 else
926 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
927 meta_preference_to_string (pref));
928
929 /* add idle at priority below the GSettings notify idle */
930 /* FIXME is this needed for GSettings too? */
931 if (changed_idle == 0)
932 changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY(200 + 10),
933 changed_idle_handler, NULL((void*)0), NULL((void*)0));
934}
935
936/****************************************************************************/
937/* Initialisation. */
938/****************************************************************************/
939
940void
941meta_prefs_init (void)
942{
943 if (settings_general != NULL((void*)0))
944 return;
945
946 /* returns references which we hold forever */
947 settings_general = g_settings_new (KEY_GENERAL_SCHEMA"org.mate.Marco.general");
948 settings_command = g_settings_new (KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands");
949 settings_screen_bindings = g_settings_new (KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings");
950 settings_window_bindings = g_settings_new (KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings");
951 settings_workspace_names = g_settings_new (KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names");
952 settings_mate_interface = g_settings_new (KEY_MATE_INTERFACE_SCHEMA"org.mate.interface");
953 settings_mate_terminal = g_settings_new (KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal");
954 settings_mate_mouse = g_settings_new (KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse");
955
956 settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal, NULL((void*)0), g_object_unref);
957 g_hash_table_insert (settings_schemas, KEY_GENERAL_SCHEMA"org.mate.Marco.general", settings_general);
958 g_hash_table_insert (settings_schemas, KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands", settings_command);
959 g_hash_table_insert (settings_schemas, KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings", settings_screen_bindings);
960 g_hash_table_insert (settings_schemas, KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings", settings_window_bindings);
961 g_hash_table_insert (settings_schemas, KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names", settings_workspace_names);
962 g_hash_table_insert (settings_schemas, KEY_MATE_INTERFACE_SCHEMA"org.mate.interface", settings_mate_interface);
963 g_hash_table_insert (settings_schemas, KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal", settings_mate_terminal);
964 g_hash_table_insert (settings_schemas, KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse", settings_mate_mouse);
965
966 g_signal_connect (settings_general, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_general), ("changed"), (((GCallback
) (change_notify))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
967 g_signal_connect (settings_command, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_command), ("changed"), (((GCallback
) (change_notify))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
968 g_signal_connect (settings_screen_bindings, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_screen_bindings), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
969 g_signal_connect (settings_window_bindings, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_window_bindings), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
970 g_signal_connect (settings_workspace_names, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_workspace_names), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
971
972 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ACCESSIBILITY, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_interface), ("changed::"
"accessibility"), (((GCallback) (change_notify))), (((void*)
0)), ((void*)0), (GConnectFlags) 0)
;
973 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ENABLE_ANIMATIONS, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_interface), ("changed::"
"enable-animations"), (((GCallback) (change_notify))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
974 g_signal_connect (settings_mate_terminal, "changed::" KEY_MATE_TERMINAL_COMMAND, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_terminal), ("changed::"
"exec"), (((GCallback) (change_notify))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
975 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_THEME, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_mouse), ("changed::" "cursor-theme"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
976 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_SIZE, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_mouse), ("changed::" "cursor-size"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
977
978 /* Pick up initial values. */
979
980 handle_preference_init_enum ();
981 handle_preference_init_bool ();
982 handle_preference_init_string ();
983 handle_preference_init_int ();
984
985 init_screen_bindings ();
986 init_window_bindings ();
987 init_commands ();
988 init_workspace_names ();
989}
990
991/****************************************************************************/
992/* Updates. */
993/****************************************************************************/
994
995gboolean (*preference_update_handler[]) (const gchar*, GSettings*) = {
996 handle_preference_update_enum,
997 handle_preference_update_bool,
998 handle_preference_update_string,
999 handle_preference_update_int,
1000 NULL((void*)0)
1001};
1002
1003static void
1004change_notify (GSettings *settings,
1005 gchar *key,
1006 gpointer user_data)
1007{
1008 gint i=0;
1009
1010 /* First, search for a handler that might know what to do. */
1011
1012 /* FIXME: When this is all working, since the first item in every
1013 * array is the gchar* of the key, there's no reason we can't
1014 * find the correct record for that key here and save code duplication.
1015 */
1016
1017 while (preference_update_handler[i]!=NULL((void*)0))
1018 {
1019 if (preference_update_handler[i] (key, settings))
1020 return; /* Get rid of this eventually */
1021
1022 i++;
1023 }
1024
1025 gchar *schema_name = NULL((void*)0);
1026 g_object_get (settings, "schema-id", &schema_name, NULL((void*)0));
1027
1028 if (g_strcmp0 (schema_name, KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings") == 0 ||
1029 g_strcmp0 (schema_name, KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings") == 0)
1030 {
1031 gchar *str;
1032 str = g_settings_get_string (settings, key);
1033
1034 if (update_key_binding (key, str))
1035 queue_changed (META_PREF_KEYBINDINGS);
1036
1037 g_free(str);
1038 }
1039 else if (g_strcmp0 (schema_name, KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands") == 0)
1040 {
1041 gchar *str;
1042 str = g_settings_get_string (settings, key);
1043
1044 if (update_command (key, str))
1045 queue_changed (META_PREF_COMMANDS);
1046
1047 g_free(str);
1048 }
1049 else if (g_strcmp0 (schema_name, KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names") == 0)
1050 {
1051 gchar *str;
1052 str = g_settings_get_string (settings, key);
1053
1054 if (update_workspace_name (key, str))
1055 queue_changed (META_PREF_WORKSPACE_NAMES);
1056
1057 g_free(str);
1058 }
1059 else
1060 {
1061 /* Is this possible with GSettings? I dont think so! */
1062 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Key %s doesn't mean anything to Marco\n",
1063 key);
1064 }
1065 g_free (schema_name);
1066}
1067
1068#if 0
1069static void
1070cleanup_error (GError **error)
1071{
1072 if (*error)
1073 {
1074 meta_warning ("%s\n", (*error)->message);
1075
1076 g_error_free (*error);
1077 *error = NULL((void*)0);
1078 }
1079}
1080#endif
1081
1082/**
1083 * Special case: give a warning the first time disable_workarounds
1084 * is turned on.
1085 */
1086static void
1087maybe_give_disable_workarounds_warning (void)
1088{
1089 static gboolean first_disable = TRUE(!(0));
1090
1091 if (first_disable && disable_workarounds)
1092 {
1093 first_disable = FALSE(0);
1094
1095 meta_warning (_("Workarounds for broken applications disabled. "((char *) g_dgettext ("marco", "Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"))
1096 "Some applications may not behave properly.\n")((char *) g_dgettext ("marco", "Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"))
);
1097 }
1098}
1099
1100MetaVirtualModifier
1101meta_prefs_get_mouse_button_mods (void)
1102{
1103 return mouse_button_mods;
1104}
1105
1106MetaFocusMode
1107meta_prefs_get_focus_mode (void)
1108{
1109 return focus_mode;
1110}
1111
1112MetaFocusNewWindows
1113meta_prefs_get_focus_new_windows (void)
1114{
1115 return focus_new_windows;
1116}
1117
1118gboolean
1119meta_prefs_get_attach_modal_dialogs (void)
1120{
1121 return attach_modal_dialogs;
1122}
1123
1124gboolean
1125meta_prefs_get_raise_on_click (void)
1126{
1127 return raise_on_click;
1128}
1129
1130const char*
1131meta_prefs_get_theme (void)
1132{
1133 return current_theme;
1134}
1135
1136const char*
1137meta_prefs_get_cursor_theme (void)
1138{
1139 return cursor_theme;
1140}
1141
1142int
1143meta_prefs_get_cursor_size (void)
1144{
1145 GdkWindow *window = gdk_get_default_root_window ();
1146 gint scale = gdk_window_get_scale_factor (window);
1147
1148 return cursor_size * scale;
1149}
1150
1151int
1152meta_prefs_get_icon_size (void)
1153{
1154 GdkWindow *window = gdk_get_default_root_window ();
1155 gint scale = gdk_window_get_scale_factor (window);
1156
1157 return icon_size * scale;
1158}
1159
1160int
1161meta_prefs_get_alt_tab_max_columns (void)
1162{
1163 return alt_tab_max_columns;
1164}
1165
1166gboolean
1167meta_prefs_get_alt_tab_expand_to_fit_title (void)
1168{
1169 return alt_tab_expand_to_fit_title;
1170}
1171
1172gboolean
1173meta_prefs_get_alt_tab_raise_windows (void)
1174{
1175 return alt_tab_raise_windows;
1176}
1177
1178gboolean
1179meta_prefs_is_in_skip_list (char *class)
1180{
1181 GList *item;
1182
1183 for (item = show_desktop_skip_list; item; item = item->next)
1184 {
1185 if (!g_ascii_strcasecmp (class, item->data))
1186 return TRUE(!(0));
1187 }
1188 return FALSE(0);
1189}
1190
1191/****************************************************************************/
1192/* Handlers for string preferences. */
1193/****************************************************************************/
1194
1195static void
1196titlebar_handler (MetaPreference pref,
1197 const gchar *string_value,
1198 gboolean *inform_listeners)
1199{
1200 PangoFontDescription *new_desc = NULL((void*)0);
1201
1202 if (string_value)
1203 new_desc = pango_font_description_from_string (string_value);
1204
1205 if (new_desc == NULL((void*)0))
1206 {
1207 meta_warning (_("Could not parse font description "((char *) g_dgettext ("marco", "Could not parse font description "
"\"%s\" from GSettings key %s\n"))
1208 "\"%s\" from GSettings key %s\n")((char *) g_dgettext ("marco", "Could not parse font description "
"\"%s\" from GSettings key %s\n"))
,
1209 string_value ? string_value : "(null)",
1210 KEY_GENERAL_TITLEBAR_FONT"titlebar-font");
1211
1212 *inform_listeners = FALSE(0);
1213
1214 return;
1215 }
1216
1217 /* Is the new description the same as the old? */
1218
1219 if (titlebar_font &&
1220 pango_font_description_equal (new_desc, titlebar_font))
1221 {
1222 pango_font_description_free (new_desc);
1223 *inform_listeners = FALSE(0);
1224 return;
1225 }
1226
1227 /* No, so free the old one and put ours in instead. */
1228
1229 if (titlebar_font)
1230 pango_font_description_free (titlebar_font);
1231
1232 titlebar_font = new_desc;
1233
1234}
1235
1236static void
1237theme_name_handler (MetaPreference pref,
1238 const gchar *string_value,
1239 gboolean *inform_listeners)
1240{
1241 g_free (current_theme);
1242
1243 /* Fallback crackrock */
1244 if (string_value == NULL((void*)0))
1245 current_theme = g_strdup ("ClearlooksRe")g_strdup_inline ("ClearlooksRe");
1246 else
1247 current_theme = g_strdup (string_value)g_strdup_inline (string_value);
1248}
1249
1250static void
1251mouse_button_mods_handler (MetaPreference pref,
1252 const gchar *string_value,
1253 gboolean *inform_listeners)
1254{
1255 MetaVirtualModifier mods;
1256
1257 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1258 "Mouse button modifier has new GSettings value \"%s\"\n",
1259 string_value);
1260 if (string_value && meta_ui_parse_modifier (string_value, &mods))
1261 {
1262 mouse_button_mods = mods;
1263 }
1264 else
1265 {
1266 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1267 "Failed to parse new GSettings value\n");
1268
1269 meta_warning (_("\"%s\" found in configuration database is "((char *) g_dgettext ("marco", "\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"))
1270 "not a valid value for mouse button modifier\n")((char *) g_dgettext ("marco", "\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"))
,
1271 string_value);
1272
1273 *inform_listeners = FALSE(0);
1274 }
1275}
1276
1277static void
1278show_desktop_skip_list_handler (MetaPreference pref,
1279 const gchar *string_value,
1280 gboolean *inform_listeners)
1281{
1282 gchar **tokens;
1283 gchar **tok;
1284 GList *item;
1285
1286 if (show_desktop_skip_list)
1287 {
1288 for (item = show_desktop_skip_list; item; item = item->next)
1289 g_free (item->data);
1290 g_list_free (show_desktop_skip_list);
1291 show_desktop_skip_list = NULL((void*)0);
1292 }
1293
1294 if (!(tokens = g_strsplit (string_value, ",", -1)))
1295 return;
1296 for (tok = tokens; tok && *tok; tok++)
1297 {
1298 gchar *stripped = g_strstrip (g_strdup (*tok))g_strchomp (g_strchug (g_strdup_inline (*tok)));
1299 show_desktop_skip_list = g_list_prepend (show_desktop_skip_list, stripped);
1300 }
1301 g_strfreev (tokens);
1302}
1303
1304static gboolean
1305button_layout_equal (const MetaButtonLayout *a,
1306 const MetaButtonLayout *b)
1307{
1308 int i;
1309
1310 i = 0;
1311 while (i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
1312 {
1313 if (a->left_buttons[i] != b->left_buttons[i])
1314 return FALSE(0);
1315 if (a->right_buttons[i] != b->right_buttons[i])
1316 return FALSE(0);
1317 if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1318 return FALSE(0);
1319 if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1320 return FALSE(0);
1321 ++i;
1322 }
1323
1324 return TRUE(!(0));
1325}
1326
1327static MetaButtonFunction
1328button_function_from_string (const char *str)
1329{
1330 /* FIXME: g_settings_get_enum is the obvious way to do this */
1331
1332 if (strcmp (str, "menu") == 0)
1333 return META_BUTTON_FUNCTION_MENU;
1334 else if (strcmp (str, "appmenu") == 0)
1335 return META_BUTTON_FUNCTION_APPMENU;
1336 else if (strcmp (str, "minimize") == 0)
1337 return META_BUTTON_FUNCTION_MINIMIZE;
1338 else if (strcmp (str, "maximize") == 0)
1339 return META_BUTTON_FUNCTION_MAXIMIZE;
1340 else if (strcmp (str, "close") == 0)
1341 return META_BUTTON_FUNCTION_CLOSE;
1342 else if (strcmp (str, "shade") == 0)
1343 return META_BUTTON_FUNCTION_SHADE;
1344 else if (strcmp (str, "above") == 0)
1345 return META_BUTTON_FUNCTION_ABOVE;
1346 else if (strcmp (str, "stick") == 0)
1347 return META_BUTTON_FUNCTION_STICK;
1348 else
1349 /* don't know; give up */
1350 return META_BUTTON_FUNCTION_LAST;
1351}
1352
1353static MetaButtonFunction
1354button_opposite_function (MetaButtonFunction ofwhat)
1355{
1356 switch (ofwhat)
1357 {
1358 case META_BUTTON_FUNCTION_SHADE:
1359 return META_BUTTON_FUNCTION_UNSHADE;
1360 case META_BUTTON_FUNCTION_UNSHADE:
1361 return META_BUTTON_FUNCTION_SHADE;
1362
1363 case META_BUTTON_FUNCTION_ABOVE:
1364 return META_BUTTON_FUNCTION_UNABOVE;
1365 case META_BUTTON_FUNCTION_UNABOVE:
1366 return META_BUTTON_FUNCTION_ABOVE;
1367
1368 case META_BUTTON_FUNCTION_STICK:
1369 return META_BUTTON_FUNCTION_UNSTICK;
1370 case META_BUTTON_FUNCTION_UNSTICK:
1371 return META_BUTTON_FUNCTION_STICK;
1372
1373 default:
1374 return META_BUTTON_FUNCTION_LAST;
1375 }
1376}
1377
1378static void
1379button_layout_handler (MetaPreference pref,
1380 const gchar *string_value,
1381 gboolean *inform_listeners)
1382{
1383 MetaButtonLayout new_layout;
1384 char **sides = NULL((void*)0);
1385 int i;
1386
1387 /* We need to ignore unknown button functions, for
1388 * compat with future versions
1389 */
1390
1391 if (string_value)
1392 sides = g_strsplit (string_value, ":", 2);
1393
1394 if (sides != NULL((void*)0) && sides[0] != NULL((void*)0))
1395 {
1396 char **buttons;
1397 int b;
1398 gboolean used[META_BUTTON_FUNCTION_LAST];
1399
1400 i = 0;
1401 while (i < META_BUTTON_FUNCTION_LAST)
1402 {
1403 used[i] = FALSE(0);
1404 new_layout.left_buttons_has_spacer[i] = FALSE(0);
1405 ++i;
1406 }
1407
1408 buttons = g_strsplit (sides[0], ",", -1);
1409 i = 0;
1410 b = 0;
1411 while (buttons[b] != NULL((void*)0))
1412 {
1413 MetaButtonFunction f = button_function_from_string (buttons[b]);
1414 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1415 {
1416 new_layout.left_buttons_has_spacer[i-1] = TRUE(!(0));
1417 f = button_opposite_function (f);
1418
1419 if (f != META_BUTTON_FUNCTION_LAST)
1420 {
1421 new_layout.left_buttons_has_spacer[i-2] = TRUE(!(0));
1422 }
1423 }
1424 else
1425 {
1426 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1427 {
1428 new_layout.left_buttons[i] = f;
1429 used[f] = TRUE(!(0));
1430 ++i;
1431
1432 f = button_opposite_function (f);
1433
1434 if (f != META_BUTTON_FUNCTION_LAST)
1435 new_layout.left_buttons[i++] = f;
1436
1437 }
1438 else
1439 {
1440 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1441 buttons[b]);
1442 }
1443 }
1444
1445 ++b;
1446 }
1447
1448 new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1449 new_layout.left_buttons_has_spacer[i] = FALSE(0);
1450
1451 g_strfreev (buttons);
1452 }
1453
1454 if (sides != NULL((void*)0) && sides[0] != NULL((void*)0) && sides[1] != NULL((void*)0))
1455 {
1456 char **buttons;
1457 int b;
1458 gboolean used[META_BUTTON_FUNCTION_LAST];
1459
1460 i = 0;
1461 while (i < META_BUTTON_FUNCTION_LAST)
1462 {
1463 used[i] = FALSE(0);
1464 new_layout.right_buttons_has_spacer[i] = FALSE(0);
1465 ++i;
1466 }
1467
1468 buttons = g_strsplit (sides[1], ",", -1);
1469 i = 0;
1470 b = 0;
1471 while (buttons[b] != NULL((void*)0))
1472 {
1473 MetaButtonFunction f = button_function_from_string (buttons[b]);
1474 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1475 {
1476 new_layout.right_buttons_has_spacer[i-1] = TRUE(!(0));
1477 f = button_opposite_function (f);
1478 if (f != META_BUTTON_FUNCTION_LAST)
1479 {
1480 new_layout.right_buttons_has_spacer[i-2] = TRUE(!(0));
1481 }
1482 }
1483 else
1484 {
1485 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1486 {
1487 new_layout.right_buttons[i] = f;
1488 used[f] = TRUE(!(0));
1489 ++i;
1490
1491 f = button_opposite_function (f);
1492
1493 if (f != META_BUTTON_FUNCTION_LAST)
1494 new_layout.right_buttons[i++] = f;
1495
1496 }
1497 else
1498 {
1499 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1500 buttons[b]);
1501 }
1502 }
1503
1504 ++b;
1505 }
1506
1507 new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1508 new_layout.right_buttons_has_spacer[i] = FALSE(0);
1509
1510 g_strfreev (buttons);
1511 }
1512
1513 g_strfreev (sides);
1514
1515 /* Invert the button layout for RTL languages */
1516 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1517 {
1518 MetaButtonLayout rtl_layout;
1519 int j;
1520
1521 for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1522 for (j = 0; j < i; j++)
1523 {
1524 rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1525 if (j == 0)
1526 rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1527 else
1528 rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1529 }
1530 rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1531 rtl_layout.right_buttons_has_spacer[j] = FALSE(0);
1532
1533 for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1534 for (j = 0; j < i; j++)
1535 {
1536 rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1537 if (j == 0)
1538 rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1539 else
1540 rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1541 }
1542 rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1543 rtl_layout.left_buttons_has_spacer[j] = FALSE(0);
1544
1545 new_layout = rtl_layout;
1546 }
1547
1548 if (button_layout_equal (&button_layout, &new_layout))
1549 {
1550 /* Same as before, so duck out */
1551 *inform_listeners = FALSE(0);
1552 }
1553 else
1554 {
1555 button_layout = new_layout;
1556 }
1557}
1558
1559const PangoFontDescription*
1560meta_prefs_get_titlebar_font (void)
1561{
1562 if (use_system_font)
1563 return NULL((void*)0);
1564 else
1565 return titlebar_font;
1566}
1567
1568int
1569meta_prefs_get_num_workspaces (void)
1570{
1571 return num_workspaces;
1572}
1573
1574MetaWrapStyle
1575meta_prefs_get_wrap_style (void)
1576{
1577 return wrap_style;
1578}
1579
1580gboolean
1581meta_prefs_get_application_based (void)
1582{
1583 return FALSE(0); /* For now, we never want this to do anything */
1584
1585 return application_based;
This statement is never executed
1586}
1587
1588gboolean
1589meta_prefs_get_disable_workarounds (void)
1590{
1591 return disable_workarounds;
1592}
1593
1594#define MAX_REASONABLE_AUTO_RAISE_DELAY10000 10000
1595
1596#ifdef WITH_VERBOSE_MODE1
1597const char*
1598meta_preference_to_string (MetaPreference pref)
1599{
1600 /* FIXME: another case for g_settings_get_enum */
1601 switch (pref)
1602 {
1603 case META_PREF_MOUSE_BUTTON_MODS:
1604 return "MOUSE_BUTTON_MODS";
1605
1606 case META_PREF_FOCUS_MODE:
1607 return "FOCUS_MODE";
1608
1609 case META_PREF_FOCUS_NEW_WINDOWS:
1610 return "FOCUS_NEW_WINDOWS";
1611
1612 case META_PREF_ATTACH_MODAL_DIALOGS:
1613 return "ATTACH_MODAL_DIALOGS";
1614
1615 case META_PREF_RAISE_ON_CLICK:
1616 return "RAISE_ON_CLICK";
1617
1618 case META_PREF_THEME:
1619 return "THEME";
1620
1621 case META_PREF_TITLEBAR_FONT:
1622 return "TITLEBAR_FONT";
1623
1624 case META_PREF_NUM_WORKSPACES:
1625 return "NUM_WORKSPACES";
1626
1627 case META_PREF_WRAP_STYLE:
1628 return "WRAP_STYLE";
1629
1630 case META_PREF_APPLICATION_BASED:
1631 return "APPLICATION_BASED";
1632
1633 case META_PREF_KEYBINDINGS:
1634 return "KEYBINDINGS";
1635
1636 case META_PREF_DISABLE_WORKAROUNDS:
1637 return "DISABLE_WORKAROUNDS";
1638
1639 case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1640 return "ACTION_DOUBLE_CLICK_TITLEBAR";
1641
1642 case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1643 return "ACTION_MIDDLE_CLICK_TITLEBAR";
1644
1645 case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1646 return "ACTION_RIGHT_CLICK_TITLEBAR";
1647
1648 case META_PREF_AUTO_RAISE:
1649 return "AUTO_RAISE";
1650
1651 case META_PREF_AUTO_RAISE_DELAY:
1652 return "AUTO_RAISE_DELAY";
1653
1654 case META_PREF_COMMANDS:
1655 return "COMMANDS";
1656
1657 case META_PREF_TERMINAL_COMMAND:
1658 return "TERMINAL_COMMAND";
1659
1660 case META_PREF_BUTTON_LAYOUT:
1661 return "BUTTON_LAYOUT";
1662
1663 case META_PREF_WORKSPACE_NAMES:
1664 return "WORKSPACE_NAMES";
1665
1666 case META_PREF_VISUAL_BELL:
1667 return "VISUAL_BELL";
1668
1669 case META_PREF_AUDIBLE_BELL:
1670 return "AUDIBLE_BELL";
1671
1672 case META_PREF_VISUAL_BELL_TYPE:
1673 return "VISUAL_BELL_TYPE";
1674
1675 case META_PREF_REDUCED_RESOURCES:
1676 return "REDUCED_RESOURCES";
1677
1678 case META_PREF_MATE_ACCESSIBILITY:
1679 return "MATE_ACCESSIBILTY";
1680
1681 case META_PREF_MATE_ANIMATIONS:
1682 return "MATE_ANIMATIONS";
1683
1684 case META_PREF_CURSOR_THEME:
1685 return "CURSOR_THEME";
1686
1687 case META_PREF_CURSOR_SIZE:
1688 return "CURSOR_SIZE";
1689
1690 case META_PREF_ICON_SIZE:
1691 return "ICON_SIZE";
1692
1693 case META_PREF_ALT_TAB_MAX_COLUMNS:
1694 return "ALT_TAB_MAX_COLUMNS";
1695
1696 case META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE:
1697 return "ALT_TAB_EXPAND_TO_FIT_TITLE";
1698
1699 case META_PREF_ALT_TAB_RAISE_WINDOWS:
1700 return "ALT_TAB_RAISE_WINDOWS";
1701
1702 case META_PREF_COMPOSITING_MANAGER:
1703 return "COMPOSITING_MANAGER";
1704
1705 case META_PREF_COMPOSITING_FAST_ALT_TAB:
1706 return "COMPOSITING_FAST_ALT_TAB";
1707
1708 case META_PREF_CENTER_NEW_WINDOWS:
1709 return "CENTER_NEW_WINDOWS";
1710
1711 case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1712 return "RESIZE_WITH_RIGHT_BUTTON";
1713
1714 case META_PREF_SHOW_TAB_BORDER:
1715 return "SHOW_TAB_BORDER";
1716
1717 case META_PREF_FORCE_FULLSCREEN:
1718 return "FORCE_FULLSCREEN";
1719
1720 case META_PREF_ALLOW_TILING:
1721 return "ALLOW_TILING";
1722
1723 case META_PREF_ALLOW_TOP_TILING:
1724 return "ALLOW_TOP_TILING";
1725
1726 case META_PREF_ALLOW_TILE_CYCLING:
1727 return "ALLOW_TILE_CYCLING";
1728
1729 case META_PREF_PLACEMENT_MODE:
1730 return "PLACEMENT_MODE";
1731
1732 case META_PREF_SHOW_DESKTOP_SKIP_LIST:
1733 return "SHOW_DESKTOP_SKIP_LIST";
1734 }
1735
1736 return "(unknown)";
1737}
1738#endif /* WITH_VERBOSE_MODE */
1739
1740void
1741meta_prefs_set_num_workspaces (int n_workspaces)
1742{
1743 if (n_workspaces < 1)
1744 n_workspaces = 1;
1745 if (n_workspaces > MAX_REASONABLE_WORKSPACES36)
1746 n_workspaces = MAX_REASONABLE_WORKSPACES36;
1747
1748 g_settings_set_int (settings_general,
1749 KEY_GENERAL_NUM_WORKSPACES"num-workspaces",
1750 n_workspaces);
1751
1752}
1753
1754#define keybind(name, handler, param, flags) \
1755 { #name, NULL((void*)0), !!(flags & BINDING_REVERSES0x02), !!(flags & BINDING_PER_WINDOW0x01) },
1756static MetaKeyPref key_bindings[] = {
1757#include "all-keybindings.h"
1758 { NULL((void*)0), NULL((void*)0), FALSE(0) }
1759};
1760#undef keybind
1761
1762static void
1763init_bindings (GSettings *settings)
1764{
1765 GSettingsSchema *schema;
1766 gchar **list;
1767 gsize i;
1768
1769 g_object_get (settings, "settings-schema", &schema, NULL((void*)0));
1770 list = g_settings_schema_list_keys (schema);
1771 g_settings_schema_unref (schema);
1772
1773 for (i = 0; list[i] != NULL((void*)0); i++)
1774 {
1775 gchar *str_val;
1776
1777 str_val = g_settings_get_string (settings, list[i]);
1778 update_key_binding (list[i], str_val);
1779 g_free (str_val);
1780 }
1781
1782 g_strfreev (list);
1783}
1784
1785static void
1786init_screen_bindings (void)
1787{
1788 init_bindings (settings_screen_bindings);
1789}
1790
1791static void
1792init_window_bindings (void)
1793{
1794 init_bindings (settings_window_bindings);
1795}
1796
1797static void
1798init_commands (void)
1799{
1800 GSettingsSchema *schema;
1801 gchar **list;
1802 gsize i;
1803
1804 g_object_get (settings_command, "settings-schema", &schema, NULL((void*)0));
1805 list = g_settings_schema_list_keys (schema);
1806 g_settings_schema_unref (schema);
1807
1808 for (i = 0; list[i] != NULL((void*)0); i++)
1809 {
1810 gchar *str_val;
1811
1812 str_val = g_settings_get_string (settings_command, list[i]);
1813 update_command (list[i], str_val);
1814 g_free (str_val);
1815 }
1816
1817 g_strfreev (list);
1818}
1819
1820static void
1821init_workspace_names (void)
1822{
1823 GSettingsSchema *schema;
1824 gchar **list;
1825 gsize i;
1826
1827 g_object_get (settings_workspace_names, "settings-schema", &schema, NULL((void*)0));
1828 list = g_settings_schema_list_keys (schema);
1829 g_settings_schema_unref (schema);
1830
1831 for (i = 0; list[i] != NULL((void*)0); i++)
1832 {
1833 gchar *str_val;
1834
1835 str_val = g_settings_get_string (settings_workspace_names, list[i]);
1836 update_workspace_name (list[i], str_val);
1837 g_free (str_val);
1838 }
1839
1840 g_strfreev (list);
1841}
1842
1843static gboolean
1844update_binding (MetaKeyPref *binding,
1845 gchar *value)
1846{
1847 unsigned int keysym;
1848 unsigned int keycode;
1849 MetaVirtualModifier mods;
1850 MetaKeyCombo *combo;
1851 gboolean changed;
1852
1853 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1854 "Binding \"%s\" has new GSettings value \"%s\"\n",
1855 binding->name, value ? value : "none");
1856
1857 keysym = 0;
1858 keycode = 0;
1859 mods = 0;
1860 if (value)
1861 {
1862 if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
1863 {
1864 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1865 "Failed to parse new GSettings value\n");
1866 meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n")((char *) g_dgettext ("marco", "\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"
))
,
1867 value, binding->name);
1868
1869 return FALSE(0);
1870 }
1871 }
1872
1873 /* If there isn't already a first element, make one. */
1874 if (!binding->bindings)
1875 {
1876 MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
1877 binding->bindings = g_slist_alloc();
1878 binding->bindings->data = blank;
1879 }
1880
1881 combo = binding->bindings->data;
1882
1883 /* Bug 329676: Bindings which can be shifted must not have no modifiers,
1884 * nor only SHIFT as a modifier.
1885 */
1886
1887 if (binding->add_shift &&
1888 0 != keysym &&
1889 (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
1890 {
1891 gchar *old_setting;
1892
1893 meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
1894 "such as Ctrl or Alt.\n",
1895 binding->name,
1896 value);
1897
1898 old_setting = meta_ui_accelerator_name (combo->keysym,
1899 combo->modifiers);
1900
1901 if (!strcmp(old_setting, value))
1902 {
1903 /* We were about to set it to the same value
1904 * that it had originally! This must be caused
1905 * by getting an invalid string back from
1906 * meta_ui_accelerator_name. Bail out now
1907 * so we don't get into an infinite loop.
1908 */
1909 g_free (old_setting);
1910 return TRUE(!(0));
1911 }
1912
1913 meta_warning ("Reverting \"%s\" to %s.\n",
1914 binding->name,
1915 old_setting);
1916
1917 /* FIXME: add_shift is currently screen_bindings only, but
1918 * there's no really good reason it should always be.
1919 * So we shouldn't blindly add KEY_SCREEN_BINDINGS_PREFIX
1920 * onto here.
1921 */
1922 g_settings_set_string(settings_screen_bindings,
1923 binding->name,
1924 old_setting);
1925
1926 g_free (old_setting);
1927
1928 /* The call to g_settings_set_string() will cause this function
1929 * to be called again with the new value, so there's no need to
1930 * carry on.
1931 */
1932 return TRUE(!(0));
1933 }
1934
1935 changed = FALSE(0);
1936 if (keysym != combo->keysym ||
1937 keycode != combo->keycode ||
1938 mods != combo->modifiers)
1939 {
1940 changed = TRUE(!(0));
1941
1942 combo->keysym = keysym;
1943 combo->keycode = keycode;
1944 combo->modifiers = mods;
1945
1946 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1947 "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
1948 binding->name, combo->keysym, combo->keycode,
1949 combo->modifiers);
1950 }
1951 else
1952 {
1953 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1954 "Keybinding for \"%s\" is unchanged\n", binding->name);
1955 }
1956
1957 return changed;
1958}
1959
1960static const gchar*
1961relative_key (const gchar* key)
1962{
1963 const gchar* end;
1964
1965 end = strrchr (key, '/');
1966
1967 ++end;
1968
1969 return end;
1970}
1971
1972/* Return value is TRUE if a preference changed and we need to
1973 * notify
1974 */
1975static gboolean
1976find_and_update_binding (MetaKeyPref *bindings,
1977 const char *name,
1978 gchar *value)
1979{
1980 const char *key;
1981 int i;
1982
1983 if (*name == '/')
1984 key = relative_key (name);
1985 else
1986 key = name;
1987
1988 i = 0;
1989 while (bindings[i].name &&
1990 strcmp (key, bindings[i].name) != 0)
1991 ++i;
1992
1993 if (bindings[i].name)
1994 return update_binding (&bindings[i], value);
1995 else
1996 return FALSE(0);
1997}
1998
1999static gboolean
2000update_key_binding (const char *name,
2001 gchar *value)
2002{
2003 return find_and_update_binding (key_bindings, name, value);
2004}
2005
2006static gboolean
2007update_command (const char *name,
2008 const char *value)
2009{
2010 char *p;
2011 int i;
2012
2013 p = strrchr (name, '-');
2014 if (p == NULL((void*)0))
2015 {
2016 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2017 "Command %s has no dash?\n", name);
2018 return FALSE(0);
2019 }
2020
2021 ++p;
2022
2023 if (g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0))
2024 {
2025 i = atoi (p);
2026 i -= 1; /* count from 0 not 1 */
2027 }
2028 else
2029 {
2030 if (strcmp (name, "command-screenshot") == 0)
2031 {
2032 i = SCREENSHOT_COMMAND_IDX((32 + 2) - 2);
2033 }
2034 else if (strcmp (name, "command-window-screenshot") == 0)
2035 {
2036 i = WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1);
2037 }
2038 else
2039 {
2040 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2041 "Command %s doesn't end in number?\n", name);
2042 return FALSE(0);
2043 }
2044 }
2045
2046 if (i >= MAX_COMMANDS(32 + 2))
2047 {
2048 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2049 "Command %d is too highly numbered, ignoring\n", i);
2050 return FALSE(0);
2051 }
2052
2053 if ((commands[i] == NULL((void*)0) && value == NULL((void*)0)) ||
2054 (commands[i] && value && strcmp (commands[i], value) == 0))
2055 {
2056 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2057 "Command %d is unchanged\n", i);
2058 return FALSE(0);
2059 }
2060
2061 g_free (commands[i]);
2062 commands[i] = g_strdup (value)g_strdup_inline (value);
2063
2064 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2065 "Updated command %d to \"%s\"\n",
2066 i, commands[i] ? commands[i] : "none");
2067
2068 return TRUE(!(0));
2069}
2070
2071const char*
2072meta_prefs_get_command (int i)
2073{
2074 g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL)do { if ((i >= 0 && i < (32 + 2))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_COMMANDS"
); return (((void*)0)); } } while (0)
;
2075
2076 return commands[i];
2077}
2078
2079char*
2080meta_prefs_get_settings_key_for_command (int i)
2081{
2082 char *key;
2083
2084 switch (i)
2085 {
2086 case SCREENSHOT_COMMAND_IDX((32 + 2) - 2):
2087 key = g_strdup (KEY_COMMAND_PREFIX "screenshot")g_strdup_inline ("command-" "screenshot");
2088 break;
2089 case WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1):
2090 key = g_strdup (KEY_COMMAND_PREFIX "window-screenshot")g_strdup_inline ("command-" "window-screenshot");
2091 break;
2092 default:
2093 key = g_strdup_printf (KEY_COMMAND_PREFIX"command-""%d", i + 1);
2094 break;
2095 }
2096
2097 return key;
2098}
2099
2100const char*
2101meta_prefs_get_terminal_command (void)
2102{
2103 return terminal_command;
2104}
2105
2106const char*
2107meta_prefs_get_settings_key_for_terminal_command (void)
2108{
2109 return KEY_MATE_TERMINAL_COMMAND"exec";
2110}
2111
2112static gboolean
2113update_workspace_name (const char *name,
2114 const char *value)
2115{
2116 char *p;
2117 int i;
2118
2119 p = strrchr (name, '-');
2120 if (p == NULL((void*)0))
2121 {
2122 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2123 "Workspace name %s has no dash?\n", name);
2124 return FALSE(0);
2125 }
2126
2127 ++p;
2128
2129 if (!g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0))
2130 {
2131 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2132 "Workspace name %s doesn't end in number?\n", name);
2133 return FALSE(0);
2134 }
2135
2136 i = atoi (p);
2137 i -= 1; /* count from 0 not 1 */
2138
2139 if (i >= MAX_REASONABLE_WORKSPACES36)
2140 {
2141 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2142 "Workspace name %d is too highly numbered, ignoring\n", i);
2143 return FALSE(0);
2144 }
2145
2146 if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2147 {
2148 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2149 "Workspace name %d is unchanged\n", i);
2150 return FALSE(0);
2151 }
2152
2153 /* This is a bad hack. We have to treat empty string as
2154 * "unset" because the root window property can't contain
2155 * null. So it gets empty string instead and we don't want
2156 * that to result in setting the empty string as a value that
2157 * overrides "unset".
2158 */
2159 if (value != NULL((void*)0) && *value != '\0')
2160 {
2161 g_free (workspace_names[i]);
2162 workspace_names[i] = g_strdup (value)g_strdup_inline (value);
2163 }
2164 else
2165 {
2166 /* use a default name */
2167 char *d;
2168
2169 d = g_strdup_printf (_("Workspace %d")((char *) g_dgettext ("marco", "Workspace %d")), i + 1);
2170 if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2171 {
2172 g_free (d);
2173 return FALSE(0);
2174 }
2175 else
2176 {
2177 g_free (workspace_names[i]);
2178 workspace_names[i] = d;
2179 }
2180 }
2181
2182 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2183 "Updated workspace name %d to \"%s\"\n",
2184 i, workspace_names[i] ? workspace_names[i] : "none");
2185
2186 return TRUE(!(0));
2187}
2188
2189const char*
2190meta_prefs_get_workspace_name (int i)
2191{
2192 g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL)do { if ((i >= 0 && i < 36)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_REASONABLE_WORKSPACES"
); return (((void*)0)); } } while (0)
;
2193
2194 g_assert (workspace_names[i] != NULL)do { if (workspace_names[i] != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/prefs.c", 2194, ((const char*) (__func__)), "workspace_names[i] != NULL"
); } while (0)
;
2195
2196 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2197 "Getting workspace name for %d: \"%s\"\n",
2198 i, workspace_names[i]);
2199
2200 return workspace_names[i];
2201}
2202
2203void
2204meta_prefs_change_workspace_name (int i,
2205 const char *name)
2206{
2207 char *key;
2208
2209 g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES)do { if ((i >= 0 && i < 36)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_REASONABLE_WORKSPACES"
); return; } } while (0)
;
2210
2211 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2212 "Changing name of workspace %d to %s\n",
2213 i, name ? name : "none");
2214
2215 if (name && *name == '\0')
2216 name = NULL((void*)0);
2217
2218 if ((name == NULL((void*)0) && workspace_names[i] == NULL((void*)0)) ||
2219 (name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2220 {
2221 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2222 "Workspace %d already has name %s\n",
2223 i, name ? name : "none");
2224 return;
2225 }
2226
2227 key = settings_key_for_workspace_name (i);
2228
2229 if (name != NULL((void*)0))
2230 g_settings_set_string (settings_workspace_names,
2231 key,
2232 name);
2233 else
2234 g_settings_set_string (settings_workspace_names,
2235 key,
2236 "");
2237
2238 g_free (key);
2239}
2240
2241static char*
2242settings_key_for_workspace_name (int i)
2243{
2244 char *key;
2245
2246 key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"name-""%d", i + 1);
2247
2248 return key;
2249}
2250
2251void
2252meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2253{
2254 *button_layout_p = button_layout;
2255}
2256
2257gboolean
2258meta_prefs_get_visual_bell (void)
2259{
2260 return provide_visual_bell;
2261}
2262
2263gboolean
2264meta_prefs_bell_is_audible (void)
2265{
2266 return bell_is_audible;
2267}
2268
2269MetaVisualBellType
2270meta_prefs_get_visual_bell_type (void)
2271{
2272 return visual_bell_type;
2273}
2274
2275void
2276meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2277 int *n_bindings)
2278{
2279
2280 *bindings = key_bindings;
2281 *n_bindings = (int) G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 1;
2282}
2283
2284MetaActionTitlebar
2285meta_prefs_get_action_double_click_titlebar (void)
2286{
2287 return action_double_click_titlebar;
2288}
2289
2290MetaActionTitlebar
2291meta_prefs_get_action_middle_click_titlebar (void)
2292{
2293 return action_middle_click_titlebar;
2294}
2295
2296MetaActionTitlebar
2297meta_prefs_get_action_right_click_titlebar (void)
2298{
2299 return action_right_click_titlebar;
2300}
2301
2302gboolean
2303meta_prefs_get_auto_raise (void)
2304{
2305 return auto_raise;
2306}
2307
2308int
2309meta_prefs_get_auto_raise_delay (void)
2310{
2311 return auto_raise_delay;
2312}
2313
2314gboolean
2315meta_prefs_get_reduced_resources (void)
2316{
2317 return reduced_resources;
2318}
2319
2320gboolean
2321meta_prefs_get_mate_accessibility ()
2322{
2323 return mate_accessibility;
2324}
2325
2326gboolean
2327meta_prefs_get_mate_animations ()
2328{
2329 return mate_animations;
2330}
2331
2332MetaKeyBindingAction
2333meta_prefs_get_keybinding_action (const char *name)
2334{
2335 int i;
2336
2337 i = G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 2; /* -2 for dummy entry at end */
2338 while (i >= 0)
2339 {
2340 if (strcmp (key_bindings[i].name, name) == 0)
2341 return (MetaKeyBindingAction) i;
2342
2343 --i;
2344 }
2345
2346 return META_KEYBINDING_ACTION_NONE;
2347}
2348
2349/* This is used by the menu system to decide what key binding
2350 * to display next to an option. We return the first non-disabled
2351 * binding, if any.
2352 */
2353void
2354meta_prefs_get_window_binding (const char *name,
2355 unsigned int *keysym,
2356 MetaVirtualModifier *modifiers)
2357{
2358 int i;
2359
2360 i = G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 2; /* -2 for dummy entry at end */
2361 while (i >= 0)
2362 {
2363 if (key_bindings[i].per_window &&
2364 strcmp (key_bindings[i].name, name) == 0)
2365 {
2366 GSList *s = key_bindings[i].bindings;
2367
2368 while (s)
2369 {
2370 MetaKeyCombo *c = s->data;
2371
2372 if (c->keysym!=0 || c->modifiers!=0)
2373 {
2374 *keysym = c->keysym;
2375 *modifiers = c->modifiers;
2376 return;
2377 }
2378
2379 s = s->next;
2380 }
2381
2382 /* Not found; return the disabled value */
2383 *keysym = *modifiers = 0;
2384 return;
2385 }
2386
2387 --i;
2388 }
2389
2390 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/prefs.c", 2390,
((const char*) (__func__)), ((void*)0)); } while (0)
;
2391}
2392
2393gboolean
2394meta_prefs_get_compositing_manager (void)
2395{
2396 if (use_force_compositor_manager)
2397 return force_compositor_manager;
2398 return compositing_manager;
2399}
2400
2401gboolean
2402meta_prefs_get_compositing_fast_alt_tab (void)
2403{
2404 return compositing_fast_alt_tab;
2405}
2406
2407gboolean
2408meta_prefs_get_center_new_windows (void)
2409{
2410 return center_new_windows;
2411}
2412
2413gboolean
2414meta_prefs_get_allow_tiling ()
2415{
2416 return allow_tiling;
2417}
2418
2419gboolean
2420meta_prefs_get_allow_top_tiling ()
2421{
2422 return allow_top_tiling;
2423}
2424
2425gboolean
2426meta_prefs_get_allow_tile_cycling ()
2427{
2428 return allow_tile_cycling;
2429}
2430
2431guint
2432meta_prefs_get_mouse_button_resize (void)
2433{
2434 return resize_with_right_button ? 3: 2;
2435}
2436
2437guint
2438meta_prefs_get_mouse_button_menu (void)
2439{
2440 return resize_with_right_button ? 2: 3;
2441}
2442
2443gboolean
2444meta_prefs_show_tab_border(void)
2445{
2446 return show_tab_border;
2447}
2448
2449gboolean
2450meta_prefs_get_force_fullscreen (void)
2451{
2452 return force_fullscreen;
2453}
2454
2455MetaPlacementMode
2456meta_prefs_get_placement_mode (void)
2457{
2458 return placement_mode;
2459}
2460
2461void
2462meta_prefs_set_force_compositing_manager (gboolean whether)
2463{
2464 use_force_compositor_manager = TRUE(!(0));
2465 force_compositor_manager = whether;
2466}
2467
2468void
2469meta_prefs_set_compositing_fast_alt_tab (gboolean whether)
2470{
2471 g_settings_set_boolean (settings_general,
2472 KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB"compositing-fast-alt-tab",
2473 whether);
2474}
2475
2476void
2477meta_prefs_set_center_new_windows (gboolean whether)
2478{
2479 g_settings_set_boolean (settings_general,
2480 KEY_GENERAL_CENTER_NEW_WINDOWS"center-new-windows",
2481 whether);
2482}
2483
2484void
2485meta_prefs_set_force_fullscreen (gboolean whether)
2486{
2487 force_fullscreen = whether;
2488}
2489
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6885b9.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6885b9.html new file mode 100644 index 00000000..5516b183 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6885b9.html @@ -0,0 +1,1807 @@ + + + +ui/theme-viewer.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme-viewer.c
Warning:line 903, column 23
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme-viewer.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme-viewer.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco theme viewer and test app main() */
4
5/*
6 * Copyright (C) 2002 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <config.h>
25#include <glib/gi18n.h>
26
27#include "util.h"
28#include "theme.h"
29#include "theme-parser.h"
30#include "preview-widget.h"
31#include <gtk/gtk.h>
32#include <time.h>
33#include <stdlib.h>
34#include <string.h>
35
36/* We need to compute all different button arrangements
37 * in terms of button location. We don't care about
38 * different arrangements in terms of button function.
39 *
40 * So if dups are allowed, from 0-4 buttons on the left, from 0-4 on
41 * the right, 5x5=25 combinations.
42 *
43 * If no dups, 0-4 on left determines the number on the right plus
44 * we have a special case for the "no buttons on either side" case.
45 */
46#ifndef ALLOW_DUPLICATE_BUTTONS
47#define BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1) (MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST + 1 + 1)
48#else
49#define BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1) ((MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST+1)*(MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST+1))
50#endif
51
52enum
53{
54 FONT_SIZE_SMALL,
55 FONT_SIZE_NORMAL,
56 FONT_SIZE_LARGE,
57 FONT_SIZE_LAST
58};
59
60static MetaTheme *global_theme = NULL((void*)0);
61static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1)] = { NULL((void*)0), };
62static double milliseconds_to_draw_frame = 0.0;
63
64static void run_theme_benchmark (void);
65
66static const gchar *xml =
67 "<interface>"
68 "<menu id='menubar'>"
69 "<submenu>"
70 "<attribute name='label'>Windows</attribute>"
71 "<section>"
72 "<item>"
73 "<attribute name='label'>Dialog</attribute>"
74 "<attribute name='action'>theme-viewer.dialog1</attribute>"
75 "<attribute name='accel'>&lt;control&gt;d</attribute>"
76 "</item>"
77 "<item>"
78 "<attribute name='label'>Modal dialog</attribute>"
79 "<attribute name='action'>theme-viewer.dialog2</attribute>"
80 "</item>"
81 "<item>"
82 "<attribute name='label'>Utility</attribute>"
83 "<attribute name='action'>theme-viewer.utility</attribute>"
84 "<attribute name='accel'>&lt;control&gt;u</attribute>"
85 "</item>"
86 "<item>"
87 "<attribute name='label'>Splashscreen</attribute>"
88 "<attribute name='action'>theme-viewer.splashscreen</attribute>"
89 "<attribute name='accel'>&lt;control&gt;s</attribute>"
90 "</item>"
91 "<item>"
92 "<attribute name='label'>Top dock</attribute>"
93 "<attribute name='action'>theme-viewer.top-dock</attribute>"
94 "</item>"
95 "<item>"
96 "<attribute name='label'>Bottom dock</attribute>"
97 "<attribute name='action'>theme-viewer.bottom-dock</attribute>"
98 "</item>"
99 "<item>"
100 "<attribute name='label'>Left dock</attribute>"
101 "<attribute name='action'>theme-viewer.left-dock</attribute>"
102 "</item>"
103 "<item>"
104 "<attribute name='label'>Right dock</attribute>"
105 "<attribute name='action'>theme-viewer.right-dock</attribute>"
106 "</item>"
107 "<item>"
108 "<attribute name='label'>All docks</attribute>"
109 "<attribute name='action'>theme-viewer.all-docks</attribute>"
110 "</item>"
111 "<item>"
112 "<attribute name='label'>Desktop</attribute>"
113 "<attribute name='action'>theme-viewer.desktop</attribute>"
114 "</item>"
115 "</section>"
116 "</submenu>"
117 "</menu>"
118 "</interface>";
119
120static GActionEntry theme_viewer_entries[] =
121{
122 /* menubar */
123 { "dialog1", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
124 { "dialog2", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
125 { "utility", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
126 { "splashscreen", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
127 { "top-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
128 { "bottom-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
129 { "left-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
130 { "right-dock", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
131 { "all-docks", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
132 { "desktop", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
133 /* toolbar */
134 { "new", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
135 { "open", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} },
136 { "quit", NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), {} }
137};
138
139static GtkWidget *
140create_toolbar (void)
141{
142 GtkWidget *toolbar;
143 GtkToolItem *item;
144
145 toolbar = gtk_toolbar_new ();
146
147 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-new", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
148 gtk_tool_item_set_tooltip_markup (item, "Open another one of these windows");
149 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.new");
150 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
151
152 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-open", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
153 gtk_tool_item_set_tooltip_markup (item, "This is a demo button with an 'open' icon");
154 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.open");
155 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
156
157 item = gtk_tool_button_new (gtk_image_new_from_icon_name ("application-exit", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL((void*)0));
158 gtk_tool_item_set_tooltip_markup (item, "This is a demo button with a 'quit' icon");
159 gtk_actionable_set_action_name (GTK_ACTIONABLE (item)((((GtkActionable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((gtk_actionable_get_type ()))))))
, "theme-viewer.quit");
160 gtk_toolbar_insert (GTK_TOOLBAR (toolbar)((((GtkToolbar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toolbar)), ((gtk_toolbar_get_type ()))))))
, item, -1);
161
162 return toolbar;
163}
164
165static GtkWidget *
166normal_contents (void)
167{
168 GtkWidget *grid;
169 GtkWidget *statusbar;
170 GtkWidget *contents;
171 GtkWidget *sw;
172 GtkBuilder *builder;
173
174 grid = gtk_grid_new ();
175 builder = gtk_builder_new_from_string (xml, -1);
176
177 /* create menu items */
178 GMenuModel *model = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar"))((((GMenuModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object (builder, "menubar"))), ((g_menu_model_get_type
()))))))
;
179 GtkWidget *menubar = gtk_menu_bar_new_from_model (model);
180 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, menubar, 0, 0, 1, 1);
181 gtk_widget_set_hexpand (menubar, TRUE(!(0)));
182
183 /* Create the toolbar */
184 GtkWidget *toolbar = create_toolbar ();
185 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, toolbar, 0, 1, 1, 1);
186 gtk_widget_set_hexpand (toolbar, TRUE(!(0)));
187
188 /* Create document
189 */
190
191 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
192 gtk_widget_set_hexpand (sw, TRUE(!(0)));
193 gtk_widget_set_vexpand (sw, TRUE(!(0)));
194
195 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
196 GTK_POLICY_AUTOMATIC,
197 GTK_POLICY_AUTOMATIC);
198
199 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
200 GTK_SHADOW_IN);
201
202 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
203 sw,
204 0, 2, 1, 1);
205
206 contents = gtk_text_view_new ();
207 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (contents)((((GtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((contents)), ((gtk_text_view_get_type ()))))))
,
208 GTK_WRAP_WORD);
209
210 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
,
211 contents);
212
213 /* Create statusbar */
214
215 statusbar = gtk_statusbar_new ();
216 gtk_widget_set_hexpand (statusbar, TRUE(!(0)));
217 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
218 statusbar,
219 0, 3, 1, 1);
220
221 gtk_widget_show_all (grid);
222
223 g_object_unref (builder);
224
225 return grid;
226}
227
228static void
229update_spacings (GtkWidget *vbox,
230 GtkWidget *action_area)
231{
232 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 2);
233 gtk_box_set_spacing (GTK_BOX (action_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_box_get_type ()))))))
, 10);
234 gtk_container_set_border_width (GTK_CONTAINER (action_area)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_container_get_type ()))))))
, 5);
235}
236
237static GtkWidget*
238dialog_contents (void)
239{
240 GtkWidget *vbox;
241 GtkWidget *hbox;
242 GtkWidget *action_area;
243 GtkWidget *label;
244 GtkWidget *image;
245 GtkWidget *button;
246
247 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
248
249 action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
250
251 gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area)((((GtkButtonBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_button_box_get_type ()))))))
,
252 GTK_BUTTONBOX_END);
253
254 button = gtk_button_new_with_mnemonic (_("_OK")gettext ("_OK"));
255 gtk_button_set_image (GTK_BUTTON (button)((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((gtk_button_get_type ()))))))
, gtk_image_new_from_icon_name ("gtk-ok", GTK_ICON_SIZE_BUTTON));
256
257 gtk_box_pack_end (GTK_BOX (action_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_area)), ((gtk_box_get_type ()))))))
,
258 button,
259 FALSE(0), TRUE(!(0)), 0);
260
261 gtk_box_pack_end (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, action_area,
262 FALSE(0), TRUE(!(0)), 0);
263
264 update_spacings (vbox, action_area);
265
266 label = gtk_label_new (_("This is a sample message in a sample dialog")gettext ("This is a sample message in a sample dialog"));
267 image = gtk_image_new_from_icon_name ("dialog-information",
268 GTK_ICON_SIZE_DIALOG);
269 gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
270 gtk_widget_set_valign (image, GTK_ALIGN_START);
271
272 gtk_label_set_line_wrap (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
273 gtk_label_set_selectable (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, TRUE(!(0)));
274
275 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
276
277 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, image,
278 FALSE(0), FALSE(0), 0);
279
280 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, label,
281 TRUE(!(0)), TRUE(!(0)), 0);
282
283 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
,
284 hbox,
285 FALSE(0), FALSE(0), 0);
286
287 gtk_widget_show_all (vbox);
288
289 return vbox;
290}
291
292static GtkWidget*
293utility_contents (void)
294{
295 GtkWidget *grid;
296 GtkWidget *button;
297 int i, j;
298
299 grid = gtk_grid_new ();
300
301 i = 0;
302 while (i < 3)
303 {
304 j = 0;
305 while (j < 4)
306 {
307 char *str;
308
309 str = g_strdup_printf ("_%c", (char) ('A' + 4*i + j));
310
311 button = gtk_button_new_with_mnemonic (str);
312
313 g_free (str);
314
315 gtk_widget_set_hexpand (button, TRUE(!(0)));
316 gtk_widget_set_vexpand (button, TRUE(!(0)));
317
318 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
,
319 button,
320 i, j, 1, 1);
321
322 ++j;
323 }
324
325 ++i;
326 }
327
328 gtk_widget_show_all (grid);
329
330 return grid;
331}
332
333static GtkWidget*
334menu_contents (void)
335{
336 GtkWidget *vbox;
337 GtkWidget *mi;
338 int i;
339 GtkWidget *frame;
340
341 frame = gtk_frame_new (NULL((void*)0));
342 gtk_frame_set_shadow_type (GTK_FRAME (frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_frame_get_type ()))))))
,
343 GTK_SHADOW_OUT);
344
345 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
346
347 i = 0;
348 while (i < 10)
349 {
350 char *str = g_strdup_printf (_("Fake menu item %d\n")gettext ("Fake menu item %d\n"), i + 1);
351 mi = gtk_label_new (str);
352 gtk_widget_set_halign (mi, GTK_ALIGN_START);
353 gtk_widget_set_valign (mi, GTK_ALIGN_CENTER);
354 g_free (str);
355 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, mi, FALSE(0), FALSE(0), 0);
356
357 ++i;
358 }
359
360 gtk_container_add (GTK_CONTAINER (frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_container_get_type ()))))))
, vbox);
361
362 gtk_widget_show_all (frame);
363
364 return frame;
365}
366
367static void
368override_background_color (GtkWidget *widget,
369 GdkRGBA *rgba)
370{
371 gchar *css;
372 GtkCssProvider *provider;
373
374 provider = gtk_css_provider_new ();
375
376 css = g_strdup_printf ("* { background-color: %s; }",
377 gdk_rgba_to_string (rgba));
378 gtk_css_provider_load_from_data (provider, css, -1, NULL((void*)0));
379 g_free (css);
380
381 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
382 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
383 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
384 g_object_unref (provider);
385}
386
387static GtkWidget*
388border_only_contents (void)
389{
390 GtkWidget *event_box;
391 GtkWidget *vbox;
392 GtkWidget *w;
393 GdkRGBA color;
394
395 event_box = gtk_event_box_new ();
396
397 color.red = 0.6;
398 color.green = 0;
399 color.blue = 0.6;
400 color.alpha = 1.0;
401 override_background_color (event_box, &color);
402
403 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
404 gtk_container_set_border_width (GTK_CONTAINER (vbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_container_get_type ()))))))
, 3);
405
406 w = gtk_label_new (_("Border-only window")gettext ("Border-only window"));
407 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, w, FALSE(0), FALSE(0), 0);
408 w = gtk_button_new_with_label (_("Bar")gettext ("Bar"));
409 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, w, FALSE(0), FALSE(0), 0);
410
411 gtk_container_add (GTK_CONTAINER (event_box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((event_box)), ((gtk_container_get_type ()))))))
, vbox);
412
413 gtk_widget_show_all (event_box);
414
415 return event_box;
416}
417
418static GtkWidget*
419get_window_contents (MetaFrameType type,
420 const char **title)
421{
422 switch (type)
423 {
424 case META_FRAME_TYPE_NORMAL:
425 *title = _("Normal Application Window")gettext ("Normal Application Window");
426 return normal_contents ();
427
428 case META_FRAME_TYPE_DIALOG:
429 *title = _("Dialog Box")gettext ("Dialog Box");
430 return dialog_contents ();
431
432 case META_FRAME_TYPE_MODAL_DIALOG:
433 *title = _("Modal Dialog Box")gettext ("Modal Dialog Box");
434 return dialog_contents ();
435
436 case META_FRAME_TYPE_UTILITY:
437 *title = _("Utility Palette")gettext ("Utility Palette");
438 return utility_contents ();
439
440 case META_FRAME_TYPE_MENU:
441 *title = _("Torn-off Menu")gettext ("Torn-off Menu");
442 return menu_contents ();
443
444 case META_FRAME_TYPE_BORDER:
445 *title = _("Border")gettext ("Border");
446 return border_only_contents ();
447
448 case META_FRAME_TYPE_ATTACHED:
449 *title = _("Attached Modal Dialog")gettext ("Attached Modal Dialog");
450 return dialog_contents ();
451
452 case META_FRAME_TYPE_LAST:
453 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme-viewer.c", 453
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
454 break;
455 }
456
457 return NULL((void*)0);
458}
459
460static MetaFrameFlags
461get_window_flags (MetaFrameType type)
462{
463 MetaFrameFlags flags;
464
465 flags = META_FRAME_ALLOWS_DELETE |
466 META_FRAME_ALLOWS_MENU |
467 META_FRAME_ALLOWS_MINIMIZE |
468 META_FRAME_ALLOWS_MAXIMIZE |
469 META_FRAME_ALLOWS_VERTICAL_RESIZE |
470 META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
471 META_FRAME_HAS_FOCUS |
472 META_FRAME_ALLOWS_SHADE |
473 META_FRAME_ALLOWS_MOVE;
474
475 switch (type)
476 {
477 case META_FRAME_TYPE_NORMAL:
478 break;
479
480 case META_FRAME_TYPE_DIALOG:
481 case META_FRAME_TYPE_MODAL_DIALOG:
482 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
483 META_FRAME_ALLOWS_MAXIMIZE);
484 break;
485
486 case META_FRAME_TYPE_UTILITY:
487 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
488 META_FRAME_ALLOWS_MAXIMIZE);
489 break;
490
491 case META_FRAME_TYPE_MENU:
492 flags &= ~(META_FRAME_ALLOWS_MINIMIZE |
493 META_FRAME_ALLOWS_MAXIMIZE);
494 break;
495
496 case META_FRAME_TYPE_BORDER:
497 break;
498
499 case META_FRAME_TYPE_ATTACHED:
500 break;
501
502 case META_FRAME_TYPE_LAST:
503 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme-viewer.c", 503
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
504 break;
505 }
506
507 return flags;
508}
509
510static void
511override_font (GtkWidget *widget,
512 const gchar *font)
513{
514 gchar *css;
515 GtkCssProvider *provider;
516
517 provider = gtk_css_provider_new ();
518
519 css = g_strdup_printf ("* { font: %s; }", font);
520 gtk_css_provider_load_from_data (provider, css, -1, NULL((void*)0));
521 g_free (css);
522
523 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
524 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
525 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
526 g_object_unref (provider);
527}
528
529static GtkWidget*
530preview_collection (int font_size,
531 const PangoFontDescription *base_desc)
532{
533 GtkWidget *box;
534 GtkWidget *sw;
535 GdkRGBA desktop_color;
536 int i;
537 GtkWidget *eventbox;
538
539 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
540 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
541 GTK_POLICY_AUTOMATIC,
542 GTK_POLICY_AUTOMATIC);
543
544 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
545 gtk_box_set_spacing (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, 20);
546 gtk_container_set_border_width (GTK_CONTAINER (box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_container_get_type ()))))))
, 20);
547
548 eventbox = gtk_event_box_new ();
549 gtk_container_add (GTK_CONTAINER (eventbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox)), ((gtk_container_get_type ()))))))
, box);
550
551 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
, eventbox);
552
553 GSimpleActionGroup *action_group = g_simple_action_group_new ();
554 g_action_map_add_action_entries (G_ACTION_MAP (action_group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), ((g_action_map_get_type ()))))))
,
555 theme_viewer_entries,
556 G_N_ELEMENTS (theme_viewer_entries)(sizeof (theme_viewer_entries) / sizeof ((theme_viewer_entries
)[0]))
,
557 NULL((void*)0));
558 gtk_widget_insert_action_group (sw, "theme-viewer", G_ACTION_GROUP (action_group)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), ((g_action_group_get_type ()))))))
);
559 g_object_unref (action_group);
560
561 desktop_color.red = 0.32;
562 desktop_color.green = 0.46;
563 desktop_color.blue = 0.65;
564 desktop_color.alpha = 1.0;
565
566 override_background_color (eventbox, &desktop_color);
567
568 i = 0;
569 while (i < META_FRAME_TYPE_LAST)
570 {
571 const char *title = NULL((void*)0);
572 GtkWidget *contents;
573 GtkAlign xalign, yalign;
574 GtkWidget *eventbox2;
575 GtkWidget *preview;
576 PangoFontDescription *font_desc;
577 gchar *font_string;
578 double scale;
579
580 eventbox2 = gtk_event_box_new ();
581
582 preview = meta_preview_new ();
583
584 gtk_container_add (GTK_CONTAINER (eventbox2)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox2)), ((gtk_container_get_type ()))))))
, preview);
585
586 meta_preview_set_frame_type (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, i);
587 meta_preview_set_frame_flags (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
,
588 get_window_flags (i));
589
590 meta_preview_set_theme (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, global_theme);
591
592 contents = get_window_contents (i, &title);
593
594 meta_preview_set_title (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, title);
595
596 gtk_container_add (GTK_CONTAINER (preview)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((gtk_container_get_type ()))))))
, contents);
597
598 if (i == META_FRAME_TYPE_MENU)
599 {
600 xalign = GTK_ALIGN_START;
601 yalign = GTK_ALIGN_START;
602 }
603 else
604 {
605 xalign = GTK_ALIGN_FILL;
606 yalign = GTK_ALIGN_FILL;
607 }
608
609 gtk_widget_set_halign (eventbox2, xalign);
610 gtk_widget_set_valign (eventbox2, yalign);
611
612 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, eventbox2, TRUE(!(0)), TRUE(!(0)), 0);
613
614 switch (font_size)
615 {
616 case FONT_SIZE_SMALL:
617 scale = PANGO_SCALE_XX_SMALL((double)0.5787037037037);
618 break;
619 case FONT_SIZE_LARGE:
620 scale = PANGO_SCALE_XX_LARGE((double)1.728);
621 break;
622 default:
623 scale = 1.0;
624 break;
625 }
626
627 if (scale != 1.0)
628 {
629 font_desc = pango_font_description_new ();
630
631 pango_font_description_set_size (font_desc,
632 MAX (pango_font_description_get_size (base_desc) * scale, 1)(((pango_font_description_get_size (base_desc) * scale) > (
1)) ? (pango_font_description_get_size (base_desc) * scale) :
(1))
);
633
634 font_string = pango_font_description_to_string (font_desc);
635 override_font (preview, font_string);
636 g_free (font_string);
637
638 pango_font_description_free (font_desc);
639 }
640
641 previews[font_size*META_FRAME_TYPE_LAST + i] = preview;
642
643 ++i;
644 }
645
646 return sw;
647}
648
649static MetaButtonLayout different_layouts[BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1)];
650
651static void
652init_layouts (void)
653{
654 int i;
655
656 /* Blank out all the layouts */
657 i = 0;
658 while (i < (int) G_N_ELEMENTS (different_layouts)(sizeof (different_layouts) / sizeof ((different_layouts)[0])
)
)
659 {
660 int j;
661
662 j = 0;
663 while (j < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
664 {
665 different_layouts[i].left_buttons[j] = META_BUTTON_FUNCTION_LAST;
666 different_layouts[i].right_buttons[j] = META_BUTTON_FUNCTION_LAST;
667 ++j;
668 }
669 ++i;
670 }
671
672#ifndef ALLOW_DUPLICATE_BUTTONS
673 i = 0;
674 while (i <= MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
675 {
676 int j;
677
678 j = 0;
679 while (j < i)
680 {
681 different_layouts[i].right_buttons[j] = (MetaButtonFunction) j;
682 ++j;
683 }
684 while (j < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
685 {
686 different_layouts[i].left_buttons[j-i] = (MetaButtonFunction) j;
687 ++j;
688 }
689
690 ++i;
691 }
692
693 /* Special extra case for no buttons on either side */
694 different_layouts[i].left_buttons[0] = META_BUTTON_FUNCTION_LAST;
695 different_layouts[i].right_buttons[0] = META_BUTTON_FUNCTION_LAST;
696
697#else
698 /* FIXME this code is if we allow duplicate buttons,
699 * which we currently do not
700 */
701 int left;
702 int i;
703
704 left = 0;
705 i = 0;
706
707 while (left < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
708 {
709 int right;
710
711 right = 0;
712
713 while (right < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
714 {
715 int j;
716
717 static MetaButtonFunction left_functions[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST] = {
718 META_BUTTON_FUNCTION_MENU,
719 META_BUTTON_FUNCTION_MINIMIZE,
720 META_BUTTON_FUNCTION_MAXIMIZE,
721 META_BUTTON_FUNCTION_CLOSE
722 };
723 static MetaButtonFunction right_functions[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST] = {
724 META_BUTTON_FUNCTION_MINIMIZE,
725 META_BUTTON_FUNCTION_MAXIMIZE,
726 META_BUTTON_FUNCTION_CLOSE,
727 META_BUTTON_FUNCTION_MENU
728 };
729
730 g_assert (i < BUTTON_LAYOUT_COMBINATIONS)do { if (i < (META_BUTTON_FUNCTION_LAST + 1 + 1)) ; else g_assertion_message_expr
("marco", "ui/theme-viewer.c", 730, ((const char*) (__func__
)), "i < BUTTON_LAYOUT_COMBINATIONS"); } while (0)
;
731
732 j = 0;
733 while (j <= left)
734 {
735 different_layouts[i].left_buttons[j] = left_functions[j];
736 ++j;
737 }
738
739 j = 0;
740 while (j <= right)
741 {
742 different_layouts[i].right_buttons[j] = right_functions[j];
743 ++j;
744 }
745
746 ++i;
747
748 ++right;
749 }
750
751 ++left;
752 }
753#endif
754}
755
756static GtkWidget*
757previews_of_button_layouts (void)
758{
759 static gboolean initted = FALSE(0);
760 GtkWidget *box;
761 GtkWidget *sw;
762 GdkRGBA desktop_color;
763 int i;
764 GtkWidget *eventbox;
765
766 if (!initted)
767 {
768 init_layouts ();
769 initted = TRUE(!(0));
770 }
771
772 sw = gtk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
773 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw)((((GtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((sw)), ((gtk_scrolled_window_get_type ())))
)))
,
774 GTK_POLICY_AUTOMATIC,
775 GTK_POLICY_AUTOMATIC);
776
777 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
778 gtk_box_set_spacing (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, 20);
779 gtk_container_set_border_width (GTK_CONTAINER (box)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_container_get_type ()))))))
, 20);
780
781 eventbox = gtk_event_box_new ();
782 gtk_container_add (GTK_CONTAINER (eventbox)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox)), ((gtk_container_get_type ()))))))
, box);
783
784 gtk_container_add (GTK_CONTAINER (sw)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((sw)), ((gtk_container_get_type ()))))))
, eventbox);
785
786 desktop_color.red = 0.32;
787 desktop_color.green = 0.46;
788 desktop_color.blue = 0.65;
789 desktop_color.alpha = 1.0;
790
791 override_background_color (eventbox, &desktop_color);
792
793 i = 0;
794 while (i < BUTTON_LAYOUT_COMBINATIONS(META_BUTTON_FUNCTION_LAST + 1 + 1))
795 {
796 GtkWidget *eventbox2;
797 GtkWidget *preview;
798 char *title;
799
800 eventbox2 = gtk_event_box_new ();
801
802 preview = meta_preview_new ();
803
804 gtk_container_add (GTK_CONTAINER (eventbox2)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((eventbox2)), ((gtk_container_get_type ()))))))
, preview);
805
806 meta_preview_set_theme (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, global_theme);
807
808 title = g_strdup_printf (_("Button layout test %d")gettext ("Button layout test %d"), i+1);
809 meta_preview_set_title (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
, title);
810 g_free (title);
811
812 meta_preview_set_button_layout (META_PREVIEW (preview)((((MetaPreview*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((preview)), ((meta_preview_get_type ()))))))
,
813 &different_layouts[i]);
814
815 gtk_widget_set_halign (eventbox2, GTK_ALIGN_FILL);
816
817 gtk_box_pack_start (GTK_BOX (box)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((gtk_box_get_type ()))))))
, eventbox2, TRUE(!(0)), TRUE(!(0)), 0);
818
819 previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + i] = preview;
820
821 ++i;
822 }
823
824 return sw;
825}
826
827static GtkWidget*
828benchmark_summary (void)
829{
830 char *msg;
831 GtkWidget *label;
832
833 msg = g_strdup_printf (_("%g milliseconds to draw one window frame")gettext ("%g milliseconds to draw one window frame"),
834 milliseconds_to_draw_frame);
835 label = gtk_label_new (msg);
836 g_free (msg);
837
838 return label;
839}
840
841int
842main (int argc, char **argv)
843{
844 GtkWidget *window;
845 GtkWidget *collection;
846 GtkStyleContext *style;
847 PangoFontDescription *font_desc;
848 GError *err;
849 clock_t start, end;
850 GtkWidget *notebook;
851 int i;
852
853 bindtextdomain (GETTEXT_PACKAGE"marco", MARCO_LOCALEDIR"/usr/local/share/locale");
854 textdomain(GETTEXT_PACKAGE"marco");
855 bind_textdomain_codeset(GETTEXT_PACKAGE"marco", "UTF-8");
856
857 gtk_init (&argc, &argv);
858
859 if (g_getenv ("MARCO_DEBUG") != NULL((void*)0))
860 {
861 meta_set_debugging (TRUE(!(0)));
862 meta_set_verbose (TRUE(!(0)));
863 }
864
865 start = clock ();
866 err = NULL((void*)0);
867 if (argc == 1)
868 global_theme = meta_theme_load ("ClearlooksRe", &err);
869 else if (argc == 2)
870 global_theme = meta_theme_load (argv[1], &err);
871 else
872 {
873 g_printerr (_("Usage: marco-theme-viewer [THEMENAME]\n")gettext ("Usage: marco-theme-viewer [THEMENAME]\n"));
874 exit (1);
875 }
876 end = clock ();
877
878 if (global_theme == NULL((void*)0))
879 {
880 g_printerr (_("Error loading theme: %s\n")gettext ("Error loading theme: %s\n"),
881 err->message);
882 g_error_free (err);
883 exit (1);
884 }
885
886 g_print (_("Loaded theme \"%s\" in %g seconds\n")gettext ("Loaded theme \"%s\" in %g seconds\n"),
887 global_theme->name,
888 (end - start) / (double) CLOCKS_PER_SEC((__clock_t) 1000000));
889
890 run_theme_benchmark ();
891
892 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
893 gtk_window_set_default_size (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
, 350, 350);
894
895 if (strcmp (global_theme->name, global_theme->readable_name)==0)
896 gtk_window_set_title (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
,
897 global_theme->readable_name);
898 else
899 {
900 /* The theme directory name is different from the name the theme
901 * gives itself within its file. Display both, directory name first.
902 */
903 gchar *title = g_strconcat (global_theme->name, " - ",
This statement is never executed
904 global_theme->readable_name,
905 NULL((void*)0));
906
907 gtk_window_set_title (GTK_WINDOW (window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_window_get_type ()))))))
,
908 title);
909
910 g_free (title);
911 }
912
913 g_signal_connect (G_OBJECT (window), "destroy",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((window)), (((GType) ((20) << (2)))
)))))), ("destroy"), (((GCallback) (gtk_main_quit))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
914 G_CALLBACK (gtk_main_quit), NULL)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((window)), (((GType) ((20) << (2)))
)))))), ("destroy"), (((GCallback) (gtk_main_quit))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
915
916 gtk_widget_realize (window);
917 style = gtk_widget_get_style_context (window);
918 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL,
919 GTK_STYLE_PROPERTY_FONT"font", &font_desc,
920 NULL((void*)0));
921
922 g_assert (style)do { if (style) ; else g_assertion_message_expr ("marco", "ui/theme-viewer.c"
, 922, ((const char*) (__func__)), "style"); } while (0)
;
923 g_assert (font_desc)do { if (font_desc) ; else g_assertion_message_expr ("marco",
"ui/theme-viewer.c", 923, ((const char*) (__func__)), "font_desc"
); } while (0)
;
924
925 notebook = gtk_notebook_new ();
926 gtk_container_add (GTK_CONTAINER (window)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((gtk_container_get_type ()))))))
, notebook);
927
928 collection = preview_collection (FONT_SIZE_NORMAL,
929 font_desc);
930 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
931 collection,
932 gtk_label_new (_("Normal Title Font")gettext ("Normal Title Font")));
933
934 collection = preview_collection (FONT_SIZE_SMALL,
935 font_desc);
936 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
937 collection,
938 gtk_label_new (_("Small Title Font")gettext ("Small Title Font")));
939
940 collection = preview_collection (FONT_SIZE_LARGE,
941 font_desc);
942 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
943 collection,
944 gtk_label_new (_("Large Title Font")gettext ("Large Title Font")));
945
946 collection = previews_of_button_layouts ();
947 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
948 collection,
949 gtk_label_new (_("Button Layouts")gettext ("Button Layouts")));
950
951 collection = benchmark_summary ();
952 gtk_notebook_append_page (GTK_NOTEBOOK (notebook)((((GtkNotebook*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((notebook)), ((gtk_notebook_get_type ()))))))
,
953 collection,
954 gtk_label_new (_("Benchmark")gettext ("Benchmark")));
955
956 pango_font_description_free (font_desc);
957
958 i = 0;
959 while (i < (int) G_N_ELEMENTS (previews)(sizeof (previews) / sizeof ((previews)[0])))
960 {
961 /* preview widget likes to be realized before its size request.
962 * it's lame that way.
963 */
964 gtk_widget_realize (previews[i]);
965
966 ++i;
967 }
968
969 gtk_widget_show_all (window);
970
971 gtk_main ();
972
973 return 0;
974}
975
976static MetaFrameFlags
977get_flags (GtkWidget *widget)
978{
979 return META_FRAME_ALLOWS_DELETE |
980 META_FRAME_ALLOWS_MENU |
981 META_FRAME_ALLOWS_MINIMIZE |
982 META_FRAME_ALLOWS_MAXIMIZE |
983 META_FRAME_ALLOWS_VERTICAL_RESIZE |
984 META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
985 META_FRAME_HAS_FOCUS |
986 META_FRAME_ALLOWS_SHADE |
987 META_FRAME_ALLOWS_MOVE;
988}
989
990static int
991get_text_height (GtkWidget *widget)
992{
993 GtkStyleContext *style;
994 PangoFontDescription *font_desc;
995 int text_height;
996
997 style = gtk_widget_get_style_context (widget);
998 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL,
999 GTK_STYLE_PROPERTY_FONT"font", &font_desc,
1000 NULL((void*)0));
1001 text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget));
1002 pango_font_description_free (font_desc);
1003
1004 return text_height;
1005}
1006
1007static PangoLayout*
1008create_title_layout (GtkWidget *widget)
1009{
1010 PangoLayout *layout;
1011
1012 layout = gtk_widget_create_pango_layout (widget, _("Window Title Goes Here")gettext ("Window Title Goes Here"));
1013
1014 return layout;
1015}
1016
1017static void
1018run_theme_benchmark (void)
1019{
1020 GtkWidget* widget;
1021 cairo_surface_t *pixmap;
1022 cairo_t *cr;
1023 MetaFrameBorders borders;
1024 MetaButtonState button_states[META_BUTTON_TYPE_LAST] =
1025 {
1026 META_BUTTON_STATE_NORMAL,
1027 META_BUTTON_STATE_NORMAL,
1028 META_BUTTON_STATE_NORMAL,
1029 META_BUTTON_STATE_NORMAL
1030 };
1031 PangoLayout *layout;
1032 clock_t start;
1033 clock_t end;
1034 GTimer *timer;
1035 int i;
1036 MetaButtonLayout button_layout;
1037#define ITERATIONS 100
1038 int client_width;
1039 int client_height;
1040 int inc;
1041
1042 widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1043 gtk_widget_realize (widget);
1044
1045 meta_theme_get_frame_borders (global_theme,
1046 META_FRAME_TYPE_NORMAL,
1047 get_text_height (widget),
1048 get_flags (widget),
1049 &borders);
1050
1051 layout = create_title_layout (widget);
1052
1053 i = 0;
1054 while (i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
1055 {
1056 button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1057 button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1058 ++i;
1059 }
1060
1061 button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
1062
1063 button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
1064 button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
1065 button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
1066
1067 timer = g_timer_new ();
1068 start = clock ();
1069
1070 client_width = 50;
1071 client_height = 50;
1072 inc = 1000 / ITERATIONS; /* Increment to grow width/height,
1073 * eliminates caching effects.
1074 */
1075
1076 i = 0;
1077 while (i < ITERATIONS)
1078 {
1079 /* Creating the pixmap in the loop is right, since
1080 * GDK does the same with its double buffering.
1081 */
1082 pixmap = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
1083 CAIRO_CONTENT_COLOR,
1084 client_width + borders.total.left + borders.total.right,
1085 client_height + borders.total.top + borders.total.bottom);
1086 cr = cairo_create (pixmap);
1087
1088 meta_theme_draw_frame (global_theme,
1089 gtk_widget_get_style_context (widget),
1090 cr,
1091 META_FRAME_TYPE_NORMAL,
1092 get_flags (widget),
1093 client_width, client_height,
1094 layout,
1095 get_text_height (widget),
1096 &button_layout,
1097 button_states,
1098 meta_preview_get_mini_icon (),
1099 meta_preview_get_icon ());
1100
1101 cairo_destroy (cr);
1102 cairo_surface_destroy (pixmap);
1103
1104 ++i;
1105 client_width += inc;
1106 client_height += inc;
1107 }
1108
1109 end = clock ();
1110 g_timer_stop (timer);
1111
1112 milliseconds_to_draw_frame = (g_timer_elapsed (timer, NULL((void*)0)) / (double) ITERATIONS) * 1000;
1113
1114 g_print (_("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n")gettext ("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n"
)
,
1115 ITERATIONS,
1116 ((double)end - (double)start) / CLOCKS_PER_SEC((__clock_t) 1000000),
1117 (((double)end - (double)start) / CLOCKS_PER_SEC((__clock_t) 1000000) / (double) ITERATIONS) * 1000,
1118 g_timer_elapsed (timer, NULL((void*)0)),
1119 milliseconds_to_draw_frame);
1120
1121 g_timer_destroy (timer);
1122 g_object_unref (G_OBJECT (layout)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((layout)), (((GType) ((20) << (2))))))))
);
1123 gtk_widget_destroy (widget);
1124
1125#undef ITERATIONS
1126}
1127
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6a7c12.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6a7c12.html new file mode 100644 index 00000000..4d5831a9 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6a7c12.html @@ -0,0 +1,1117 @@ + + + +core/bell.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/bell.c
Warning:line 401, column 2
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bell.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/bell.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco visual bell */
4
5/*
6 * Copyright (C) 2002 Sun Microsystems Inc.
7 * Copyright (C) 2005, 2006 Elijah Newren
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25/**
26 * \file bell.c Ring the bell or flash the screen
27 *
28 * Sometimes, X programs "ring the bell", whatever that means. Marco lets
29 * the user configure the bell to be audible or visible (aka visual), and
30 * if it's visual it can be configured to be frame-flash or fullscreen-flash.
31 * We never get told about audible bells; X handles them just fine by itself.
32 *
33 * Visual bells come in at meta_bell_notify(), which checks we are actually
34 * in visual mode and calls through to bell_visual_notify(). That
35 * function then checks what kind of visual flash you like, and calls either
36 * bell_flash_fullscreen()-- which calls bell_flash_screen() to do
37 * its work-- or bell_flash_frame(), which flashes the focussed window
38 * using bell_flash_window_frame(), unless there is no such window, in
39 * which case it flashes the screen instead. bell_flash_window_frame()
40 * flashes the frame and calls bell_unflash_frame() as a timeout to
41 * remove the flash.
42 *
43 * The visual bell was the result of a discussion in Bugzilla here:
44 * <http://bugzilla.gnome.org/show_bug.cgi?id=99886>.
45 *
46 * Several of the functions in this file are ifdeffed out entirely if we are
47 * found not to have the XKB extension, which is required to do these clever
48 * things with bells; some others are entirely no-ops in that case.
49 */
50
51#include <config.h>
52#include <glib/gi18n-lib.h>
53
54#include "bell.h"
55#include "screen-private.h"
56#include "prefs.h"
57#include <canberra-gtk.h>
58
59#ifdef HAVE_XKB
60/**
61 * Flashes one entire screen. This is done by making a window the size of the
62 * whole screen (or reusing the old one, if it's still around), mapping it,
63 * painting it white and then black, and then unmapping it. We set saveunder so
64 * that all the windows behind it come back immediately.
65 *
66 * Unlike frame flashes, we don't do fullscreen flashes with a timeout; rather,
67 * we do them in one go, because we don't have to rely on the theme code
68 * redrawing the frame for us in order to do the flash.
69 *
70 * \param display The display which owns the screen (rather redundant)
71 * \param screen The screen to flash
72 *
73 * \bug The way I read it, this appears not to do the flash
74 * the first time we flash a particular display. Am I wrong?
75 *
76 * \bug This appears to destroy our current XSync status.
77 */
78static void
79bell_flash_screen (MetaDisplay *display,
80 MetaScreen *screen)
81{
82 Window root = screen->xroot;
83 int width = screen->rect.width;
84 int height = screen->rect.height;
85
86 if (screen->flash_window == None0L)
87 {
88 Visual *visual = (Visual *)CopyFromParent0L;
89 XSetWindowAttributes xswa;
90 int depth = CopyFromParent0L;
91 xswa.save_under = True1;
92 xswa.override_redirect = True1;
93 /*
94 * TODO: use XGetVisualInfo and determine which is an
95 * overlay, if one is present, and use the Overlay visual
96 * for this window (for performance reasons).
97 * Not sure how to tell this yet...
98 */
99 screen->flash_window = XCreateWindow (display->xdisplay, root,
100 0, 0, width, height,
101 0, depth,
102 InputOutput1,
103 visual,
104 /* note: XSun doesn't like SaveUnder here */
105 CWSaveUnder(1L<<10) | CWOverrideRedirect(1L<<9),
106 &xswa);
107 XSelectInput (display->xdisplay, screen->flash_window, ExposureMask(1L<<15));
108 XMapWindow (display->xdisplay, screen->flash_window);
109 XSync (display->xdisplay, False0);
110 XFlush (display->xdisplay);
111 XUnmapWindow (display->xdisplay, screen->flash_window);
112 }
113 else
114 {
115 /* just draw something in the window */
116 GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL((void*)0));
117 XMapWindow (display->xdisplay, screen->flash_window);
118 XSetForeground (display->xdisplay, gc,
119 WhitePixel (display->xdisplay,((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->white_pixel)
120 XScreenNumberOfScreen (screen->xscreen))((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->white_pixel)
);
121 XFillRectangle (display->xdisplay, screen->flash_window, gc,
122 0, 0, width, height);
123 XSetForeground (display->xdisplay, gc,
124 BlackPixel (display->xdisplay,((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->black_pixel)
125 XScreenNumberOfScreen (screen->xscreen))((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->black_pixel)
);
126 XFillRectangle (display->xdisplay, screen->flash_window, gc,
127 0, 0, width, height);
128 XFlush (display->xdisplay);
129 XSync (display->xdisplay, False0);
130 XUnmapWindow (display->xdisplay, screen->flash_window);
131 XFreeGC (display->xdisplay, gc);
132 }
133
134 if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK &&
135 !display->mouse_mode)
136 meta_display_increment_focus_sentinel (display);
137 XFlush (display->xdisplay);
138}
139#endif /* HAVE_XKB */
140
141/**
142 * Flashes one screen, or all screens, in response to a bell event.
143 * If the event is on a particular window, flash the screen that
144 * window is on. Otherwise, flash every screen on this display.
145 *
146 * If the configure script found we had no XKB, this does not exist.
147 *
148 * \param display The display the event came in on
149 * \param xkb_ev The bell event
150 */
151#ifdef HAVE_XKB
152static void
153bell_flash_fullscreen (MetaDisplay *display,
154 XkbAnyEvent *xkb_ev)
155{
156 XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
157 MetaScreen *screen;
158
159 g_assert (xkb_ev->xkb_type == XkbBellNotify)do { if (xkb_ev->xkb_type == 8) ; else g_assertion_message_expr
("marco", "core/bell.c", 159, ((const char*) (__func__)), "xkb_ev->xkb_type == XkbBellNotify"
); } while (0)
;
160 if (xkb_bell_ev->window != None0L)
161 {
162 screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
163 if (screen)
164 bell_flash_screen (display, screen);
165 }
166 else
167 {
168 GSList *screen_list = display->screens;
169 while (screen_list)
170 {
171 screen = (MetaScreen *) screen_list->data;
172 bell_flash_screen (display, screen);
173 screen_list = screen_list->next;
174 }
175 }
176}
177
178/**
179 * Makes a frame be not flashed; this is the timeout half of
180 * bell_flash_window_frame(). This is done simply by clearing the
181 * flash flag and queuing a redraw of the frame.
182 *
183 * If the configure script found we had no XKB, this does not exist.
184 *
185 * \param data The frame to unflash, cast to a gpointer so it can go into
186 * a callback function.
187 * \return Always FALSE, so we don't get called again.
188 *
189 * \bug This is the parallel to bell_flash_window_frame(), so it should
190 * really be called meta_bell_unflash_window_frame().
191 */
192static gboolean
193bell_unflash_frame (gpointer data)
194{
195 MetaFrame *frame = (MetaFrame *) data;
196 frame->is_flashing = 0;
197 meta_frame_queue_draw (frame);
198 return FALSE(0);
199}
200
201/**
202 * Makes a frame flash and then return to normal shortly afterwards.
203 * This is done by setting a flag so that the theme
204 * code will temporarily draw the frame as focussed if it's unfocussed and
205 * vice versa, and then queueing a redraw. Lastly, we create a timeout so
206 * that the flag can be unset and the frame re-redrawn.
207 *
208 * If the configure script found we had no XKB, this does not exist.
209 *
210 * \param window The window to flash
211 */
212static void
213bell_flash_window_frame (MetaWindow *window)
214{
215 g_assert (window->frame != NULL)do { if (window->frame != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/bell.c", 215, ((const char*) (__func__)), "window->frame != NULL"
); } while (0)
;
216 window->frame->is_flashing = 1;
217 meta_frame_queue_draw (window->frame);
218 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE200, 100,
219 bell_unflash_frame, window->frame, NULL((void*)0));
220}
221
222/**
223 * Flashes the frame of the focussed window. If there is no focussed window,
224 * flashes the screen.
225 *
226 * \param display The display the bell event came in on
227 * \param xkb_ev The bell event we just received
228 */
229static void
230bell_flash_frame (MetaDisplay *display,
231 XkbAnyEvent *xkb_ev)
232{
233 XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
234 MetaWindow *window;
235
236 g_assert (xkb_ev->xkb_type == XkbBellNotify)do { if (xkb_ev->xkb_type == 8) ; else g_assertion_message_expr
("marco", "core/bell.c", 236, ((const char*) (__func__)), "xkb_ev->xkb_type == XkbBellNotify"
); } while (0)
;
237 window = meta_display_lookup_x_window (display, xkb_bell_event->window);
238 if (!window && (display->focus_window))
239 {
240 window = display->focus_window;
241 }
242 if (window && window->frame)
243 {
244 bell_flash_window_frame (window);
245 }
246 else /* revert to fullscreen flash if there's no focussed window */
247 {
248 bell_flash_fullscreen (display, xkb_ev);
249 }
250}
251
252/**
253 * Gives the user some kind of visual bell substitute, in response to a
254 * bell event. What this is depends on the "visual bell type" pref.
255 *
256 * If the configure script found we had no XKB, this does not exist.
257 *
258 * \param display The display the bell event came in on
259 * \param xkb_ev The bell event we just received
260 *
261 * \bug This should be merged with meta_bell_notify().
262 */
263static void
264bell_visual_notify (MetaDisplay *display,
265 XkbAnyEvent *xkb_ev)
266{
267 switch (meta_prefs_get_visual_bell_type ())
268 {
269 case META_VISUAL_BELL_FULLSCREEN_FLASH:
270 bell_flash_fullscreen (display, xkb_ev);
271 break;
272 case META_VISUAL_BELL_FRAME_FLASH:
273 bell_flash_frame (display, xkb_ev); /* does nothing yet */
274 break;
275 case META_VISUAL_BELL_INVALID:
276 /* do nothing */
277 break;
278 }
279}
280
281void
282meta_bell_notify (MetaDisplay *display,
283 XkbAnyEvent *xkb_ev)
284{
285 /* flash something */
286 if (meta_prefs_get_visual_bell ())
287 bell_visual_notify (display, xkb_ev);
288
289 if (meta_prefs_bell_is_audible ())
290 {
291 ca_proplist *p;
292 XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
293 MetaWindow *window;
294 int res;
295
296 ca_proplist_create (&p);
297 ca_proplist_sets (p, CA_PROP_EVENT_ID"event.id", "bell-window-system");
298 ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION"event.description", _("Bell event")((char *) g_dgettext ("marco", "Bell event")));
299 ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL"canberra.cache-control", "permanent");
300
301 window = meta_display_lookup_x_window (display, xkb_bell_event->window);
302 if (!window && (display->focus_window) && (display->focus_window->frame))
303 window = display->focus_window;
304
305 if (window)
306 {
307 int x=-1, y=-1, width=-1, height=-1, screen_width=-1, screen_height=-1;
308 MetaScreen *screen;
309
310 screen = meta_window_get_screen (window);
311
312 ca_proplist_sets (p, CA_PROP_WINDOW_NAME"window.name", window->title);
313 ca_proplist_setf (p, CA_PROP_WINDOW_X11_XID"window.x11.xid", "%lu", (unsigned long)window->xwindow);
314 ca_proplist_setf (p, CA_PROP_WINDOW_X11_SCREEN"window.x11.screen", "%i", meta_screen_get_screen_number(screen));
315 ca_proplist_sets (p, CA_PROP_APPLICATION_NAME"application.name", window->res_name);
316 ca_proplist_setf (p, CA_PROP_APPLICATION_PROCESS_ID"application.process.id", "%d", window->net_wm_pid);
317
318 /* properties for positional sound based on window placement */
319 meta_window_get_geometry (window, &x, &y, &width, &height);
320 ca_proplist_setf (p, CA_PROP_WINDOW_X"window.x", "%i", x);
321 ca_proplist_setf (p, CA_PROP_WINDOW_Y"window.y", "%i", y);
322 ca_proplist_setf (p, CA_PROP_WINDOW_WIDTH"window.width", "%i", width);
323 ca_proplist_setf (p, CA_PROP_WINDOW_HEIGHT"window.height", "%i", height);
324
325 meta_screen_get_size (screen, &screen_width, &screen_height);
326 if (screen_width > 1)
327 {
328 x += width/2;
329 x = CLAMP(x, 0, screen_width-1)(((x) > (screen_width-1)) ? (screen_width-1) : (((x) < (
0)) ? (0) : (x)))
;
330
331 /* From libcanberra-gtk.
332 * We use these strange format strings here to avoid that libc
333 * applies locale information on the formatting of floating
334 * numbers. */
335
336 ca_proplist_setf (p, CA_PROP_WINDOW_HPOS"window.hpos", "%i.%03i",
337 (int) (x/(screen_width-1)), (int) (1000.0*x/(screen_width-1)) % 1000);
338 }
339 if (screen_height > 1)
340 {
341 y += height/2;
342 y = CLAMP(y, 0, screen_height-1)(((y) > (screen_height-1)) ? (screen_height-1) : (((y) <
(0)) ? (0) : (y)))
;
343
344 ca_proplist_setf (p, CA_PROP_WINDOW_VPOS"window.vpos", "%i.%03i",
345 (int) (y/(screen_height-1)), (int) (1000.0*y/(screen_height-1)) % 1000);
346 }
347 }
348
349 /* First, we try to play a real sound ... */
350 res = ca_context_play_full (ca_gtk_context_get (), 1, p, NULL((void*)0), NULL((void*)0));
351
352 ca_proplist_destroy (p);
353
354 if (res != CA_SUCCESS && res != CA_ERROR_DISABLED)
355 {
356 /* ...and in case that failed we use the classic X11 bell. */
357 XkbForceDeviceBell (display->xdisplay,
358 xkb_bell_event->device,
359 xkb_bell_event->bell_class,
360 xkb_bell_event->bell_id,
361 xkb_bell_event->percent);
362 }
363 }
364}
365#endif /* HAVE_XKB */
366
367void
368meta_bell_set_audible (MetaDisplay *display, gboolean audible)
369{
370}
371
372gboolean
373meta_bell_init (MetaDisplay *display)
374{
375#ifdef HAVE_XKB
376 int xkb_base_error_type, xkb_opcode;
377
378 if (!XkbQueryExtension (display->xdisplay, &xkb_opcode,
379 &display->xkb_base_event_type,
380 &xkb_base_error_type,
381 NULL((void*)0), NULL((void*)0)))
382 {
383 display->xkb_base_event_type = -1;
384 g_message ("could not find XKB extension.");
385 return FALSE(0);
386 }
387 else
388 {
389 unsigned int mask = XkbBellNotifyMask(1L << 8);
390 gboolean visual_bell_auto_reset = FALSE(0);
391 /* TRUE if and when non-broken version is available */
392 XkbSelectEvents (display->xdisplay,
393 XkbUseCoreKbd0x0100,
394 XkbBellNotifyMask(1L << 8),
395 XkbBellNotifyMask(1L << 8));
396 XkbChangeEnabledControls (display->xdisplay,
397 XkbUseCoreKbd0x0100,
398 XkbAudibleBellMask(1L << 9),
399 0);
400 if (visual_bell_auto_reset) {
401 XkbSetAutoResetControls (display->xdisplay,
This statement is never executed
402 XkbAudibleBellMask(1L << 9),
403 &mask,
404 &mask);
405 }
406 return TRUE(!(0));
407 }
408#endif
409 return FALSE(0);
410}
411
412void
413meta_bell_shutdown (MetaDisplay *display)
414{
415#ifdef HAVE_XKB
416 /* TODO: persist initial bell state in display, reset here */
417 XkbChangeEnabledControls (display->xdisplay,
418 XkbUseCoreKbd0x0100,
419 XkbAudibleBellMask(1L << 9),
420 XkbAudibleBellMask(1L << 9));
421#endif
422}
423
424/**
425 * Deals with a frame being destroyed. This is important because if we're
426 * using a visual bell, we might be flashing the edges of the frame, and
427 * so we'd have a timeout function waiting ready to un-flash them. If the
428 * frame's going away, we can tell the timeout not to bother.
429 *
430 * \param frame The frame which is being destroyed
431 */
432void
433meta_bell_notify_frame_destroy (MetaFrame *frame)
434{
435 if (frame->is_flashing)
436 g_source_remove_by_funcs_user_data (&g_timeout_funcs, frame);
437}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6ce2b4.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6ce2b4.html new file mode 100644 index 00000000..21257445 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6ce2b4.html @@ -0,0 +1,3697 @@ + + + +ui/frames.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/frames.c
Warning:line 1779, column 7
Value stored to 'op' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name frames.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/frames.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco window frame manager widget */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 * Copyright (C) 2003 Red Hat, Inc.
8 * Copyright (C) 2005, 2006 Elijah Newren
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26#include <config.h>
27#include <glib/gi18n-lib.h>
28
29#include <math.h>
30#include <string.h>
31#include "boxes.h"
32#include "frames.h"
33#include "util.h"
34#include "core.h"
35#include "menu.h"
36#include "fixedtip.h"
37#include "theme.h"
38#include "prefs.h"
39#include "ui.h"
40#include "display.h"
41
42#ifdef HAVE_SHAPE
43#include <X11/extensions/shape.h>
44#endif
45
46#include <cairo-xlib.h>
47
48G_DEFINE_TYPE (MetaFrames, meta_frames, GTK_TYPE_WINDOW)static void meta_frames_init (MetaFrames *self); static void meta_frames_class_init
(MetaFramesClass *klass); static GType meta_frames_get_type_once
(void); static gpointer meta_frames_parent_class = ((void*)0
); static gint MetaFrames_private_offset; static void meta_frames_class_intern_init
(gpointer klass) { meta_frames_parent_class = g_type_class_peek_parent
(klass); if (MetaFrames_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MetaFrames_private_offset); meta_frames_class_init
((MetaFramesClass*) klass); } __attribute__ ((__unused__)) static
inline gpointer meta_frames_get_instance_private (MetaFrames
*self) { return (((gpointer) ((guint8*) (self) + (glong) (MetaFrames_private_offset
)))); } GType meta_frames_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = meta_frames_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType meta_frames_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_window_get_type ()), g_intern_static_string ("MetaFrames"
), sizeof (MetaFramesClass), (GClassInitFunc)(void (*)(void))
meta_frames_class_intern_init, sizeof (MetaFrames), (GInstanceInitFunc
)(void (*)(void)) meta_frames_init, (GTypeFlags) 0); { {{};} }
return g_define_type_id; }
;
49
50#define DEFAULT_INNER_BUTTON_BORDER3 3
51
52static void meta_frames_class_init (MetaFramesClass *klass);
53static void meta_frames_init (MetaFrames *frames);
54static void meta_frames_destroy (GtkWidget *object);
55static void meta_frames_finalize (GObject *object);
56static void meta_frames_style_updated (GtkWidget *widget);
57
58static void meta_frames_update_prelit_control (MetaFrames *frames,
59 MetaUIFrame *frame,
60 MetaFrameControl control);
61static gboolean meta_frames_button_press_event (GtkWidget *widget,
62 GdkEventButton *event);
63static gboolean meta_frames_button_release_event (GtkWidget *widget,
64 GdkEventButton *event);
65static gboolean meta_frames_motion_notify_event (GtkWidget *widget,
66 GdkEventMotion *event);
67static gboolean meta_frames_destroy_event (GtkWidget *widget,
68 GdkEventAny *event);
69static gboolean meta_frames_draw (GtkWidget *widget,
70 cairo_t *cr);
71static gboolean meta_frames_enter_notify_event (GtkWidget *widget,
72 GdkEventCrossing *event);
73static gboolean meta_frames_leave_notify_event (GtkWidget *widget,
74 GdkEventCrossing *event);
75
76static void meta_frames_attach_style (MetaFrames *frames,
77 MetaUIFrame *frame);
78
79static void meta_frames_paint_to_drawable (MetaFrames *frames,
80 MetaUIFrame *frame,
81 cairo_t *cr);
82
83static void meta_frames_calc_geometry (MetaFrames *frames,
84 MetaUIFrame *frame,
85 MetaFrameGeometry *fgeom);
86
87static void meta_frames_ensure_layout (MetaFrames *frames,
88 MetaUIFrame *frame);
89
90static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
91 Window xwindow);
92
93static void meta_frames_font_changed (MetaFrames *frames);
94static void meta_frames_button_layout_changed (MetaFrames *frames);
95
96static GdkRectangle* control_rect (MetaFrameControl control,
97 MetaFrameGeometry *fgeom);
98static MetaFrameControl get_control (MetaFrames *frames,
99 MetaUIFrame *frame,
100 int x,
101 int y);
102static void clear_tip (MetaFrames *frames);
103static void invalidate_all_caches (MetaFrames *frames);
104static void invalidate_whole_window (MetaFrames *frames,
105 MetaUIFrame *frame);
106
107static GObject *
108meta_frames_constructor (GType gtype,
109 guint n_properties,
110 GObjectConstructParam *properties)
111{
112 GObject *object;
113 GObjectClass *gobject_class;
114
115 gobject_class = G_OBJECT_CLASS (meta_frames_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), (((GType) ((20) << (2)
)))))))
;
116 object = gobject_class->constructor (gtype, n_properties, properties);
117
118 return object;
119}
120
121static void
122meta_frames_class_init (MetaFramesClass *class)
123{
124 GObjectClass *gobject_class;
125 GtkWidgetClass *widget_class;
126
127 gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
128 widget_class = (GtkWidgetClass*) class;
129
130 gobject_class->constructor = meta_frames_constructor;
131 gobject_class->finalize = meta_frames_finalize;
132 widget_class->destroy = meta_frames_destroy;
133 widget_class->style_updated = meta_frames_style_updated;
134
135 widget_class->draw = meta_frames_draw;
136 widget_class->destroy_event = meta_frames_destroy_event;
137 widget_class->button_press_event = meta_frames_button_press_event;
138 widget_class->button_release_event = meta_frames_button_release_event;
139 widget_class->motion_notify_event = meta_frames_motion_notify_event;
140 widget_class->enter_notify_event = meta_frames_enter_notify_event;
141 widget_class->leave_notify_event = meta_frames_leave_notify_event;
142}
143
144static gint
145unsigned_long_equal (gconstpointer v1,
146 gconstpointer v2)
147{
148 return *((const gulong*) v1) == *((const gulong*) v2);
149}
150
151static guint
152unsigned_long_hash (gconstpointer v)
153{
154 gulong val = * (const gulong *) v;
155
156 /* I'm not sure this works so well. */
157#if GLIB_SIZEOF_LONG8 > 4
158 return (guint) (val ^ (val >> 32));
159#else
160 return val;
161#endif
162}
163
164static void
165prefs_changed_callback (MetaPreference pref,
166 void *data)
167{
168 switch (pref)
169 {
170 case META_PREF_TITLEBAR_FONT:
171 meta_frames_font_changed (META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
);
172 break;
173 case META_PREF_BUTTON_LAYOUT:
174 meta_frames_button_layout_changed (META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
);
175 break;
176 default:
177 break;
178 }
179}
180
181static GtkStyleContext *
182create_style_context (MetaFrames *frames,
183 const gchar *variant)
184{
185 GtkStyleContext *style;
186 GdkScreen *screen;
187 char *theme_name;
188
189 screen = gtk_widget_get_screen (GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
);
190 g_object_get (gtk_settings_get_for_screen (screen),
191 "gtk-theme-name", &theme_name,
192 NULL((void*)0));
193
194 style = gtk_style_context_new ();
195 gtk_style_context_set_path (style,
196 gtk_widget_get_path (GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
));
197
198 if (theme_name && *theme_name)
199 {
200 GtkCssProvider *provider;
201
202 provider = gtk_css_provider_get_named (theme_name, variant);
203 gtk_style_context_add_provider (style,
204 GTK_STYLE_PROVIDER (provider)((((GtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((gtk_style_provider_get_type (
)))))))
,
205 GTK_STYLE_PROVIDER_PRIORITY_SETTINGS400);
206 }
207
208 if (theme_name)
209 g_free (theme_name);
210
211 return style;
212}
213
214static GtkStyleContext *
215meta_frames_get_theme_variant (MetaFrames *frames,
216 const gchar *variant)
217{
218 GtkStyleContext *style;
219
220 style = g_hash_table_lookup (frames->style_variants, variant);
221 if (style == NULL((void*)0))
222 {
223 style = create_style_context (frames, variant);
224 g_hash_table_insert (frames->style_variants, g_strdup (variant)g_strdup_inline (variant), style);
225 }
226
227 return style;
228}
229
230static void
231update_style_contexts (MetaFrames *frames)
232{
233 GtkStyleContext *style;
234 GList *variant_list, *variant;
235
236 if (frames->normal_style)
237 g_object_unref (frames->normal_style);
238 frames->normal_style = create_style_context (frames, NULL((void*)0));
239
240 variant_list = g_hash_table_get_keys (frames->style_variants);
241 for (variant = variant_list; variant; variant = variant->next)
242 {
243 style = create_style_context (frames, (char *)variant->data);
244 g_hash_table_insert (frames->style_variants,
245 g_strdup (variant->data)g_strdup_inline (variant->data), style);
246 }
247 g_list_free (variant_list);
248}
249static void
250meta_frames_init (MetaFrames *frames)
251{
252 frames->text_heights = g_hash_table_new (NULL((void*)0), NULL((void*)0));
253
254 frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
255
256 frames->tooltip_timeout = 0;
257
258 frames->expose_delay_count = 0;
259
260 frames->invalidate_cache_timeout_id = 0;
261 frames->invalidate_frames = NULL((void*)0);
262 frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
263 frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal,
264 g_free, g_object_unref);
265 update_style_contexts (frames);
266
267 meta_prefs_add_listener (prefs_changed_callback, frames);
268}
269
270static void
271listify_func (gpointer key, gpointer value, gpointer data)
272{
273 GSList **listp;
274
275 listp = data;
276 *listp = g_slist_prepend (*listp, value);
277}
278
279static void
280meta_frames_destroy (GtkWidget *widget)
281{
282 GSList *winlist;
283 GSList *tmp;
284 MetaFrames *frames;
285
286 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
287
288 clear_tip (frames);
289
290 winlist = NULL((void*)0);
291 g_hash_table_foreach (frames->frames, listify_func, &winlist);
292
293 /* Unmanage all frames */
294 for (tmp = winlist; tmp != NULL((void*)0); tmp = tmp->next)
295 {
296 MetaUIFrame *frame;
297
298 frame = tmp->data;
299
300 meta_frames_unmanage_window (frames, frame->xwindow);
301 }
302 g_slist_free (winlist);
303
304 if (frames->normal_style)
305 {
306 g_object_unref (frames->normal_style);
307 frames->normal_style = NULL((void*)0);
308 }
309
310 if (frames->style_variants)
311 {
312 g_hash_table_destroy (frames->style_variants);
313 frames->style_variants = NULL((void*)0);
314 }
315
316 GTK_WIDGET_CLASS (meta_frames_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), ((gtk_widget_get_type ()))))
))
->destroy (widget);
317}
318
319static void
320meta_frames_finalize (GObject *object)
321{
322 MetaFrames *frames;
323
324 frames = META_FRAMES (object)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((meta_frames_get_type ()))))))
;
325
326 meta_prefs_remove_listener (prefs_changed_callback, frames);
327
328 g_hash_table_destroy (frames->text_heights);
329
330 invalidate_all_caches (frames);
331 if (frames->invalidate_cache_timeout_id)
332 g_source_remove (frames->invalidate_cache_timeout_id);
333
334 g_assert (g_hash_table_size (frames->frames) == 0)do { if (g_hash_table_size (frames->frames) == 0) ; else g_assertion_message_expr
("marco", "ui/frames.c", 334, ((const char*) (__func__)), "g_hash_table_size (frames->frames) == 0"
); } while (0)
;
335 g_hash_table_destroy (frames->frames);
336 g_hash_table_destroy (frames->cache);
337
338 G_OBJECT_CLASS (meta_frames_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), (((GType) ((20) << (2)
)))))))
->finalize (object);
339}
340
341typedef struct
342{
343 cairo_rectangle_int_t rect;
344 cairo_surface_t *pixmap;
345} CachedFramePiece;
346
347typedef struct
348{
349 /* Caches of the four rendered sides in a MetaFrame.
350 * Order: top (titlebar), left, right, bottom.
351 */
352 CachedFramePiece piece[4];
353} CachedPixels;
354
355static CachedPixels *
356get_cache (MetaFrames *frames,
357 MetaUIFrame *frame)
358{
359 CachedPixels *pixels;
360
361 pixels = g_hash_table_lookup (frames->cache, frame);
362
363 if (!pixels)
364 {
365 pixels = g_new0 (CachedPixels, 1)((CachedPixels *) g_malloc0_n ((1), sizeof (CachedPixels)));
366 g_hash_table_insert (frames->cache, frame, pixels);
367 }
368
369 return pixels;
370}
371
372static void
373invalidate_cache (MetaFrames *frames,
374 MetaUIFrame *frame)
375{
376 CachedPixels *pixels = get_cache (frames, frame);
377 int i;
378
379 for (i = 0; i < 4; i++)
380 if (pixels->piece[i].pixmap)
381 cairo_surface_destroy (pixels->piece[i].pixmap);
382
383 g_free (pixels);
384 g_hash_table_remove (frames->cache, frame);
385}
386
387static void
388invalidate_all_caches (MetaFrames *frames)
389{
390 GList *l;
391
392 for (l = frames->invalidate_frames; l; l = l->next)
393 {
394 MetaUIFrame *frame = l->data;
395
396 invalidate_cache (frames, frame);
397 }
398
399 g_list_free (frames->invalidate_frames);
400 frames->invalidate_frames = NULL((void*)0);
401}
402
403static gboolean
404invalidate_cache_timeout (gpointer data)
405{
406 MetaFrames *frames = data;
407
408 invalidate_all_caches (frames);
409 frames->invalidate_cache_timeout_id = 0;
410 return FALSE(0);
411}
412
413static void
414queue_recalc_func (gpointer key, gpointer value, gpointer data)
415{
416 MetaUIFrame *frame;
417 MetaFrames *frames;
418
419 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
420 frame = value;
421
422 invalidate_whole_window (frames, frame);
423 meta_core_queue_frame_resize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
424 frame->xwindow);
425 if (frame->text_layout)
426 {
427 /* save title to recreate layout */
428 g_free (frame->title);
429
430 frame->title = g_strdup (pango_layout_get_text (frame->text_layout))g_strdup_inline (pango_layout_get_text (frame->text_layout
))
;
431
432 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
433 }
434}
435
436static void
437meta_frames_font_changed (MetaFrames *frames)
438{
439 if (g_hash_table_size (frames->text_heights) > 0)
440 {
441 g_hash_table_destroy (frames->text_heights);
442 frames->text_heights = g_hash_table_new (NULL((void*)0), NULL((void*)0));
443 }
444
445 /* Queue a draw/resize on all frames */
446 g_hash_table_foreach (frames->frames,
447 queue_recalc_func, frames);
448
449}
450
451static void
452queue_draw_func (gpointer key, gpointer value, gpointer data)
453{
454 MetaUIFrame *frame;
455 MetaFrames *frames;
456
457 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
458 frame = value;
459
460 invalidate_whole_window (frames, frame);
461}
462
463static void
464meta_frames_button_layout_changed (MetaFrames *frames)
465{
466 g_hash_table_foreach (frames->frames,
467 queue_draw_func, frames);
468}
469
470static void
471reattach_style_func (gpointer key, gpointer value, gpointer data)
472{
473 MetaUIFrame *frame;
474 MetaFrames *frames;
475
476 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
477 frame = value;
478
479 meta_frames_attach_style (frames, frame);
480}
481
482static void
483meta_frames_style_updated (GtkWidget *widget)
484{
485 MetaFrames *frames;
486
487 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
488
489 meta_frames_font_changed (frames);
490
491 update_style_contexts (frames);
492 g_hash_table_foreach (frames->frames,
493 reattach_style_func, frames);
494
495 GTK_WIDGET_CLASS (meta_frames_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), ((gtk_widget_get_type ()))))
))
->style_updated (widget);
496}
497
498static void
499meta_frames_ensure_layout (MetaFrames *frames,
500 MetaUIFrame *frame)
501{
502 GtkWidget *widget;
503 MetaFrameFlags flags;
504 MetaFrameType type;
505 MetaFrameStyle *style;
506
507 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (frames)))do { if ((gtk_widget_get_realized (((((GtkWidget*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((frames)), ((gtk_widget_get_type ()))))))
))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "gtk_widget_get_realized (GTK_WIDGET (frames))"
); return; } } while (0)
;
508
509 widget = GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
;
510
511 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
512 META_CORE_GET_FRAME_FLAGS, &flags,
513 META_CORE_GET_FRAME_TYPE, &type,
514 META_CORE_GET_END);
515
516 style = meta_theme_get_frame_style (meta_theme_get_current (),
517 type, flags);
518
519 if (style != frame->cache_style)
520 {
521 if (frame->text_layout)
522 {
523 /* save title to recreate layout */
524 g_free (frame->title);
525
526 frame->title = g_strdup (pango_layout_get_text (frame->text_layout))g_strdup_inline (pango_layout_get_text (frame->text_layout
))
;
527
528 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
529 }
530 }
531
532 frame->cache_style = style;
533
534 if (frame->text_layout == NULL((void*)0))
535 {
536 gpointer key, value;
537 PangoFontDescription *font_desc;
538 double scale;
539 int size;
540
541 scale = meta_theme_get_title_scale (meta_theme_get_current (),
542 type,
543 flags);
544
545 frame->text_layout = gtk_widget_create_pango_layout (widget, frame->title);
546
547 pango_layout_set_ellipsize (frame->text_layout, PANGO_ELLIPSIZE_END);
548 pango_layout_set_auto_dir (frame->text_layout, FALSE(0));
549
550 pango_layout_set_single_paragraph_mode (frame->text_layout, TRUE(!(0)));
551
552 font_desc = meta_gtk_widget_get_font_desc (widget, scale,
553 meta_prefs_get_titlebar_font ());
554
555 size = pango_font_description_get_size (font_desc);
556
557 if (g_hash_table_lookup_extended (frames->text_heights,
558 GINT_TO_POINTER (size)((gpointer) (glong) (size)),
559 &key, &value))
560 {
561 frame->text_height = GPOINTER_TO_INT (value)((gint) (glong) (value));
562 }
563 else
564 {
565 frame->text_height =
566 meta_pango_font_desc_get_text_height (font_desc,
567 gtk_widget_get_pango_context (widget));
568
569 g_hash_table_replace (frames->text_heights,
570 GINT_TO_POINTER (size)((gpointer) (glong) (size)),
571 GINT_TO_POINTER (frame->text_height)((gpointer) (glong) (frame->text_height)));
572 }
573
574 pango_layout_set_font_description (frame->text_layout,
575 font_desc);
576
577 pango_font_description_free (font_desc);
578
579 /* Save some RAM */
580 g_free (frame->title);
581 frame->title = NULL((void*)0);
582 }
583}
584
585static void
586meta_frames_calc_geometry (MetaFrames *frames,
587 MetaUIFrame *frame,
588 MetaFrameGeometry *fgeom)
589{
590 int width, height, scale;
591 MetaFrameFlags flags;
592 MetaFrameType type;
593 MetaButtonLayout button_layout;
594
595 scale = gdk_window_get_scale_factor (frame->window);
596
597 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
598 META_CORE_GET_CLIENT_WIDTH, &width,
599 META_CORE_GET_CLIENT_HEIGHT, &height,
600 META_CORE_GET_FRAME_FLAGS, &flags,
601 META_CORE_GET_FRAME_TYPE, &type,
602 META_CORE_GET_END);
603
604 meta_frames_ensure_layout (frames, frame);
605
606 meta_prefs_get_button_layout (&button_layout);
607
608 meta_theme_calc_geometry (meta_theme_get_current (),
609 type,
610 frame->text_height,
611 flags,
612 width / scale, height / scale,
613 &button_layout,
614 fgeom);
615}
616
617MetaFrames*
618meta_frames_new (void)
619{
620 GdkScreen *screen;
621 MetaFrames *frames;
622
623 screen = gdk_display_get_default_screen (gdk_display_get_default ());
624
625 frames = g_object_new (META_TYPE_FRAMES(meta_frames_get_type ()),
626 "screen", screen,
627 "type", GTK_WINDOW_POPUP,
628 NULL((void*)0));
629
630 /* Put the window at an arbitrary offscreen location; the one place
631 * it can't be is at -100x-100, since the meta_window_new() will
632 * mistake it for a window created via meta_create_offscreen_window()
633 * and ignore it, and we need this window to get frame-synchronization
634 * messages so that GTK+'s style change handling works.
635 */
636 gtk_window_move (GTK_WINDOW (frames)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_window_get_type ()))))))
, -200, -200);
637 gtk_window_resize (GTK_WINDOW (frames)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_window_get_type ()))))))
, 1, 1);
638
639 return frames;
640}
641
642/* In order to use a style with a window it has to be attached to that
643 * window. Actually, the colormaps just have to match, but since GTK+
644 * already takes care of making sure that its cheap to attach a style
645 * to multiple windows with the same colormap, we can just go ahead
646 * and attach separately for each window.
647 */
648static void
649meta_frames_attach_style (MetaFrames *frames,
650 MetaUIFrame *frame)
651{
652 gboolean has_frame;
653 char *variant = NULL((void*)0);
654 if (frame->style != NULL((void*)0))
655 g_object_unref (frame->style);
656
657 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
658 frame->xwindow,
659 META_CORE_WINDOW_HAS_FRAME, &has_frame,
660 META_CORE_GET_THEME_VARIANT, &variant,
661 META_CORE_GET_END);
662
663 if (variant == NULL((void*)0) || strcmp(variant, "normal") == 0)
664 frame->style = g_object_ref (frames->normal_style)((__typeof__ (frames->normal_style)) (g_object_ref) (frames
->normal_style))
;
665 else
666 frame->style = g_object_ref (meta_frames_get_theme_variant (frames,((__typeof__ (meta_frames_get_theme_variant (frames, variant)
)) (g_object_ref) (meta_frames_get_theme_variant (frames, variant
)))
667 variant))((__typeof__ (meta_frames_get_theme_variant (frames, variant)
)) (g_object_ref) (meta_frames_get_theme_variant (frames, variant
)))
;
668}
669
670void
671meta_frames_manage_window (MetaFrames *frames,
672 Window xwindow,
673 GdkWindow *window)
674{
675 MetaUIFrame *frame;
676
677 g_assert (window)do { if (window) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 677, ((const char*) (__func__)), "window"); } while (0)
;
678
679 frame = g_new (MetaUIFrame, 1)((MetaUIFrame *) g_malloc_n ((1), sizeof (MetaUIFrame)));
680
681 frame->window = window;
682
683 gdk_window_set_user_data (frame->window, frames);
684
685 frame->style = NULL((void*)0);
686
687 /* Don't set event mask here, it's in frame.c */
688
689 frame->xwindow = xwindow;
690 frame->cache_style = NULL((void*)0);
691 frame->text_layout = NULL((void*)0);
692 frame->text_height = -1;
693 frame->title = NULL((void*)0);
694 frame->expose_delayed = FALSE(0);
695 frame->shape_applied = FALSE(0);
696 frame->prelit_control = META_FRAME_CONTROL_NONE;
697
698 meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
699
700 g_hash_table_replace (frames->frames, &frame->xwindow, frame);
701}
702
703void
704meta_frames_unmanage_window (MetaFrames *frames,
705 Window xwindow)
706{
707 MetaUIFrame *frame;
708
709 clear_tip (frames);
710
711 frame = g_hash_table_lookup (frames->frames, &xwindow);
712
713 if (frame)
714 {
715 /* invalidating all caches ensures the frame
716 * is not actually referenced anymore
717 */
718 invalidate_all_caches (frames);
719
720 /* restore the cursor */
721 meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
722 frame->xwindow,
723 META_CURSOR_DEFAULT);
724
725 gdk_window_set_user_data (frame->window, NULL((void*)0));
726
727 if (frames->last_motion_frame == frame)
728 frames->last_motion_frame = NULL((void*)0);
729
730 g_hash_table_remove (frames->frames, &frame->xwindow);
731
732 g_object_unref (frame->style);
733
734 gdk_window_destroy (frame->window);
735
736 if (frame->text_layout)
737 g_object_unref (G_OBJECT (frame->text_layout)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame->text_layout)), (((GType) ((20) << (2))))
))))
);
738
739 if (frame->title)
740 g_free (frame->title);
741
742 g_free (frame);
743 }
744 else
745 meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
746}
747
748static MetaUIFrame*
749meta_frames_lookup_window (MetaFrames *frames,
750 Window xwindow)
751{
752 MetaUIFrame *frame;
753
754 frame = g_hash_table_lookup (frames->frames, &xwindow);
755
756 return frame;
757}
758
759static void
760meta_ui_frame_get_borders (MetaFrames *frames,
761 MetaUIFrame *frame,
762 MetaFrameBorders *borders)
763{
764 MetaFrameFlags flags;
765 MetaFrameType type;
766 gint scale;
767
768 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
769 META_CORE_GET_FRAME_FLAGS, &flags,
770 META_CORE_GET_FRAME_TYPE, &type,
771 META_CORE_GET_END);
772
773 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
774
775 scale = gdk_window_get_scale_factor (frame->window);
776
777 meta_frames_ensure_layout (frames, frame);
778
779 /* We can't get the full geometry, because that depends on
780 * the client window size and probably we're being called
781 * by the core move/resize code to decide on the client
782 * window size
783 */
784 meta_theme_get_frame_borders (meta_theme_get_current (),
785 type,
786 frame->text_height,
787 flags,
788 borders);
789
790 /* Scale frame geometry to ensure proper frame position */
791 borders->visible.top *= scale;
792 borders->visible.bottom *= scale;
793 borders->visible.left *= scale;
794 borders->visible.right *= scale;
795
796 borders->invisible.top *= scale;
797 borders->invisible.bottom *= scale;
798 borders->invisible.left *= scale;
799 borders->invisible.right *= scale;
800
801 borders->total.top *= scale;
802 borders->total.bottom *= scale;
803 borders->total.left *= scale;
804 borders->total.right *= scale;
805}
806
807void
808meta_frames_get_borders (MetaFrames *frames,
809 Window xwindow,
810 MetaFrameBorders *borders)
811{
812 MetaUIFrame *frame;
813
814 frame = meta_frames_lookup_window (frames, xwindow);
815
816 if (frame == NULL((void*)0))
817 g_error ("No such frame 0x%lx\n", xwindow);
818
819 meta_ui_frame_get_borders (frames, frame, borders);
820}
821
822static void
823meta_ui_frame_get_corner_radiuses (MetaFrames *frames,
824 MetaUIFrame *frame,
825 float *top_left,
826 float *top_right,
827 float *bottom_left,
828 float *bottom_right)
829{
830 MetaFrameGeometry fgeom;
831
832 meta_frames_calc_geometry (frames, frame, &fgeom);
833
834 /* For compatibility with the code in get_visible_rect(), there's
835 * a mysterious sqrt() added to the corner radiuses:
836 *
837 * const float radius = sqrt(corner) + corner;
838 *
839 * It's unclear why the radius is calculated like this, but we
840 * need to be consistent with it.
841 */
842
843 if (top_left)
844 *top_left = fgeom.top_left_corner_rounded_radius + sqrt(fgeom.top_left_corner_rounded_radius);
845 if (top_right)
846 *top_right = fgeom.top_right_corner_rounded_radius + sqrt(fgeom.top_right_corner_rounded_radius);
847 if (bottom_left)
848 *bottom_left = fgeom.bottom_left_corner_rounded_radius + sqrt(fgeom.bottom_left_corner_rounded_radius);
849 if (bottom_right)
850 *bottom_right = fgeom.bottom_right_corner_rounded_radius + sqrt(fgeom.bottom_right_corner_rounded_radius);
851}
852
853void
854meta_frames_get_corner_radiuses (MetaFrames *frames,
855 Window xwindow,
856 float *top_left,
857 float *top_right,
858 float *bottom_left,
859 float *bottom_right)
860{
861 MetaUIFrame *frame;
862
863 frame = meta_frames_lookup_window (frames, xwindow);
864
865 meta_ui_frame_get_corner_radiuses (frames, frame, top_left, top_right,
866 bottom_left, bottom_right);
867}
868
869#ifdef HAVE_SHAPE
870static void
871apply_cairo_region_to_window (Display *display,
872 Window xwindow,
873 cairo_region_t *region,
874 int op)
875{
876 int n_rects, i;
877 XRectangle *rects;
878
879 n_rects = cairo_region_num_rectangles (region);
880 rects = g_new (XRectangle, n_rects)((XRectangle *) g_malloc_n ((n_rects), sizeof (XRectangle)));
881
882 for (i = 0; i < n_rects; i++)
883 {
884 cairo_rectangle_int_t rect;
885
886 cairo_region_get_rectangle (region, i, &rect);
887
888 rects[i].x = rect.x;
889 rects[i].y = rect.y;
890 rects[i].width = rect.width;
891 rects[i].height = rect.height;
892 }
893
894 XShapeCombineRectangles (display, xwindow,
895 ShapeBounding0, 0, 0, rects, n_rects,
896 op, YXBanded3);
897
898 g_free (rects);
899}
900#endif
901
902/* The client rectangle surrounds client window; it subtracts both
903 * the visible and invisible borders from the frame window's size.
904 */
905static void
906get_client_rect (MetaFrameGeometry *fgeom,
907 int window_width,
908 int window_height,
909 cairo_rectangle_int_t *rect)
910{
911 rect->x = fgeom->borders.total.left;
912 rect->y = fgeom->borders.total.top;
913 rect->width = window_width - fgeom->borders.total.right - rect->x;
914 rect->height = window_height - fgeom->borders.total.bottom - rect->y;
915}
916
917/* The visible frame rectangle surrounds the visible portion of the
918 * frame window; it subtracts only the invisible borders from the frame
919 * window's size.
920 */
921static void
922get_visible_frame_rect (MetaFrameGeometry *fgeom,
923 int window_width,
924 int window_height,
925 cairo_rectangle_int_t *rect)
926{
927 rect->x = fgeom->borders.invisible.left;
928 rect->y = fgeom->borders.invisible.top;
929 rect->width = window_width - fgeom->borders.invisible.right - rect->x;
930 rect->height = window_height - fgeom->borders.invisible.bottom - rect->y;
931}
932
933static cairo_region_t *
934get_visible_region (MetaFrames *frames,
935 MetaUIFrame *frame,
936 MetaFrameGeometry *fgeom,
937 int window_width,
938 int window_height)
939{
940 cairo_region_t *corners_region;
941 cairo_region_t *visible_region;
942 cairo_rectangle_int_t rect;
943 cairo_rectangle_int_t frame_rect;
944 gint scale;
945
946 corners_region = cairo_region_create ();
947 scale = gdk_window_get_scale_factor (frame->window);
948
949 fgeom->borders.invisible.top *= scale;
950 fgeom->borders.invisible.bottom *= scale;
951 fgeom->borders.invisible.left *= scale;
952 fgeom->borders.invisible.right *= scale;
953
954 get_visible_frame_rect (fgeom, window_width, window_height, &frame_rect);
955
956 if (fgeom->top_left_corner_rounded_radius != 0)
957 {
958 const int corner = fgeom->top_left_corner_rounded_radius * scale;
959 const float radius = sqrt(corner) + corner;
960 int i;
961
962 for (i=0; i<corner; i++)
963 {
964 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
965 rect.x = frame_rect.x;
966 rect.y = frame_rect.y + i;
967 rect.width = width;
968 rect.height = 1;
969
970 cairo_region_union_rectangle (corners_region, &rect);
971 }
972 }
973
974 if (fgeom->top_right_corner_rounded_radius != 0)
975 {
976 const int corner = fgeom->top_right_corner_rounded_radius * scale;
977 const float radius = sqrt(corner) + corner;
978 int i;
979
980 for (i=0; i<corner; i++)
981 {
982 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
983 rect.x = frame_rect.x + frame_rect.width - width;
984 rect.y = frame_rect.y + i;
985 rect.width = width;
986 rect.height = 1;
987
988 cairo_region_union_rectangle (corners_region, &rect);
989 }
990 }
991
992 if (fgeom->bottom_left_corner_rounded_radius != 0)
993 {
994 const int corner = fgeom->bottom_left_corner_rounded_radius * scale;
995 const float radius = sqrt(corner) + corner;
996 int i;
997
998 for (i=0; i<corner; i++)
999 {
1000 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
1001 rect.x = frame_rect.x;
1002 rect.y = frame_rect.y + frame_rect.height - i - 1;
1003 rect.width = width;
1004 rect.height = 1;
1005
1006 cairo_region_union_rectangle (corners_region, &rect);
1007 }
1008 }
1009
1010 if (fgeom->bottom_right_corner_rounded_radius != 0)
1011 {
1012 const int corner = fgeom->bottom_right_corner_rounded_radius * scale;
1013 const float radius = sqrt(corner) + corner;
1014 int i;
1015
1016 for (i=0; i<corner; i++)
1017 {
1018 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
1019 rect.x = frame_rect.x + frame_rect.width - width;
1020 rect.y = frame_rect.y + frame_rect.height - i - 1;
1021 rect.width = width;
1022 rect.height = 1;
1023
1024 cairo_region_union_rectangle (corners_region, &rect);
1025 }
1026 }
1027
1028 visible_region = cairo_region_create_rectangle (&frame_rect);
1029 cairo_region_subtract (visible_region, corners_region);
1030 cairo_region_destroy (corners_region);
1031
1032 return visible_region;
1033}
1034
1035#ifdef HAVE_SHAPE
1036static cairo_region_t *
1037get_client_region (MetaFrameGeometry *fgeom,
1038 int window_width,
1039 int window_height)
1040{
1041 cairo_rectangle_int_t rect;
1042
1043 rect.x = fgeom->borders.total.left;
1044 rect.y = fgeom->borders.total.top;
1045 rect.width = window_width - fgeom->borders.total.right - rect.x;
1046 rect.height = window_height - fgeom->borders.total.bottom - rect.y;
1047
1048 return cairo_region_create_rectangle (&rect);
1049}
1050
1051static cairo_region_t *
1052get_frame_region (int window_width,
1053 int window_height)
1054{
1055 cairo_rectangle_int_t rect;
1056
1057 rect.x = 0;
1058 rect.y = 0;
1059 rect.width = window_width;
1060 rect.height = window_height;
1061
1062 return cairo_region_create_rectangle (&rect);
1063}
1064#endif /* HAVE_SHAPE */
1065
1066void
1067meta_frames_apply_shapes (MetaFrames *frames,
1068 MetaDisplay *meta_display,
1069 Window xwindow,
1070 int new_window_width,
1071 int new_window_height,
1072 gboolean window_has_shape)
1073{
1074#ifdef HAVE_SHAPE
1075 /* Apply shapes as if window had new_window_width, new_window_height */
1076 MetaUIFrame *frame;
1077 MetaFrameGeometry fgeom;
1078 cairo_region_t *window_region;
1079 Display *display;
1080 gboolean compositing_manager;
1081
1082 frame = meta_frames_lookup_window (frames, xwindow);
1083 g_return_if_fail (frame != NULL)do { if ((frame != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "frame != NULL"); return
; } } while (0)
;
1084
1085 display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
1086
1087 if (frame->shape_applied)
1088 {
1089 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1090 "Unsetting shape mask on frame 0x%lx\n",
1091 frame->xwindow);
1092
1093 XShapeCombineMask (display, frame->xwindow,
1094 ShapeBounding0, 0, 0, None0L, ShapeSet0);
1095 frame->shape_applied = FALSE(0);
1096 }
1097
1098 meta_frames_calc_geometry (frames, frame, &fgeom);
1099
1100 compositing_manager = meta_prefs_get_compositing_manager () &&
1101 meta_display &&
1102 !!(meta_display_get_compositor (meta_display));
1103
1104 if (!window_has_shape && compositing_manager)
1105 return;
1106
1107 window_region = get_visible_region (frames,
1108 frame,
1109 &fgeom,
1110 new_window_width,
1111 new_window_height);
1112
1113 if (window_has_shape)
1114 {
1115 /* The client window is oclock or something and has a shape
1116 * mask. To avoid a round trip to get its shape region, we
1117 * create a fake window that's never mapped, build up our shape
1118 * on that, then combine. Wasting the window is assumed cheaper
1119 * than a round trip, but who really knows for sure.
1120 */
1121 XSetWindowAttributes attrs;
1122 Window shape_window;
1123 Window client_window;
1124 cairo_region_t *frame_region;
1125 cairo_region_t *client_region;
1126 cairo_region_t *tmp_region;
1127 GdkScreen *screen;
1128 int screen_number;
1129
1130 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1131 "Frame 0x%lx needs to incorporate client shape\n",
1132 frame->xwindow);
1133
1134 screen = gtk_widget_get_screen (GTK_WIDGET (frames)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((gtk_widget_get_type ()))))))
);
1135 screen_number = gdk_x11_screen_get_screen_number (screen);
1136
1137 attrs.override_redirect = True1;
1138
1139 shape_window = XCreateWindow (display,
1140 RootWindow (display, screen_number)((&((_XPrivDisplay)(display))->screens[screen_number])
->root)
,
1141 -5000, -5000,
1142 new_window_width,
1143 new_window_height,
1144 0,
1145 CopyFromParent0L,
1146 CopyFromParent0L,
1147 (Visual *)CopyFromParent0L,
1148 CWOverrideRedirect(1L<<9),
1149 &attrs);
1150
1151 /* Copy the client's shape to the temporary shape_window */
1152 meta_core_get (display, frame->xwindow,
1153 META_CORE_GET_CLIENT_XWINDOW, &client_window,
1154 META_CORE_GET_END);
1155
1156 XShapeCombineShape (display, shape_window, ShapeBounding0,
1157 fgeom.borders.total.left,
1158 fgeom.borders.total.top,
1159 client_window,
1160 ShapeBounding0,
1161 ShapeSet0);
1162
1163 /* Punch the client area out of the normal frame shape,
1164 * then union it with the shape_window's existing shape
1165 */
1166 frame_region = get_frame_region (new_window_width,
1167 new_window_height);
1168 client_region = get_client_region (&fgeom,
1169 new_window_width,
1170 new_window_height);
1171
1172 tmp_region = compositing_manager ? frame_region : window_region;
1173
1174 cairo_region_subtract (tmp_region, client_region);
1175
1176 cairo_region_destroy (client_region);
1177
1178 apply_cairo_region_to_window (display, shape_window,
1179 tmp_region, ShapeUnion1);
1180
1181 cairo_region_destroy (frame_region);
1182
1183 /* Now copy shape_window shape to the real frame */
1184 XShapeCombineShape (display, frame->xwindow, ShapeBounding0,
1185 0, 0,
1186 shape_window,
1187 ShapeBounding0,
1188 ShapeSet0);
1189
1190 XDestroyWindow (display, shape_window);
1191 }
1192 else
1193 {
1194 /* No shape on the client, so just do simple stuff */
1195
1196 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1197 "Frame 0x%lx has shaped corners\n",
1198 frame->xwindow);
1199
1200 if (!compositing_manager)
1201 apply_cairo_region_to_window (display,
1202 frame->xwindow, window_region,
1203 ShapeSet0);
1204 }
1205
1206 frame->shape_applied = TRUE(!(0));
1207
1208 cairo_region_destroy (window_region);
1209#endif /* HAVE_SHAPE */
1210}
1211
1212cairo_region_t *
1213meta_frames_get_frame_bounds (MetaFrames *frames,
1214 Window xwindow,
1215 int window_width,
1216 int window_height)
1217{
1218 MetaUIFrame *frame;
1219 MetaFrameGeometry fgeom;
1220
1221 frame = meta_frames_lookup_window (frames, xwindow);
1222 g_return_val_if_fail (frame != NULL, NULL)do { if ((frame != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "frame != NULL"); return
(((void*)0)); } } while (0)
;
1223
1224 meta_frames_calc_geometry (frames, frame, &fgeom);
1225
1226 return get_visible_region (frames,
1227 frame,
1228 &fgeom,
1229 window_width,
1230 window_height);
1231}
1232
1233void
1234meta_frames_move_resize_frame (MetaFrames *frames,
1235 Window xwindow,
1236 int x,
1237 int y,
1238 int width,
1239 int height)
1240{
1241 MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
1242 int old_width, old_height;
1243 gint scale;
1244
1245 old_width = gdk_window_get_width (frame->window);
1246 old_height = gdk_window_get_height (frame->window);
1247
1248 scale = gdk_window_get_scale_factor (frame->window);
1249
1250 gdk_window_move_resize (frame->window, x / scale, y / scale, width / scale, height / scale);
1251
1252 if (old_width != width || old_height != height)
1253 invalidate_whole_window (frames, frame);
1254}
1255
1256void
1257meta_frames_queue_draw (MetaFrames *frames,
1258 Window xwindow)
1259{
1260 MetaUIFrame *frame;
1261
1262 frame = meta_frames_lookup_window (frames, xwindow);
1263
1264 invalidate_whole_window (frames, frame);
1265}
1266
1267void
1268meta_frames_set_title (MetaFrames *frames,
1269 Window xwindow,
1270 const char *title)
1271{
1272 MetaUIFrame *frame;
1273
1274 frame = meta_frames_lookup_window (frames, xwindow);
1275
1276 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 1276, ((const char*) (__func__)), "frame"); } while (0)
;
1277
1278 g_free (frame->title);
1279 frame->title = g_strdup (title)g_strdup_inline (title);
1280
1281 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
1282
1283 invalidate_whole_window (frames, frame);
1284}
1285
1286void
1287meta_frames_update_frame_style (MetaFrames *frames,
1288 Window xwindow)
1289{
1290 MetaUIFrame *frame;
1291
1292 frame = meta_frames_lookup_window (frames, xwindow);
1293
1294 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 1294, ((const char*) (__func__)), "frame"); } while (0)
;
1295
1296 meta_frames_attach_style (frames, frame);
1297 invalidate_whole_window (frames, frame);
1298}
1299
1300void
1301meta_frames_repaint_frame (MetaFrames *frames,
1302 Window xwindow)
1303{
1304 MetaUIFrame *frame;
1305
1306 frame = meta_frames_lookup_window (frames, xwindow);
1307
1308 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("marco", "ui/frames.c"
, 1308, ((const char*) (__func__)), "frame"); } while (0)
;
1309
1310 /* repaint everything, so the other frame don't
1311 * lag behind if they are exposed
1312 */
1313 gdk_window_process_all_updates ();
1314}
1315
1316static void
1317show_tip_now (MetaFrames *frames)
1318{
1319 const char *tiptext;
1320 MetaUIFrame *frame;
1321 int x, y, root_x, root_y;
1322 Window root, child;
1323 guint mask;
1324 MetaFrameControl control;
1325
1326 frame = frames->last_motion_frame;
1327 if (frame == NULL((void*)0))
1328 return;
1329
1330 XQueryPointer (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1331 frame->xwindow,
1332 &root, &child,
1333 &root_x, &root_y,
1334 &x, &y,
1335 &mask);
1336
1337 control = get_control (frames, frame, x, y);
1338
1339 tiptext = NULL((void*)0);
1340 switch (control)
1341 {
1342 case META_FRAME_CONTROL_TITLE:
1343 break;
1344 case META_FRAME_CONTROL_DELETE:
1345 tiptext = _("Close Window")((char *) g_dgettext ("marco", "Close Window"));
1346 break;
1347 case META_FRAME_CONTROL_MENU:
1348 tiptext = _("Window Menu")((char *) g_dgettext ("marco", "Window Menu"));
1349 break;
1350 case META_FRAME_CONTROL_APPMENU:
1351 tiptext = _("Window App Menu")((char *) g_dgettext ("marco", "Window App Menu"));
1352 break;
1353 case META_FRAME_CONTROL_MINIMIZE:
1354 tiptext = _("Minimize Window")((char *) g_dgettext ("marco", "Minimize Window"));
1355 break;
1356 case META_FRAME_CONTROL_MAXIMIZE:
1357 tiptext = _("Maximize Window")((char *) g_dgettext ("marco", "Maximize Window"));
1358 break;
1359 case META_FRAME_CONTROL_UNMAXIMIZE:
1360 tiptext = _("Restore Window")((char *) g_dgettext ("marco", "Restore Window"));
1361 break;
1362 case META_FRAME_CONTROL_SHADE:
1363 tiptext = _("Roll Up Window")((char *) g_dgettext ("marco", "Roll Up Window"));
1364 break;
1365 case META_FRAME_CONTROL_UNSHADE:
1366 tiptext = _("Unroll Window")((char *) g_dgettext ("marco", "Unroll Window"));
1367 break;
1368 case META_FRAME_CONTROL_ABOVE:
1369 tiptext = _("Keep Window On Top")((char *) g_dgettext ("marco", "Keep Window On Top"));
1370 break;
1371 case META_FRAME_CONTROL_UNABOVE:
1372 tiptext = _("Remove Window From Top")((char *) g_dgettext ("marco", "Remove Window From Top"));
1373 break;
1374 case META_FRAME_CONTROL_STICK:
1375 tiptext = _("Always On Visible Workspace")((char *) g_dgettext ("marco", "Always On Visible Workspace")
)
;
1376 break;
1377 case META_FRAME_CONTROL_UNSTICK:
1378 tiptext = _("Put Window On Only One Workspace")((char *) g_dgettext ("marco", "Put Window On Only One Workspace"
))
;
1379 break;
1380 case META_FRAME_CONTROL_RESIZE_SE:
1381 break;
1382 case META_FRAME_CONTROL_RESIZE_S:
1383 break;
1384 case META_FRAME_CONTROL_RESIZE_SW:
1385 break;
1386 case META_FRAME_CONTROL_RESIZE_N:
1387 break;
1388 case META_FRAME_CONTROL_RESIZE_NE:
1389 break;
1390 case META_FRAME_CONTROL_RESIZE_NW:
1391 break;
1392 case META_FRAME_CONTROL_RESIZE_W:
1393 break;
1394 case META_FRAME_CONTROL_RESIZE_E:
1395 break;
1396 case META_FRAME_CONTROL_NONE:
1397 break;
1398 case META_FRAME_CONTROL_CLIENT_AREA:
1399 break;
1400 }
1401
1402 if (tiptext)
1403 {
1404 MetaFrameGeometry fgeom;
1405 GdkRectangle *rect;
1406 int dx, dy, scale;
1407
1408 meta_frames_calc_geometry (frames, frame, &fgeom);
1409
1410 rect = control_rect (control, &fgeom);
1411 scale = gdk_window_get_scale_factor (frame->window);
1412
1413 /* get conversion delta for root-to-frame coords */
1414 dx = (root_x - x) / scale;
1415 dy = (root_y - y) / scale;
1416
1417 /* Align the tooltip to the button right end if RTL */
1418 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1419 dx += rect->width;
1420
1421 meta_fixed_tip_show (rect->x + dx,
1422 rect->y + rect->height + 2 + dy,
1423 tiptext);
1424 }
1425}
1426
1427static gboolean
1428tip_timeout_func (gpointer data)
1429{
1430 MetaFrames *frames;
1431
1432 frames = data;
1433
1434 show_tip_now (frames);
1435
1436 frames->tooltip_timeout = 0;
1437
1438 return FALSE(0);
1439}
1440
1441#define TIP_DELAY450 450
1442static void
1443queue_tip (MetaFrames *frames)
1444{
1445 clear_tip (frames);
1446
1447 frames->tooltip_timeout = g_timeout_add (TIP_DELAY450,
1448 tip_timeout_func,
1449 frames);
1450}
1451
1452static void
1453clear_tip (MetaFrames *frames)
1454{
1455 if (frames->tooltip_timeout)
1456 {
1457 g_source_remove (frames->tooltip_timeout);
1458 frames->tooltip_timeout = 0;
1459 }
1460 meta_fixed_tip_hide ();
1461}
1462
1463static void
1464redraw_control (MetaFrames *frames,
1465 MetaUIFrame *frame,
1466 MetaFrameControl control)
1467{
1468 MetaFrameGeometry fgeom;
1469 GdkRectangle *rect;
1470
1471 meta_frames_calc_geometry (frames, frame, &fgeom);
1472
1473 rect = control_rect (control, &fgeom);
1474
1475 gdk_window_invalidate_rect (frame->window, rect, FALSE(0));
1476 invalidate_cache (frames, frame);
1477}
1478
1479static gboolean
1480meta_frame_titlebar_event (MetaUIFrame *frame,
1481 GdkEventButton *event,
1482 int action)
1483{
1484 MetaFrameFlags flags;
1485
1486 switch (action)
1487 {
1488 case META_ACTION_TITLEBAR_TOGGLE_SHADE:
1489 {
1490 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1491 META_CORE_GET_FRAME_FLAGS, &flags,
1492 META_CORE_GET_END);
1493
1494 if (flags & META_FRAME_ALLOWS_SHADE)
1495 {
1496 if (flags & META_FRAME_SHADED)
1497 meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1498 frame->xwindow,
1499 event->time);
1500 else
1501 meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1502 frame->xwindow,
1503 event->time);
1504 }
1505 }
1506 break;
1507
1508 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE:
1509 {
1510 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1511 META_CORE_GET_FRAME_FLAGS, &flags,
1512 META_CORE_GET_END);
1513
1514 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1515 {
1516 meta_core_toggle_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1517 }
1518 }
1519 break;
1520
1521 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY:
1522 {
1523 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1524 META_CORE_GET_FRAME_FLAGS, &flags,
1525 META_CORE_GET_END);
1526
1527 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1528 {
1529 meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1530 }
1531 }
1532 break;
1533
1534 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY:
1535 {
1536 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1537 META_CORE_GET_FRAME_FLAGS, &flags,
1538 META_CORE_GET_END);
1539
1540 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1541 {
1542 meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1543 }
1544 }
1545 break;
1546
1547 case META_ACTION_TITLEBAR_MINIMIZE:
1548 {
1549 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1550 META_CORE_GET_FRAME_FLAGS, &flags,
1551 META_CORE_GET_END);
1552
1553 if (flags & META_FRAME_ALLOWS_MINIMIZE)
1554 {
1555 meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1556 }
1557 }
1558 break;
1559
1560 case META_ACTION_TITLEBAR_NONE:
1561 /* Yaay, a sane user that doesn't use that other weird crap! */
1562 break;
1563
1564 case META_ACTION_TITLEBAR_LOWER:
1565 meta_core_user_lower_and_unfocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1566 frame->xwindow,
1567 event->time);
1568 break;
1569
1570 case META_ACTION_TITLEBAR_MENU:
1571 meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1572 frame->xwindow,
1573 event->x_root,
1574 event->y_root,
1575 event->button,
1576 event->time);
1577 break;
1578
1579 case META_ACTION_TITLEBAR_LAST:
1580 break;
1581 }
1582
1583 return TRUE(!(0));
1584}
1585
1586static gboolean
1587meta_frame_double_click_event (MetaUIFrame *frame,
1588 GdkEventButton *event)
1589{
1590 int action = meta_prefs_get_action_double_click_titlebar ();
1591
1592 return meta_frame_titlebar_event (frame, event, action);
1593}
1594
1595static gboolean
1596meta_frame_middle_click_event (MetaUIFrame *frame,
1597 GdkEventButton *event)
1598{
1599 int action = meta_prefs_get_action_middle_click_titlebar();
1600
1601 return meta_frame_titlebar_event (frame, event, action);
1602}
1603
1604static gboolean
1605meta_frame_right_click_event(MetaUIFrame *frame,
1606 GdkEventButton *event)
1607{
1608 int action = meta_prefs_get_action_right_click_titlebar();
1609
1610 return meta_frame_titlebar_event (frame, event, action);
1611}
1612
1613static gboolean
1614meta_frames_button_press_event (GtkWidget *widget,
1615 GdkEventButton *event)
1616{
1617 MetaUIFrame *frame;
1618 MetaFrames *frames;
1619 MetaFrameControl control;
1620
1621 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
1622
1623 /* Remember that the display may have already done something with this event.
1624 * If so there's probably a GrabOp in effect.
1625 */
1626
1627 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
1628 if (frame == NULL((void*)0))
1629 return FALSE(0);
1630
1631 clear_tip (frames);
1632
1633 control = get_control (frames, frame, event->x, event->y);
1634
1635 /* focus on click, even if click was on client area */
1636 if (event->button == 1 &&
1637 !(control == META_FRAME_CONTROL_MINIMIZE ||
1638 control == META_FRAME_CONTROL_DELETE ||
1639 control == META_FRAME_CONTROL_MAXIMIZE))
1640 {
1641 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1642 "Focusing window with frame 0x%lx due to button 1 press\n",
1643 frame->xwindow);
1644 meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1645 frame->xwindow,
1646 event->time);
1647 }
1648
1649 /* don't do the rest of this if on client area */
1650 if (control == META_FRAME_CONTROL_CLIENT_AREA)
1651 return FALSE(0); /* not on the frame, just passed through from client */
1652
1653 /* We want to shade even if we have a GrabOp, since we'll have a move grab
1654 * if we double click the titlebar.
1655 */
1656 if (control == META_FRAME_CONTROL_TITLE &&
1657 event->button == 1 &&
1658 event->type == GDK_2BUTTON_PRESS)
1659 {
1660 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1661 return meta_frame_double_click_event (frame, event);
1662 }
1663
1664 if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))) !=
1665 META_GRAB_OP_NONE)
1666 return FALSE(0); /* already up to something */
1667
1668 if ((event->button == 1 &&
1669 (control == META_FRAME_CONTROL_MINIMIZE ||
1670 control == META_FRAME_CONTROL_DELETE ||
1671 control == META_FRAME_CONTROL_SHADE ||
1672 control == META_FRAME_CONTROL_UNSHADE ||
1673 control == META_FRAME_CONTROL_ABOVE ||
1674 control == META_FRAME_CONTROL_UNABOVE ||
1675 control == META_FRAME_CONTROL_STICK ||
1676 control == META_FRAME_CONTROL_UNSTICK ||
1677 control == META_FRAME_CONTROL_MENU)) ||
1678 (control == META_FRAME_CONTROL_MAXIMIZE ||
1679 control == META_FRAME_CONTROL_UNMAXIMIZE))
1680 {
1681 MetaGrabOp op;
1682
1683 switch (control)
1684 {
1685 case META_FRAME_CONTROL_MINIMIZE:
1686 op = META_GRAB_OP_CLICKING_MINIMIZE;
1687 break;
1688 case META_FRAME_CONTROL_MAXIMIZE:
1689 op = META_GRAB_OP_CLICKING_MAXIMIZE + event->button - 1;
1690 op = op > META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL ? META_GRAB_OP_CLICKING_MAXIMIZE : op;
1691 break;
1692 case META_FRAME_CONTROL_UNMAXIMIZE:
1693 op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
1694 break;
1695 case META_FRAME_CONTROL_DELETE:
1696 op = META_GRAB_OP_CLICKING_DELETE;
1697 break;
1698 case META_FRAME_CONTROL_MENU:
1699 op = META_GRAB_OP_CLICKING_MENU;
1700 break;
1701 case META_FRAME_CONTROL_APPMENU:
1702 op = META_GRAB_OP_CLICKING_APPMENU;
1703 break;
1704 case META_FRAME_CONTROL_SHADE:
1705 op = META_GRAB_OP_CLICKING_SHADE;
1706 break;
1707 case META_FRAME_CONTROL_UNSHADE:
1708 op = META_GRAB_OP_CLICKING_UNSHADE;
1709 break;
1710 case META_FRAME_CONTROL_ABOVE:
1711 op = META_GRAB_OP_CLICKING_ABOVE;
1712 break;
1713 case META_FRAME_CONTROL_UNABOVE:
1714 op = META_GRAB_OP_CLICKING_UNABOVE;
1715 break;
1716 case META_FRAME_CONTROL_STICK:
1717 op = META_GRAB_OP_CLICKING_STICK;
1718 break;
1719 case META_FRAME_CONTROL_UNSTICK:
1720 op = META_GRAB_OP_CLICKING_UNSTICK;
1721 break;
1722 default:
1723 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/frames.c", 1723, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1724 op = META_GRAB_OP_NONE;
1725 }
1726
1727 meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1728 frame->xwindow,
1729 op,
1730 TRUE(!(0)),
1731 TRUE(!(0)),
1732 event->button,
1733 0,
1734 event->time,
1735 event->x_root,
1736 event->y_root);
1737
1738 frame->prelit_control = control;
1739 redraw_control (frames, frame, control);
1740
1741 if (op == META_GRAB_OP_CLICKING_MENU)
1742 {
1743 MetaFrameGeometry fgeom;
1744 GdkRectangle *rect;
1745 int dx, dy;
1746
1747 meta_frames_calc_geometry (frames, frame, &fgeom);
1748
1749 rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
1750
1751 /* get delta to convert to root coords */
1752 dx = event->x_root - event->x;
1753 dy = event->y_root - event->y;
1754
1755 /* Align to the right end of the menu rectangle if RTL */
1756 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1757 dx += rect->width;
1758
1759 meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1760 frame->xwindow,
1761 rect->x + dx,
1762 rect->y + rect->height + dy,
1763 event->button,
1764 event->time);
1765 }
1766 }
1767 else if (event->button == 1 &&
1768 (control == META_FRAME_CONTROL_RESIZE_SE ||
1769 control == META_FRAME_CONTROL_RESIZE_S ||
1770 control == META_FRAME_CONTROL_RESIZE_SW ||
1771 control == META_FRAME_CONTROL_RESIZE_NE ||
1772 control == META_FRAME_CONTROL_RESIZE_N ||
1773 control == META_FRAME_CONTROL_RESIZE_NW ||
1774 control == META_FRAME_CONTROL_RESIZE_E ||
1775 control == META_FRAME_CONTROL_RESIZE_W))
1776 {
1777 MetaGrabOp op;
1778
1779 op = META_GRAB_OP_NONE;
Value stored to 'op' is never read
1780
1781 switch (control)
1782 {
1783 case META_FRAME_CONTROL_RESIZE_SE:
1784 op = META_GRAB_OP_RESIZING_SE;
1785 break;
1786 case META_FRAME_CONTROL_RESIZE_S:
1787 op = META_GRAB_OP_RESIZING_S;
1788 break;
1789 case META_FRAME_CONTROL_RESIZE_SW:
1790 op = META_GRAB_OP_RESIZING_SW;
1791 break;
1792 case META_FRAME_CONTROL_RESIZE_NE:
1793 op = META_GRAB_OP_RESIZING_NE;
1794 break;
1795 case META_FRAME_CONTROL_RESIZE_N:
1796 op = META_GRAB_OP_RESIZING_N;
1797 break;
1798 case META_FRAME_CONTROL_RESIZE_NW:
1799 op = META_GRAB_OP_RESIZING_NW;
1800 break;
1801 case META_FRAME_CONTROL_RESIZE_E:
1802 op = META_GRAB_OP_RESIZING_E;
1803 break;
1804 case META_FRAME_CONTROL_RESIZE_W:
1805 op = META_GRAB_OP_RESIZING_W;
1806 break;
1807 default:
1808 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/frames.c", 1808, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1809 break;
1810 }
1811
1812 meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1813 frame->xwindow,
1814 op,
1815 TRUE(!(0)),
1816 TRUE(!(0)),
1817 event->button,
1818 0,
1819 event->time,
1820 event->x_root,
1821 event->y_root);
1822 }
1823 else if (control == META_FRAME_CONTROL_TITLE &&
1824 event->button == 1)
1825 {
1826 MetaFrameFlags flags;
1827
1828 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
1829 META_CORE_GET_FRAME_FLAGS, &flags,
1830 META_CORE_GET_END);
1831
1832 if (flags & META_FRAME_ALLOWS_MOVE)
1833 {
1834 meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1835 frame->xwindow,
1836 META_GRAB_OP_MOVING,
1837 TRUE(!(0)),
1838 TRUE(!(0)),
1839 event->button,
1840 0,
1841 event->time,
1842 event->x_root,
1843 event->y_root);
1844 }
1845 }
1846 else if (event->button == 2)
1847 {
1848 return meta_frame_middle_click_event (frame, event);
1849 }
1850 else if (event->button == 3)
1851 {
1852 return meta_frame_right_click_event (frame, event);
1853 }
1854
1855 return TRUE(!(0));
1856}
1857
1858void
1859meta_frames_notify_menu_hide (MetaFrames *frames)
1860{
1861 if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))) ==
1862 META_GRAB_OP_CLICKING_MENU)
1863 {
1864 Window grab_frame;
1865
1866 grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
1867
1868 if (grab_frame != None0L)
1869 {
1870 MetaUIFrame *frame;
1871
1872 frame = meta_frames_lookup_window (frames, grab_frame);
1873
1874 if (frame)
1875 {
1876 redraw_control (frames, frame,
1877 META_FRAME_CONTROL_MENU);
1878 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), CurrentTime0L);
1879 }
1880 }
1881 }
1882}
1883
1884static gboolean
1885meta_frames_button_release_event (GtkWidget *widget,
1886 GdkEventButton *event)
1887{
1888 MetaUIFrame *frame;
1889 MetaFrames *frames;
1890 MetaGrabOp op;
1891
1892 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
1893
1894 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
1895 if (frame == NULL((void*)0))
1896 return FALSE(0);
1897
1898 clear_tip (frames);
1899
1900 op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
1901
1902 if (op == META_GRAB_OP_NONE)
1903 return FALSE(0);
1904
1905 /* We only handle the releases we handled the presses for (things
1906 * involving frame controls). Window ops that don't require a
1907 * frame are handled in the Xlib part of the code, display.c/window.c
1908 */
1909 if (frame->xwindow == meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))) &&
1910 ((int) event->button) == meta_core_get_grab_button (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()))))
1911 {
1912 MetaFrameControl control;
1913
1914 control = get_control (frames, frame, event->x, event->y);
1915
1916 switch (op)
1917 {
1918 case META_GRAB_OP_CLICKING_MINIMIZE:
1919 if (control == META_FRAME_CONTROL_MINIMIZE)
1920 meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1921
1922 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1923 break;
1924
1925 case META_GRAB_OP_CLICKING_MAXIMIZE:
1926 case META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL:
1927 case META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL:
1928 if (control == META_FRAME_CONTROL_MAXIMIZE)
1929 {
1930 /* Focus the window on the maximize */
1931 meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
1932 frame->xwindow,
1933 event->time);
1934
1935 if (op == META_GRAB_OP_CLICKING_MAXIMIZE)
1936 meta_core_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1937 if (op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL)
1938 meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1939 if (op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL)
1940 meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1941 }
1942 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1943 break;
1944
1945 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
1946 case META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL:
1947 case META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL:
1948 if (control == META_FRAME_CONTROL_UNMAXIMIZE) {
1949 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE)
1950 meta_core_unmaximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1951 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL)
1952 meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1953 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)
1954 meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1955 }
1956
1957 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1958 break;
1959
1960 case META_GRAB_OP_CLICKING_DELETE:
1961 if (control == META_FRAME_CONTROL_DELETE)
1962 meta_core_delete (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow, event->time);
1963
1964 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1965 break;
1966
1967 case META_GRAB_OP_CLICKING_MENU:
1968 case META_GRAB_OP_CLICKING_APPMENU:
1969 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1970 break;
1971
1972 case META_GRAB_OP_CLICKING_SHADE:
1973 if (control == META_FRAME_CONTROL_SHADE)
1974 meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow, event->time);
1975
1976 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1977 break;
1978
1979 case META_GRAB_OP_CLICKING_UNSHADE:
1980 if (control == META_FRAME_CONTROL_UNSHADE)
1981 meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow, event->time);
1982
1983 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1984 break;
1985
1986 case META_GRAB_OP_CLICKING_ABOVE:
1987 if (control == META_FRAME_CONTROL_ABOVE)
1988 meta_core_make_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1989
1990 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1991 break;
1992
1993 case META_GRAB_OP_CLICKING_UNABOVE:
1994 if (control == META_FRAME_CONTROL_UNABOVE)
1995 meta_core_unmake_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
1996
1997 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
1998 break;
1999
2000 case META_GRAB_OP_CLICKING_STICK:
2001 if (control == META_FRAME_CONTROL_STICK)
2002 meta_core_stick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
2003
2004 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
2005 break;
2006
2007 case META_GRAB_OP_CLICKING_UNSTICK:
2008 if (control == META_FRAME_CONTROL_UNSTICK)
2009 meta_core_unstick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow);
2010
2011 meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), event->time);
2012 break;
2013
2014 default:
2015 break;
2016 }
2017
2018 /* Update the prelit control regardless of what button the mouse
2019 * was released over; needed so that the new button can become
2020 * prelit so to let the user know that it can now be pressed.
2021 * :)
2022 */
2023 meta_frames_update_prelit_control (frames, frame, control);
2024 }
2025
2026 return TRUE(!(0));
2027}
2028
2029static void
2030meta_frames_update_prelit_control (MetaFrames *frames,
2031 MetaUIFrame *frame,
2032 MetaFrameControl control)
2033{
2034 MetaFrameControl old_control;
2035 MetaCursor cursor;
2036
2037 meta_verbosemeta_verbose_real ("Updating prelit control from %u to %u\n",
2038 frame->prelit_control, control);
2039
2040 cursor = META_CURSOR_DEFAULT;
2041
2042 switch (control)
2043 {
2044 case META_FRAME_CONTROL_CLIENT_AREA:
2045 break;
2046 case META_FRAME_CONTROL_NONE:
2047 break;
2048 case META_FRAME_CONTROL_TITLE:
2049 break;
2050 case META_FRAME_CONTROL_DELETE:
2051 break;
2052 case META_FRAME_CONTROL_MENU:
2053 break;
2054 case META_FRAME_CONTROL_APPMENU:
2055 break;
2056 case META_FRAME_CONTROL_MINIMIZE:
2057 break;
2058 case META_FRAME_CONTROL_MAXIMIZE:
2059 break;
2060 case META_FRAME_CONTROL_UNMAXIMIZE:
2061 break;
2062 case META_FRAME_CONTROL_SHADE:
2063 break;
2064 case META_FRAME_CONTROL_UNSHADE:
2065 break;
2066 case META_FRAME_CONTROL_ABOVE:
2067 break;
2068 case META_FRAME_CONTROL_UNABOVE:
2069 break;
2070 case META_FRAME_CONTROL_STICK:
2071 break;
2072 case META_FRAME_CONTROL_UNSTICK:
2073 break;
2074 case META_FRAME_CONTROL_RESIZE_SE:
2075 cursor = META_CURSOR_SE_RESIZE;
2076 break;
2077 case META_FRAME_CONTROL_RESIZE_S:
2078 cursor = META_CURSOR_SOUTH_RESIZE;
2079 break;
2080 case META_FRAME_CONTROL_RESIZE_SW:
2081 cursor = META_CURSOR_SW_RESIZE;
2082 break;
2083 case META_FRAME_CONTROL_RESIZE_N:
2084 cursor = META_CURSOR_NORTH_RESIZE;
2085 break;
2086 case META_FRAME_CONTROL_RESIZE_NE:
2087 cursor = META_CURSOR_NE_RESIZE;
2088 break;
2089 case META_FRAME_CONTROL_RESIZE_NW:
2090 cursor = META_CURSOR_NW_RESIZE;
2091 break;
2092 case META_FRAME_CONTROL_RESIZE_W:
2093 cursor = META_CURSOR_WEST_RESIZE;
2094 break;
2095 case META_FRAME_CONTROL_RESIZE_E:
2096 cursor = META_CURSOR_EAST_RESIZE;
2097 break;
2098 }
2099
2100 /* set/unset the prelight cursor */
2101 meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())),
2102 frame->xwindow,
2103 cursor);
2104
2105 switch (control)
2106 {
2107 case META_FRAME_CONTROL_MENU:
2108 case META_FRAME_CONTROL_APPMENU:
2109 case META_FRAME_CONTROL_MINIMIZE:
2110 case META_FRAME_CONTROL_MAXIMIZE:
2111 case META_FRAME_CONTROL_DELETE:
2112 case META_FRAME_CONTROL_SHADE:
2113 case META_FRAME_CONTROL_UNSHADE:
2114 case META_FRAME_CONTROL_ABOVE:
2115 case META_FRAME_CONTROL_UNABOVE:
2116 case META_FRAME_CONTROL_STICK:
2117 case META_FRAME_CONTROL_UNSTICK:
2118 case META_FRAME_CONTROL_UNMAXIMIZE:
2119 /* leave control set */
2120 break;
2121 default:
2122 /* Only prelight buttons */
2123 control = META_FRAME_CONTROL_NONE;
2124 break;
2125 }
2126
2127 if (control == frame->prelit_control)
2128 return;
2129
2130 /* Save the old control so we can unprelight it */
2131 old_control = frame->prelit_control;
2132
2133 frame->prelit_control = control;
2134
2135 redraw_control (frames, frame, old_control);
2136 redraw_control (frames, frame, control);
2137}
2138
2139static gboolean
2140meta_frames_motion_notify_event (GtkWidget *widget,
2141 GdkEventMotion *event)
2142{
2143 MetaUIFrame *frame;
2144 MetaFrames *frames;
2145 MetaGrabOp grab_op;
2146
2147 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2148
2149 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2150 if (frame == NULL((void*)0))
2151 return FALSE(0);
2152
2153 clear_tip (frames);
2154
2155 frames->last_motion_frame = frame;
2156
2157 grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2158
2159 switch (grab_op)
2160 {
2161 case META_GRAB_OP_CLICKING_MENU:
2162 case META_GRAB_OP_CLICKING_APPMENU:
2163 case META_GRAB_OP_CLICKING_DELETE:
2164 case META_GRAB_OP_CLICKING_MINIMIZE:
2165 case META_GRAB_OP_CLICKING_MAXIMIZE:
2166 case META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL:
2167 case META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL:
2168 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
2169 case META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL:
2170 case META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL:
2171 case META_GRAB_OP_CLICKING_SHADE:
2172 case META_GRAB_OP_CLICKING_UNSHADE:
2173 case META_GRAB_OP_CLICKING_ABOVE:
2174 case META_GRAB_OP_CLICKING_UNABOVE:
2175 case META_GRAB_OP_CLICKING_STICK:
2176 case META_GRAB_OP_CLICKING_UNSTICK:
2177 {
2178 MetaFrameControl control;
2179 int x, y, scale;
2180
2181 gdk_window_get_device_position (frame->window, event->device,
2182 &x, &y, NULL((void*)0));
2183 scale = gdk_window_get_scale_factor (frame->window);
2184 x *= scale;
2185 y *= scale;
2186
2187 /* Control is set to none unless it matches
2188 * the current grab
2189 */
2190 control = get_control (frames, frame, x, y);
2191 if (! ((control == META_FRAME_CONTROL_MENU &&
2192 grab_op == META_GRAB_OP_CLICKING_MENU) ||
2193 (control == META_FRAME_CONTROL_APPMENU &&
2194 grab_op == META_GRAB_OP_CLICKING_APPMENU) ||
2195 (control == META_FRAME_CONTROL_DELETE &&
2196 grab_op == META_GRAB_OP_CLICKING_DELETE) ||
2197 (control == META_FRAME_CONTROL_MINIMIZE &&
2198 grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
2199 ((control == META_FRAME_CONTROL_MAXIMIZE ||
2200 control == META_FRAME_CONTROL_UNMAXIMIZE) &&
2201 (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
2202 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL ||
2203 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL ||
2204 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE ||
2205 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL ||
2206 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)) ||
2207 (control == META_FRAME_CONTROL_SHADE &&
2208 grab_op == META_GRAB_OP_CLICKING_SHADE) ||
2209 (control == META_FRAME_CONTROL_UNSHADE &&
2210 grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
2211 (control == META_FRAME_CONTROL_ABOVE &&
2212 grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
2213 (control == META_FRAME_CONTROL_UNABOVE &&
2214 grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
2215 (control == META_FRAME_CONTROL_STICK &&
2216 grab_op == META_GRAB_OP_CLICKING_STICK) ||
2217 (control == META_FRAME_CONTROL_UNSTICK &&
2218 grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
2219 control = META_FRAME_CONTROL_NONE;
2220
2221 /* Update prelit control and cursor */
2222 meta_frames_update_prelit_control (frames, frame, control);
2223
2224 /* No tooltip while in the process of clicking */
2225 }
2226 break;
2227 case META_GRAB_OP_NONE:
2228 {
2229 MetaFrameControl control;
2230 int x, y, scale;
2231
2232 gdk_window_get_device_position (frame->window, event->device,
2233 &x, &y, NULL((void*)0));
2234 scale = gdk_window_get_scale_factor (frame->window);
2235 x *= scale;
2236 y *= scale;
2237
2238 control = get_control (frames, frame, x, y);
2239
2240 /* Update prelit control and cursor */
2241 meta_frames_update_prelit_control (frames, frame, control);
2242
2243 queue_tip (frames);
2244 }
2245 break;
2246
2247 default:
2248 break;
2249 }
2250
2251 return TRUE(!(0));
2252}
2253
2254static gboolean
2255meta_frames_destroy_event (GtkWidget *widget,
2256 GdkEventAny *event)
2257{
2258 MetaUIFrame *frame;
2259 MetaFrames *frames;
2260
2261 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2262
2263 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2264 if (frame == NULL((void*)0))
2265 return FALSE(0);
2266
2267 return TRUE(!(0));
2268}
2269
2270/* Returns a pixmap with a piece of the windows frame painted on it.
2271*/
2272static cairo_surface_t *
2273generate_pixmap (MetaFrames *frames,
2274 MetaUIFrame *frame,
2275 cairo_rectangle_int_t *rect)
2276{
2277 cairo_surface_t *result;
2278 cairo_t *cr;
2279
2280 /* do not create a pixmap for nonexisting areas */
2281 if (rect->width <= 0 || rect->height <= 0)
2282 return NULL((void*)0);
2283
2284 result = gdk_window_create_similar_surface (frame->window,
2285 CAIRO_CONTENT_COLOR_ALPHA,
2286 rect->width, rect->height);
2287
2288 cr = cairo_create (result);
2289 cairo_translate (cr, -rect->x, -rect->y);
2290
2291 meta_frames_paint_to_drawable (frames, frame, cr);
2292
2293 cairo_destroy (cr);
2294
2295 return result;
2296}
2297
2298static void
2299populate_cache (MetaFrames *frames,
2300 MetaUIFrame *frame)
2301{
2302 MetaFrameBorders borders;
2303 int width, height;
2304 int frame_width, frame_height, screen_width, screen_height;
2305 CachedPixels *pixels;
2306 MetaFrameType frame_type;
2307 MetaFrameFlags frame_flags;
2308 int i;
2309
2310 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2311 META_CORE_GET_FRAME_WIDTH, &frame_width,
2312 META_CORE_GET_FRAME_HEIGHT, &frame_height,
2313 META_CORE_GET_SCREEN_WIDTH, &screen_width,
2314 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
2315 META_CORE_GET_CLIENT_WIDTH, &width,
2316 META_CORE_GET_CLIENT_HEIGHT, &height,
2317 META_CORE_GET_FRAME_TYPE, &frame_type,
2318 META_CORE_GET_FRAME_FLAGS, &frame_flags,
2319 META_CORE_GET_END);
2320
2321 /* don't cache extremely large windows */
2322 if (frame_width > 2 * screen_width ||
2323 frame_height > 2 * screen_height)
2324 {
2325 return;
2326 }
2327
2328 meta_theme_get_frame_borders (meta_theme_get_current (),
2329 frame_type,
2330 frame->text_height,
2331 frame_flags,
2332 &borders);
2333
2334 pixels = get_cache (frames, frame);
2335
2336 /* Setup the rectangles for the four visible frame borders. First top, then
2337 * left, right and bottom. Top and bottom extend to the invisible borders
2338 * while left and right snugly fit in between:
2339 * -----
2340 * | |
2341 * -----
2342 */
2343
2344 /* width and height refer to the client window's
2345 * size without any border added. */
2346
2347 /* top */
2348 pixels->piece[0].rect.x = 0;
2349 pixels->piece[0].rect.y = 0;
2350 pixels->piece[0].rect.width = width + borders.total.left + borders.total.right;
2351 pixels->piece[0].rect.height = borders.total.top;
2352
2353 /* left */
2354 pixels->piece[1].rect.x = 0;
2355 pixels->piece[1].rect.y = borders.total.top;
2356 pixels->piece[1].rect.width = borders.total.left;
2357 pixels->piece[1].rect.height = height;
2358
2359 /* right */
2360 pixels->piece[2].rect.x = borders.total.left + width;
2361 pixels->piece[2].rect.y = borders.total.top;
2362 pixels->piece[2].rect.width = borders.total.right;
2363 pixels->piece[2].rect.height = height;
2364
2365 /* bottom */
2366 pixels->piece[3].rect.x = 0;
2367 pixels->piece[3].rect.y = borders.total.top + height;
2368 pixels->piece[3].rect.width = width + borders.total.left + borders.total.right;
2369 pixels->piece[3].rect.height = borders.total.bottom;
2370
2371 for (i = 0; i < 4; i++)
2372 {
2373 CachedFramePiece *piece = &pixels->piece[i];
2374 if (!piece->pixmap)
2375 piece->pixmap = generate_pixmap (frames, frame, &piece->rect);
2376 }
2377
2378 if (frames->invalidate_cache_timeout_id)
2379 g_source_remove (frames->invalidate_cache_timeout_id);
2380
2381 frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
2382
2383 if (!g_list_find (frames->invalidate_frames, frame))
2384 frames->invalidate_frames =
2385 g_list_prepend (frames->invalidate_frames, frame);
2386}
2387
2388static void
2389clip_to_screen (cairo_region_t *region, MetaUIFrame *frame)
2390{
2391 GdkRectangle frame_area;
2392 GdkRectangle screen_area = { 0, 0, 0, 0 };
2393 cairo_region_t *tmp_region;
2394
2395 /* Chop off stuff outside the screen; this optimization
2396 * is crucial to handle huge client windows,
2397 * like "xterm -geometry 1000x1000"
2398 */
2399 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2400 META_CORE_GET_FRAME_X, &frame_area.x,
2401 META_CORE_GET_FRAME_Y, &frame_area.y,
2402 META_CORE_GET_FRAME_WIDTH, &frame_area.width,
2403 META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
2404 META_CORE_GET_SCREEN_WIDTH, &screen_area.width,
2405 META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
2406 META_CORE_GET_END);
2407
2408 cairo_region_translate (region, frame_area.x, frame_area.y);
2409
2410 tmp_region = cairo_region_create_rectangle (&frame_area);
2411 cairo_region_intersect (region, tmp_region);
2412 cairo_region_destroy (tmp_region);
2413
2414 cairo_region_translate (region, - frame_area.x, - frame_area.y);
2415}
2416
2417static void
2418subtract_client_area (cairo_region_t *region,
2419 MetaUIFrame *frame)
2420{
2421 cairo_rectangle_int_t area;
2422 MetaFrameFlags flags;
2423 MetaFrameType type;
2424 MetaFrameBorders borders;
2425 cairo_region_t *tmp_region;
2426 Display *display;
2427 gint scale;
2428
2429 display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
2430 scale = gdk_window_get_scale_factor (frame->window);
2431
2432 meta_core_get (display, frame->xwindow,
2433 META_CORE_GET_FRAME_FLAGS, &flags,
2434 META_CORE_GET_FRAME_TYPE, &type,
2435 META_CORE_GET_CLIENT_WIDTH, &area.width,
2436 META_CORE_GET_CLIENT_HEIGHT, &area.height,
2437 META_CORE_GET_END);
2438 meta_theme_get_frame_borders (meta_theme_get_current (),
2439 type, frame->text_height, flags,
2440 &borders);
2441
2442 area.width /= scale;
2443 area.height /= scale;
2444 area.x = borders.total.left / scale;
2445 area.y = borders.total.top / scale;
2446
2447 tmp_region = cairo_region_create_rectangle (&area);
2448 cairo_region_subtract (region, tmp_region);
2449 cairo_region_destroy (tmp_region);
2450}
2451
2452static void
2453cached_pixels_draw (CachedPixels *pixels,
2454 cairo_t *cr,
2455 cairo_region_t *region)
2456{
2457 cairo_region_t *region_piece;
2458 int i;
2459
2460 for (i = 0; i < 4; i++)
2461 {
2462 CachedFramePiece *piece;
2463 piece = &pixels->piece[i];
2464
2465 if (piece->pixmap)
2466 {
2467 cairo_set_source_surface (cr, piece->pixmap,
2468 piece->rect.x, piece->rect.y);
2469 cairo_paint (cr);
2470
2471 region_piece = cairo_region_create_rectangle (&piece->rect);
2472 cairo_region_subtract (region, region_piece);
2473 cairo_region_destroy (region_piece);
2474 }
2475 }
2476}
2477
2478static MetaUIFrame *
2479find_frame_to_draw (MetaFrames *frames,
2480 cairo_t *cr)
2481{
2482 GHashTableIter iter;
2483 MetaUIFrame *frame;
2484
2485 g_hash_table_iter_init (&iter, frames->frames);
2486 while (g_hash_table_iter_next (&iter, NULL((void*)0), (gpointer *) &frame))
2487 if (gtk_cairo_should_draw_window (cr, frame->window))
2488 return frame;
2489
2490 return NULL((void*)0);
2491}
2492
2493static gboolean
2494meta_frames_draw (GtkWidget *widget,
2495 cairo_t *cr)
2496{
2497 MetaUIFrame *frame;
2498 MetaFrames *frames;
2499 CachedPixels *pixels;
2500 cairo_region_t *region;
2501 cairo_rectangle_int_t clip;
2502 int i, n_areas;
2503
2504 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2505 gdk_cairo_get_clip_rectangle (cr, &clip);
2506
2507 frame = find_frame_to_draw (frames, cr);
2508
2509 if (frame == NULL((void*)0))
2510 return FALSE(0);
2511
2512 if (frames->expose_delay_count > 0)
2513 {
2514 /* Redraw this entire frame later */
2515 frame->expose_delayed = TRUE(!(0));
2516 return TRUE(!(0));
2517 }
2518
2519 populate_cache (frames, frame);
2520
2521 region = cairo_region_create_rectangle (&clip);
2522
2523 pixels = get_cache (frames, frame);
2524
2525 cached_pixels_draw (pixels, cr, region);
2526
2527 clip_to_screen (region, frame);
2528 subtract_client_area (region, frame);
2529
2530 n_areas = cairo_region_num_rectangles (region);
2531
2532 for (i = 0; i < n_areas; i++)
2533 {
2534 cairo_rectangle_int_t area;
2535
2536 cairo_region_get_rectangle (region, i, &area);
2537
2538 cairo_save (cr);
2539
2540 cairo_rectangle (cr, area.x, area.y, area.width, area.height);
2541 cairo_clip (cr);
2542
2543 cairo_push_group (cr);
2544
2545 meta_frames_paint_to_drawable (frames, frame, cr);
2546
2547 cairo_pop_group_to_source (cr);
2548 cairo_paint (cr);
2549
2550 cairo_restore (cr);
2551 }
2552
2553 cairo_region_destroy (region);
2554
2555 return TRUE(!(0));
2556}
2557
2558/* How far off the screen edge the window decorations should
2559 * be drawn. Used only in meta_frames_paint_to_drawable, below.
2560 */
2561#define DECORATING_BORDER100 100
2562
2563static void
2564meta_frames_paint_to_drawable (MetaFrames *frames,
2565 MetaUIFrame *frame,
2566 cairo_t *cr)
2567{
2568 MetaFrameFlags flags;
2569 MetaFrameType type;
2570 GdkPixbuf *mini_icon;
2571 GdkPixbuf *icon;
2572 int w, h, scale;
2573 MetaButtonState button_states[META_BUTTON_TYPE_LAST];
2574 Window grab_frame;
2575 int i;
2576 MetaButtonLayout button_layout;
2577 MetaGrabOp grab_op;
2578
2579 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
2580 button_states[i] = META_BUTTON_STATE_NORMAL;
2581
2582 grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2583 grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2584 if (grab_frame != frame->xwindow)
2585 grab_op = META_GRAB_OP_NONE;
2586
2587 /* Set prelight state */
2588 switch (frame->prelit_control)
2589 {
2590 case META_FRAME_CONTROL_MENU:
2591 if (grab_op == META_GRAB_OP_CLICKING_MENU)
2592 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED;
2593 else
2594 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT;
2595 break;
2596 case META_FRAME_CONTROL_APPMENU:
2597 if (grab_op == META_GRAB_OP_CLICKING_MENU)
2598 button_states[META_BUTTON_TYPE_APPMENU] = META_BUTTON_STATE_PRESSED;
2599 else
2600 button_states[META_BUTTON_TYPE_APPMENU] = META_BUTTON_STATE_PRELIGHT;
2601 break;
2602 case META_FRAME_CONTROL_MINIMIZE:
2603 if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE)
2604 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED;
2605 else
2606 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT;
2607 break;
2608 case META_FRAME_CONTROL_MAXIMIZE:
2609 if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL ||
2610 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL)
2611 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2612 else
2613 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2614 break;
2615 case META_FRAME_CONTROL_UNMAXIMIZE:
2616 if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE || grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL ||
2617 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)
2618 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2619 else
2620 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2621 break;
2622 case META_FRAME_CONTROL_SHADE:
2623 if (grab_op == META_GRAB_OP_CLICKING_SHADE)
2624 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
2625 else
2626 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
2627 break;
2628 case META_FRAME_CONTROL_UNSHADE:
2629 if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
2630 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
2631 else
2632 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
2633 break;
2634 case META_FRAME_CONTROL_ABOVE:
2635 if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
2636 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
2637 else
2638 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
2639 break;
2640 case META_FRAME_CONTROL_UNABOVE:
2641 if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
2642 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
2643 else
2644 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
2645 break;
2646 case META_FRAME_CONTROL_STICK:
2647 if (grab_op == META_GRAB_OP_CLICKING_STICK)
2648 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
2649 else
2650 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
2651 break;
2652 case META_FRAME_CONTROL_UNSTICK:
2653 if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
2654 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
2655 else
2656 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
2657 break;
2658 case META_FRAME_CONTROL_DELETE:
2659 if (grab_op == META_GRAB_OP_CLICKING_DELETE)
2660 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
2661 else
2662 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT;
2663 break;
2664 default:
2665 break;
2666 }
2667
2668 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2669 META_CORE_GET_FRAME_FLAGS, &flags,
2670 META_CORE_GET_FRAME_TYPE, &type,
2671 META_CORE_GET_MINI_ICON, &mini_icon,
2672 META_CORE_GET_ICON, &icon,
2673 META_CORE_GET_CLIENT_WIDTH, &w,
2674 META_CORE_GET_CLIENT_HEIGHT, &h,
2675 META_CORE_GET_END);
2676
2677 meta_frames_ensure_layout (frames, frame);
2678
2679 meta_prefs_get_button_layout (&button_layout);
2680
2681 scale = gdk_window_get_scale_factor (frame->window);
2682 meta_theme_draw_frame (meta_theme_get_current (),
2683 frame->style,
2684 cr,
2685 type,
2686 flags,
2687 w / scale,
2688 h / scale,
2689 frame->text_layout,
2690 frame->text_height,
2691 &button_layout,
2692 button_states,
2693 mini_icon,
2694 icon);
2695}
2696
2697static gboolean
2698meta_frames_enter_notify_event (GtkWidget *widget,
2699 GdkEventCrossing *event)
2700{
2701 MetaUIFrame *frame;
2702 MetaFrames *frames;
2703 MetaFrameControl control;
2704
2705 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2706
2707 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2708 if (frame == NULL((void*)0))
2709 return FALSE(0);
2710
2711 control = get_control (frames, frame, event->x, event->y);
2712 meta_frames_update_prelit_control (frames, frame, control);
2713
2714 return TRUE(!(0));
2715}
2716
2717static gboolean
2718meta_frames_leave_notify_event (GtkWidget *widget,
2719 GdkEventCrossing *event)
2720{
2721 MetaUIFrame *frame;
2722 MetaFrames *frames;
2723
2724 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2725
2726 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)(gdk_x11_window_get_xid (event->window)));
2727 if (frame == NULL((void*)0))
2728 return FALSE(0);
2729
2730 meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
2731
2732 clear_tip (frames);
2733
2734 return TRUE(!(0));
2735}
2736
2737static GdkRectangle*
2738control_rect (MetaFrameControl control,
2739 MetaFrameGeometry *fgeom)
2740{
2741 GdkRectangle *rect;
2742
2743 rect = NULL((void*)0);
2744 switch (control)
2745 {
2746 case META_FRAME_CONTROL_TITLE:
2747 rect = &fgeom->title_rect;
2748 break;
2749 case META_FRAME_CONTROL_DELETE:
2750 rect = &fgeom->close_rect.visible;
2751 break;
2752 case META_FRAME_CONTROL_MENU:
2753 rect = &fgeom->menu_rect.visible;
2754 break;
2755 case META_FRAME_CONTROL_APPMENU:
2756 rect = &fgeom->appmenu_rect.visible;
2757 break;
2758 case META_FRAME_CONTROL_MINIMIZE:
2759 rect = &fgeom->min_rect.visible;
2760 break;
2761 case META_FRAME_CONTROL_MAXIMIZE:
2762 case META_FRAME_CONTROL_UNMAXIMIZE:
2763 rect = &fgeom->max_rect.visible;
2764 break;
2765 case META_FRAME_CONTROL_SHADE:
2766 rect = &fgeom->shade_rect.visible;
2767 break;
2768 case META_FRAME_CONTROL_UNSHADE:
2769 rect = &fgeom->unshade_rect.visible;
2770 break;
2771 case META_FRAME_CONTROL_ABOVE:
2772 rect = &fgeom->above_rect.visible;
2773 break;
2774 case META_FRAME_CONTROL_UNABOVE:
2775 rect = &fgeom->unabove_rect.visible;
2776 break;
2777 case META_FRAME_CONTROL_STICK:
2778 rect = &fgeom->stick_rect.visible;
2779 break;
2780 case META_FRAME_CONTROL_UNSTICK:
2781 rect = &fgeom->unstick_rect.visible;
2782 break;
2783 case META_FRAME_CONTROL_RESIZE_SE:
2784 break;
2785 case META_FRAME_CONTROL_RESIZE_S:
2786 break;
2787 case META_FRAME_CONTROL_RESIZE_SW:
2788 break;
2789 case META_FRAME_CONTROL_RESIZE_N:
2790 break;
2791 case META_FRAME_CONTROL_RESIZE_NE:
2792 break;
2793 case META_FRAME_CONTROL_RESIZE_NW:
2794 break;
2795 case META_FRAME_CONTROL_RESIZE_W:
2796 break;
2797 case META_FRAME_CONTROL_RESIZE_E:
2798 break;
2799 case META_FRAME_CONTROL_NONE:
2800 break;
2801 case META_FRAME_CONTROL_CLIENT_AREA:
2802 break;
2803 }
2804
2805 return rect;
2806}
2807
2808#define RESIZE_EXTENDS15 15
2809#define TOP_RESIZE_HEIGHT4 4
2810static MetaFrameControl
2811get_control (MetaFrames *frames,
2812 MetaUIFrame *frame,
2813 int x, int y)
2814{
2815 MetaFrameGeometry fgeom;
2816 MetaFrameFlags flags;
2817 gboolean has_vert, has_horiz;
2818 GdkRectangle client;
2819 gint scale;
2820
2821 scale = gdk_window_get_scale_factor (frame->window);
2822 x /= scale;
2823 y /= scale;
2824
2825 meta_frames_calc_geometry (frames, frame, &fgeom);
2826 get_client_rect (&fgeom, fgeom.width, fgeom.height, &client);
2827
2828 if (POINT_IN_RECT (x, y, client)((x) >= (client).x && (x) < ((client).x + (client
).width) && (y) >= (client).y && (y) < (
(client).y + (client).height))
)
2829 return META_FRAME_CONTROL_CLIENT_AREA;
2830
2831 if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable)((x) >= (fgeom.close_rect.clickable).x && (x) <
((fgeom.close_rect.clickable).x + (fgeom.close_rect.clickable
).width) && (y) >= (fgeom.close_rect.clickable).y &&
(y) < ((fgeom.close_rect.clickable).y + (fgeom.close_rect
.clickable).height))
)
2832 return META_FRAME_CONTROL_DELETE;
2833
2834 if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable)((x) >= (fgeom.min_rect.clickable).x && (x) < (
(fgeom.min_rect.clickable).x + (fgeom.min_rect.clickable).width
) && (y) >= (fgeom.min_rect.clickable).y &&
(y) < ((fgeom.min_rect.clickable).y + (fgeom.min_rect.clickable
).height))
)
2835 return META_FRAME_CONTROL_MINIMIZE;
2836
2837 if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable)((x) >= (fgeom.menu_rect.clickable).x && (x) < (
(fgeom.menu_rect.clickable).x + (fgeom.menu_rect.clickable).width
) && (y) >= (fgeom.menu_rect.clickable).y &&
(y) < ((fgeom.menu_rect.clickable).y + (fgeom.menu_rect.clickable
).height))
)
2838 return META_FRAME_CONTROL_MENU;
2839
2840 if (POINT_IN_RECT (x, y, fgeom.appmenu_rect.clickable)((x) >= (fgeom.appmenu_rect.clickable).x && (x) <
((fgeom.appmenu_rect.clickable).x + (fgeom.appmenu_rect.clickable
).width) && (y) >= (fgeom.appmenu_rect.clickable).
y && (y) < ((fgeom.appmenu_rect.clickable).y + (fgeom
.appmenu_rect.clickable).height))
)
2841 return META_FRAME_CONTROL_APPMENU;
2842
2843 meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())), frame->xwindow,
2844 META_CORE_GET_FRAME_FLAGS, &flags,
2845 META_CORE_GET_END);
2846
2847 has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
2848 has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
2849
2850 if (POINT_IN_RECT (x, y, fgeom.title_rect)((x) >= (fgeom.title_rect).x && (x) < ((fgeom.title_rect
).x + (fgeom.title_rect).width) && (y) >= (fgeom.title_rect
).y && (y) < ((fgeom.title_rect).y + (fgeom.title_rect
).height))
)
2851 {
2852 if (has_vert && y <= TOP_RESIZE_HEIGHT4 * scale)
2853 return META_FRAME_CONTROL_RESIZE_N;
2854 else
2855 return META_FRAME_CONTROL_TITLE;
2856 }
2857
2858 if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable)((x) >= (fgeom.max_rect.clickable).x && (x) < (
(fgeom.max_rect.clickable).x + (fgeom.max_rect.clickable).width
) && (y) >= (fgeom.max_rect.clickable).y &&
(y) < ((fgeom.max_rect.clickable).y + (fgeom.max_rect.clickable
).height))
)
2859 {
2860 if (flags & META_FRAME_MAXIMIZED)
2861 return META_FRAME_CONTROL_UNMAXIMIZE;
2862 else
2863 return META_FRAME_CONTROL_MAXIMIZE;
2864 }
2865
2866 if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable)((x) >= (fgeom.shade_rect.clickable).x && (x) <
((fgeom.shade_rect.clickable).x + (fgeom.shade_rect.clickable
).width) && (y) >= (fgeom.shade_rect.clickable).y &&
(y) < ((fgeom.shade_rect.clickable).y + (fgeom.shade_rect
.clickable).height))
)
2867 {
2868 return META_FRAME_CONTROL_SHADE;
2869 }
2870
2871 if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable)((x) >= (fgeom.unshade_rect.clickable).x && (x) <
((fgeom.unshade_rect.clickable).x + (fgeom.unshade_rect.clickable
).width) && (y) >= (fgeom.unshade_rect.clickable).
y && (y) < ((fgeom.unshade_rect.clickable).y + (fgeom
.unshade_rect.clickable).height))
)
2872 {
2873 return META_FRAME_CONTROL_UNSHADE;
2874 }
2875
2876 if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable)((x) >= (fgeom.above_rect.clickable).x && (x) <
((fgeom.above_rect.clickable).x + (fgeom.above_rect.clickable
).width) && (y) >= (fgeom.above_rect.clickable).y &&
(y) < ((fgeom.above_rect.clickable).y + (fgeom.above_rect
.clickable).height))
)
2877 {
2878 return META_FRAME_CONTROL_ABOVE;
2879 }
2880
2881 if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable)((x) >= (fgeom.unabove_rect.clickable).x && (x) <
((fgeom.unabove_rect.clickable).x + (fgeom.unabove_rect.clickable
).width) && (y) >= (fgeom.unabove_rect.clickable).
y && (y) < ((fgeom.unabove_rect.clickable).y + (fgeom
.unabove_rect.clickable).height))
)
2882 {
2883 return META_FRAME_CONTROL_UNABOVE;
2884 }
2885
2886 if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable)((x) >= (fgeom.stick_rect.clickable).x && (x) <
((fgeom.stick_rect.clickable).x + (fgeom.stick_rect.clickable
).width) && (y) >= (fgeom.stick_rect.clickable).y &&
(y) < ((fgeom.stick_rect.clickable).y + (fgeom.stick_rect
.clickable).height))
)
2887 {
2888 return META_FRAME_CONTROL_STICK;
2889 }
2890
2891 if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable)((x) >= (fgeom.unstick_rect.clickable).x && (x) <
((fgeom.unstick_rect.clickable).x + (fgeom.unstick_rect.clickable
).width) && (y) >= (fgeom.unstick_rect.clickable).
y && (y) < ((fgeom.unstick_rect.clickable).y + (fgeom
.unstick_rect.clickable).height))
)
2892 {
2893 return META_FRAME_CONTROL_UNSTICK;
2894 }
2895
2896 /* South resize always has priority over north resize,
2897 * in case of overlap.
2898 */
2899
2900 if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15) &&
2901 x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2902 {
2903 if (has_vert && has_horiz)
2904 return META_FRAME_CONTROL_RESIZE_SE;
2905 else if (has_vert)
2906 return META_FRAME_CONTROL_RESIZE_S;
2907 else if (has_horiz)
2908 return META_FRAME_CONTROL_RESIZE_E;
2909 }
2910 else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15) &&
2911 x <= (fgeom.borders.total.left + RESIZE_EXTENDS15))
2912 {
2913 if (has_vert && has_horiz)
2914 return META_FRAME_CONTROL_RESIZE_SW;
2915 else if (has_vert)
2916 return META_FRAME_CONTROL_RESIZE_S;
2917 else if (has_horiz)
2918 return META_FRAME_CONTROL_RESIZE_W;
2919 }
2920 else if (y < (fgeom.borders.invisible.top + RESIZE_EXTENDS15) &&
2921 x <= (fgeom.borders.total.left + RESIZE_EXTENDS15))
2922 {
2923 if (has_vert && has_horiz)
2924 return META_FRAME_CONTROL_RESIZE_NW;
2925 else if (has_vert)
2926 return META_FRAME_CONTROL_RESIZE_N;
2927 else if (has_horiz)
2928 return META_FRAME_CONTROL_RESIZE_W;
2929 }
2930 else if (y < (fgeom.borders.invisible.top + RESIZE_EXTENDS15) &&
2931 x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2932 {
2933 if (has_vert && has_horiz)
2934 return META_FRAME_CONTROL_RESIZE_NE;
2935 else if (has_vert)
2936 return META_FRAME_CONTROL_RESIZE_N;
2937 else if (has_horiz)
2938 return META_FRAME_CONTROL_RESIZE_E;
2939 }
2940 else if (y < (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT4 * scale))
2941 {
2942 if (has_vert)
2943 return META_FRAME_CONTROL_RESIZE_N;
2944 }
2945 else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15))
2946 {
2947 if (has_vert)
2948 return META_FRAME_CONTROL_RESIZE_S;
2949 }
2950 else if (x <= fgeom.borders.total.left + RESIZE_EXTENDS15)
2951 {
2952 if (has_horiz)
2953 return META_FRAME_CONTROL_RESIZE_W;
2954 }
2955 else if (x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2956 {
2957 if (has_horiz)
2958 return META_FRAME_CONTROL_RESIZE_E;
2959 }
2960
2961 if (y >= fgeom.borders.total.top)
2962 return META_FRAME_CONTROL_NONE;
2963 else
2964 return META_FRAME_CONTROL_TITLE;
2965}
2966
2967void
2968meta_frames_push_delay_exposes (MetaFrames *frames)
2969{
2970 if (frames->expose_delay_count == 0)
2971 {
2972 /* Make sure we've repainted things */
2973 gdk_window_process_all_updates ();
2974 XFlush (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())(gdk_x11_display_get_xdisplay (gdk_display_get_default ())));
2975 }
2976
2977 frames->expose_delay_count += 1;
2978}
2979
2980static void
2981queue_pending_exposes_func (gpointer key, gpointer value, gpointer data)
2982{
2983 MetaUIFrame *frame;
2984 MetaFrames *frames;
2985
2986 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
2987 frame = value;
2988
2989 if (frame->expose_delayed)
2990 {
2991 invalidate_whole_window (frames, frame);
2992 frame->expose_delayed = FALSE(0);
2993 }
2994}
2995
2996void
2997meta_frames_pop_delay_exposes (MetaFrames *frames)
2998{
2999 g_return_if_fail (frames->expose_delay_count > 0)do { if ((frames->expose_delay_count > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "frames->expose_delay_count > 0"
); return; } } while (0)
;
3000
3001 frames->expose_delay_count -= 1;
3002
3003 if (frames->expose_delay_count == 0)
3004 {
3005 g_hash_table_foreach (frames->frames,
3006 queue_pending_exposes_func,
3007 frames);
3008 }
3009}
3010
3011static void
3012invalidate_whole_window (MetaFrames *frames,
3013 MetaUIFrame *frame)
3014{
3015 gdk_window_invalidate_rect (frame->window, NULL((void*)0), FALSE(0));
3016 invalidate_cache (frames, frame);
3017}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6de546.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6de546.html new file mode 100644 index 00000000..ea11b66e --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-6de546.html @@ -0,0 +1,8014 @@ + + + +ui/theme.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme.c
Warning:line 1324, column 10
Cast a region whose size is not a multiple of the destination type size
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco Theme Rendering */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24/**
25 * \file theme.c Making Marco look pretty
26 *
27 * The window decorations drawn by Marco are described by files on disk
28 * known internally as "themes" (externally as "window border themes" on
29 * http://art.gnome.org/themes/marco/ or "Marco themes"). This file
30 * contains most of the code necessary to support themes; it does not
31 * contain the XML parser, which is in theme-parser.c.
32 *
33 * \bug This is a big file with lots of different subsystems, which might
34 * be better split out into separate files.
35 */
36
37/**
38 * \defgroup tokenizer The theme expression tokenizer
39 *
40 * Themes can use a simple expression language to represent the values of
41 * things. This is the tokeniser used for that language.
42 *
43 * \bug We could remove almost all this code by using GScanner instead,
44 * but we would also have to find every expression in every existing theme
45 * we could and make sure the parse trees were the same.
46 */
47
48/**
49 * \defgroup parser The theme expression parser
50 *
51 * Themes can use a simple expression language to represent the values of
52 * things. This is the parser used for that language.
53 */
54
55#include <config.h>
56#include <glib/gi18n-lib.h>
57
58#include "prefs.h"
59#include "theme.h"
60#include "theme-parser.h"
61#include "util.h"
62#include "gradient.h"
63#include <gtk/gtk.h>
64#include <string.h>
65#include <stdlib.h>
66#define __USE_XOPEN
67#include <math.h>
68
69#define GDK_COLOR_RGBA(color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
\
70 ((guint32) (0xff | \
71 ((int)((color).red * 255) << 24) | \
72 ((int)((color).green * 255) << 16) | \
73 ((int)((color).blue * 255) << 8)))
74
75#define GDK_COLOR_RGB(color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
\
76 ((guint32) (((int)((color).red * 255) << 16) | \
77 ((int)((color).green * 255) << 8) | \
78 ((int)((color).blue * 255))))
79
80#define DEBUG_FILL_STRUCT(s)memset ((s), 0xef, sizeof (*(s))) memset ((s), 0xef, sizeof (*(s)))
81#define CLAMP_UCHAR(v)((guchar) ((((((int)v)) > ((int)255)) ? ((int)255) : (((((
int)v)) < ((int)0)) ? ((int)0) : (((int)v))))))
((guchar) (CLAMP (((int)v), (int)0, (int)255)(((((int)v)) > ((int)255)) ? ((int)255) : (((((int)v)) <
((int)0)) ? ((int)0) : (((int)v))))
))
82#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
83
84static void gtk_style_shade (GdkRGBA *a,
85 GdkRGBA *b,
86 gdouble k);
87static void rgb_to_hls (gdouble *r,
88 gdouble *g,
89 gdouble *b);
90static void hls_to_rgb (gdouble *h,
91 gdouble *l,
92 gdouble *s);
93
94/**
95 * The current theme. (Themes are singleton.)
96 */
97static MetaTheme *meta_current_theme = NULL((void*)0);
98
99static cairo_surface_t *
100scale_surface (cairo_surface_t *surface,
101 gdouble old_width,
102 gdouble old_height,
103 gdouble new_width,
104 gdouble new_height,
105 gboolean vertical_stripes,
106 gboolean horizontal_stripes)
107{
108 gdouble scale_x;
109 gdouble scale_y;
110 cairo_content_t content;
111 gdouble width;
112 gdouble height;
113 cairo_surface_t *scaled;
114 cairo_t *cr;
115
116 scale_x = new_width / old_width;
117 scale_y = new_height / old_height;
118
119 if (horizontal_stripes && !vertical_stripes)
120 {
121 new_width = old_width;
122 scale_x = 1.0;
123 }
124 else if (vertical_stripes && !horizontal_stripes)
125 {
126 new_height = old_height;
127 scale_y = 1.0;
128 }
129
130 content = CAIRO_CONTENT_COLOR_ALPHA;
131 width = ceil (new_width);
132 height = ceil (new_height);
133
134 scaled = cairo_surface_create_similar (surface, content, (int) width, (int) height);
135 cr = cairo_create (scaled);
136
137 cairo_scale (cr, scale_x, scale_y);
138 cairo_set_source_surface (cr, surface, 0, 0);
139
140 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
141
142 cairo_paint (cr);
143 cairo_destroy (cr);
144
145 return scaled;
146}
147
148static cairo_surface_t *
149get_surface_from_pixbuf (GdkPixbuf *pixbuf,
150 MetaImageFillType fill_type,
151 gdouble width,
152 gdouble height,
153 gboolean vertical_stripes,
154 gboolean horizontal_stripes)
155{
156 gdouble pixbuf_width;
157 gdouble pixbuf_height;
158 cairo_surface_t *surface;
159 cairo_content_t content;
160 cairo_surface_t *copy;
161 cairo_t *cr;
162
163 pixbuf_width = gdk_pixbuf_get_width (pixbuf);
164 pixbuf_height = gdk_pixbuf_get_height (pixbuf);
165 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL((void*)0));
166
167 if (pixbuf_width == width && pixbuf_height == height)
168 {
169 return surface;
170 }
171
172 if (fill_type != META_IMAGE_FILL_TILE)
173 {
174 cairo_surface_t *scaled;
175
176 scaled = scale_surface (surface, pixbuf_width, pixbuf_height,
177 width, height, vertical_stripes,
178 horizontal_stripes);
179
180 cairo_surface_destroy (surface);
181 surface = scaled;
182 }
183
184 content = CAIRO_CONTENT_COLOR_ALPHA;
185 width = ceil (width);
186 height = ceil (height);
187
188 copy = cairo_surface_create_similar (surface, content, (int) width, (int) height);
189 cr = cairo_create (copy);
190
191 cairo_set_source_surface (cr, surface, 0, 0);
192
193 if (fill_type == META_IMAGE_FILL_TILE ||
194 vertical_stripes || horizontal_stripes)
195 {
196 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
197 }
198
199 cairo_paint (cr);
200 cairo_destroy (cr);
201
202 cairo_surface_destroy (surface);
203
204 return copy;
205}
206
207static GdkPixbuf *
208colorize_pixbuf (GdkPixbuf *orig,
209 GdkRGBA *new_color)
210{
211 GdkPixbuf *pixbuf;
212 double intensity;
213 int x, y;
214 const guchar *src;
215 guchar *dest;
216 int orig_rowstride;
217 int dest_rowstride;
218 int width, height;
219 gboolean has_alpha;
220 const guchar *src_pixels;
221 guchar *dest_pixels;
222
223 pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
224 gdk_pixbuf_get_bits_per_sample (orig),
225 gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
226
227 if (pixbuf == NULL((void*)0))
228 return NULL((void*)0);
229
230 orig_rowstride = gdk_pixbuf_get_rowstride (orig);
231 dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
232 width = gdk_pixbuf_get_width (pixbuf);
233 height = gdk_pixbuf_get_height (pixbuf);
234 has_alpha = gdk_pixbuf_get_has_alpha (orig);
235 src_pixels = gdk_pixbuf_get_pixels (orig);
236 dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
237
238 for (y = 0; y < height; y++)
239 {
240 src = src_pixels + y * orig_rowstride;
241 dest = dest_pixels + y * dest_rowstride;
242
243 for (x = 0; x < width; x++)
244 {
245 double dr, dg, db;
246
247 intensity = INTENSITY (src[0], src[1], src[2])((src[0]) * 0.30 + (src[1]) * 0.59 + (src[2]) * 0.11) / 255.0;
248
249 if (intensity <= 0.5)
250 {
251 /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
252 dr = new_color->red * intensity * 2.0;
253 dg = new_color->green * intensity * 2.0;
254 db = new_color->blue * intensity * 2.0;
255 }
256 else
257 {
258 /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
259 dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
260 dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
261 db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
262 }
263
264 dest[0] = CLAMP_UCHAR (255 * dr)((guchar) ((((((int)255 * dr)) > ((int)255)) ? ((int)255) :
(((((int)255 * dr)) < ((int)0)) ? ((int)0) : (((int)255 *
dr))))))
;
265 dest[1] = CLAMP_UCHAR (255 * dg)((guchar) ((((((int)255 * dg)) > ((int)255)) ? ((int)255) :
(((((int)255 * dg)) < ((int)0)) ? ((int)0) : (((int)255 *
dg))))))
;
266 dest[2] = CLAMP_UCHAR (255 * db)((guchar) ((((((int)255 * db)) > ((int)255)) ? ((int)255) :
(((((int)255 * db)) < ((int)0)) ? ((int)0) : (((int)255 *
db))))))
;
267
268 if (has_alpha)
269 {
270 dest[3] = src[3];
271 src += 4;
272 dest += 4;
273 }
274 else
275 {
276 src += 3;
277 dest += 3;
278 }
279 }
280 }
281
282 return pixbuf;
283}
284
285static void
286color_composite (const GdkRGBA *bg,
287 const GdkRGBA *fg,
288 double alpha,
289 GdkRGBA *color)
290{
291 *color = *bg;
292 color->red = color->red + (fg->red - color->red) * alpha;
293 color->green = color->green + (fg->green - color->green) * alpha;
294 color->blue = color->blue + (fg->blue - color->blue) * alpha;
295}
296
297/**
298 * Sets all the fields of a border to dummy values.
299 *
300 * \param border The border whose fields should be reset.
301 */
302static void
303init_border (GtkBorder *border)
304{
305 border->top = -1;
306 border->bottom = -1;
307 border->left = -1;
308 border->right = -1;
309}
310
311/**
312 * Creates a new, empty MetaFrameLayout. The fields will be set to dummy
313 * values.
314 *
315 * \return The newly created MetaFrameLayout.
316 */
317MetaFrameLayout*
318meta_frame_layout_new (void)
319{
320 MetaFrameLayout *layout;
321
322 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
323
324 layout->refcount = 1;
325
326 /* Fill with -1 values to detect invalid themes */
327 layout->left_width = -1;
328 layout->right_width = -1;
329 layout->bottom_height = -1;
330
331 layout->invisible_border.left = 10;
332 layout->invisible_border.right = 10;
333 layout->invisible_border.bottom = 10;
334 layout->invisible_border.top = 10;
335
336 init_border (&layout->title_border);
337
338 layout->title_vertical_pad = -1;
339
340 layout->right_titlebar_edge = -1;
341 layout->left_titlebar_edge = -1;
342
343 layout->button_sizing = META_BUTTON_SIZING_LAST;
344 layout->button_aspect = 1.0;
345 layout->button_width = -1;
346 layout->button_height = -1;
347
348 layout->has_title = TRUE(!(0));
349 layout->title_scale = 1.0;
350
351 init_border (&layout->button_border);
352
353 return layout;
354}
355
356/**
357 *
358 */
359static gboolean
360validate_border (const GtkBorder *border,
361 const char **bad)
362{
363 *bad = NULL((void*)0);
364
365 if (border->top < 0)
366 *bad = _("top")((char *) g_dgettext ("marco", "top"));
367 else if (border->bottom < 0)
368 *bad = _("bottom")((char *) g_dgettext ("marco", "bottom"));
369 else if (border->left < 0)
370 *bad = _("left")((char *) g_dgettext ("marco", "left"));
371 else if (border->right < 0)
372 *bad = _("right")((char *) g_dgettext ("marco", "right"));
373
374 return *bad == NULL((void*)0);
375}
376
377/**
378 * Ensures that the theme supplied a particular dimension. When a
379 * MetaFrameLayout is created, all its integer fields are set to -1
380 * by meta_frame_layout_new(). After an instance of this type
381 * should have been initialised, this function checks that
382 * a given field is not still at -1. It is never called directly, but
383 * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER
384 * macros.
385 *
386 * \param val The value to check
387 * \param name The name to use in the error message
388 * \param[out] error Set to an error if val was not initialised
389 */
390static gboolean
391validate_geometry_value (int val,
392 const char *name,
393 GError **error)
394{
395 if (val < 0)
396 {
397 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
398 META_THEME_ERROR_FRAME_GEOMETRY,
399 _("frame geometry does not specify \"%s\" dimension")((char *) g_dgettext ("marco", "frame geometry does not specify \"%s\" dimension"
))
,
400 name);
401 return FALSE(0);
402 }
403 else
404 return TRUE(!(0));
405}
406
407static gboolean
408validate_geometry_border (const GtkBorder *border,
409 const char *name,
410 GError **error)
411{
412 const char *bad;
413
414 if (!validate_border (border, &bad))
415 {
416 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
417 META_THEME_ERROR_FRAME_GEOMETRY,
418 _("frame geometry does not specify dimension \"%s\" for border \"%s\"")((char *) g_dgettext ("marco", "frame geometry does not specify dimension \"%s\" for border \"%s\""
))
,
419 bad, name);
420 return FALSE(0);
421 }
422 else
423 return TRUE(!(0));
424}
425
426gboolean
427meta_frame_layout_validate (const MetaFrameLayout *layout,
428 GError **error)
429{
430 g_return_val_if_fail (layout != NULL, FALSE)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
((0)); } } while (0)
;
431
432#define CHECK_GEOMETRY_VALUE(vname)if (!validate_geometry_value (layout->vname, "vname", error
)) return (0)
if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE(0)
433
434#define CHECK_GEOMETRY_BORDER(bname)if (!validate_geometry_border (&layout->bname, "bname"
, error)) return (0)
if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE(0)
435
436 CHECK_GEOMETRY_VALUE (left_width)if (!validate_geometry_value (layout->left_width, "left_width"
, error)) return (0)
;
437 CHECK_GEOMETRY_VALUE (right_width)if (!validate_geometry_value (layout->right_width, "right_width"
, error)) return (0)
;
438 CHECK_GEOMETRY_VALUE (bottom_height)if (!validate_geometry_value (layout->bottom_height, "bottom_height"
, error)) return (0)
;
439
440 CHECK_GEOMETRY_BORDER (title_border)if (!validate_geometry_border (&layout->title_border, "title_border"
, error)) return (0)
;
441
442 CHECK_GEOMETRY_VALUE (title_vertical_pad)if (!validate_geometry_value (layout->title_vertical_pad, "title_vertical_pad"
, error)) return (0)
;
443
444 CHECK_GEOMETRY_VALUE (right_titlebar_edge)if (!validate_geometry_value (layout->right_titlebar_edge,
"right_titlebar_edge", error)) return (0)
;
445 CHECK_GEOMETRY_VALUE (left_titlebar_edge)if (!validate_geometry_value (layout->left_titlebar_edge, "left_titlebar_edge"
, error)) return (0)
;
446
447 switch (layout->button_sizing)
448 {
449 case META_BUTTON_SIZING_ASPECT:
450 if (layout->button_aspect < (0.1) ||
451 layout->button_aspect > (15.0))
452 {
453 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
454 META_THEME_ERROR_FRAME_GEOMETRY,
455 _("Button aspect ratio %g is not reasonable")((char *) g_dgettext ("marco", "Button aspect ratio %g is not reasonable"
))
,
456 layout->button_aspect);
457 return FALSE(0);
458 }
459 break;
460 case META_BUTTON_SIZING_FIXED:
461 CHECK_GEOMETRY_VALUE (button_width)if (!validate_geometry_value (layout->button_width, "button_width"
, error)) return (0)
;
462 CHECK_GEOMETRY_VALUE (button_height)if (!validate_geometry_value (layout->button_height, "button_height"
, error)) return (0)
;
463 break;
464 case META_BUTTON_SIZING_LAST:
465 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
466 META_THEME_ERROR_FRAME_GEOMETRY,
467 _("Frame geometry does not specify size of buttons")((char *) g_dgettext ("marco", "Frame geometry does not specify size of buttons"
))
);
468 return FALSE(0);
469 }
470
471 CHECK_GEOMETRY_BORDER (button_border)if (!validate_geometry_border (&layout->button_border,
"button_border", error)) return (0)
;
472
473 return TRUE(!(0));
474}
475
476MetaFrameLayout*
477meta_frame_layout_copy (const MetaFrameLayout *src)
478{
479 MetaFrameLayout *layout;
480
481 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
482
483 *layout = *src;
484
485 layout->refcount = 1;
486
487 return layout;
488}
489
490void
491meta_frame_layout_ref (MetaFrameLayout *layout)
492{
493 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
494
495 layout->refcount += 1;
496}
497
498void
499meta_frame_layout_unref (MetaFrameLayout *layout)
500{
501 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
502 g_return_if_fail (layout->refcount > 0)do { if ((layout->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout->refcount > 0"
); return; } } while (0)
;
503
504 layout->refcount -= 1;
505
506 if (layout->refcount == 0)
507 {
508 DEBUG_FILL_STRUCT (layout)memset ((layout), 0xef, sizeof (*(layout)));
509 g_free (layout);
510 }
511}
512
513void
514meta_frame_layout_get_borders (const MetaFrameLayout *layout,
515 int text_height,
516 MetaFrameFlags flags,
517 MetaFrameBorders *borders)
518{
519 int buttons_height, title_height;
520
521 meta_frame_borders_clear (borders);
522
523 /* For a full-screen window, we don't have any borders, visible or not. */
524 if (flags & META_FRAME_FULLSCREEN)
525 return;
526
527 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
528
529 if (!layout->has_title)
530 text_height = 0;
531
532 buttons_height = layout->button_height +
533 layout->button_border.top + layout->button_border.bottom;
534 title_height = text_height +
535 layout->title_vertical_pad +
536 layout->title_border.top + layout->title_border.bottom;
537
538 borders->visible.top = MAX (buttons_height, title_height)(((buttons_height) > (title_height)) ? (buttons_height) : (
title_height))
;
539 borders->visible.left = layout->left_width;
540 borders->visible.right = layout->right_width;
541 borders->visible.bottom = layout->bottom_height;
542
543 if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
544 {
545 borders->invisible.left = layout->invisible_border.left;
546 borders->invisible.right = layout->invisible_border.right;
547 }
548
549 if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
550 {
551 borders->invisible.bottom = layout->invisible_border.bottom;
552 borders->invisible.top = layout->invisible_border.top;
553 }
554
555 if (flags & META_FRAME_SHADED)
556 borders->visible.bottom = borders->invisible.bottom = 0;
557
558 borders->total.left = borders->invisible.left + borders->visible.left;
559 borders->total.right = borders->invisible.right + borders->visible.right;
560 borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
561 borders->total.top = borders->invisible.top + borders->visible.top;
562}
563
564static MetaButtonType
565map_button_function_to_type (MetaButtonFunction function)
566{
567 switch (function)
568 {
569 case META_BUTTON_FUNCTION_SHADE:
570 return META_BUTTON_TYPE_SHADE;
571 case META_BUTTON_FUNCTION_ABOVE:
572 return META_BUTTON_TYPE_ABOVE;
573 case META_BUTTON_FUNCTION_STICK:
574 return META_BUTTON_TYPE_STICK;
575 case META_BUTTON_FUNCTION_UNSHADE:
576 return META_BUTTON_TYPE_UNSHADE;
577 case META_BUTTON_FUNCTION_UNABOVE:
578 return META_BUTTON_TYPE_UNABOVE;
579 case META_BUTTON_FUNCTION_UNSTICK:
580 return META_BUTTON_TYPE_UNSTICK;
581 case META_BUTTON_FUNCTION_MENU:
582 return META_BUTTON_TYPE_MENU;
583 case META_BUTTON_FUNCTION_APPMENU:
584 return META_BUTTON_TYPE_APPMENU;
585 case META_BUTTON_FUNCTION_MINIMIZE:
586 return META_BUTTON_TYPE_MINIMIZE;
587 case META_BUTTON_FUNCTION_MAXIMIZE:
588 return META_BUTTON_TYPE_MAXIMIZE;
589 case META_BUTTON_FUNCTION_CLOSE:
590 return META_BUTTON_TYPE_CLOSE;
591 case META_BUTTON_FUNCTION_LAST:
592 return META_BUTTON_TYPE_LAST;
593 }
594
595 return META_BUTTON_TYPE_LAST;
596}
597
598static MetaButtonSpace*
599rect_for_function (MetaFrameGeometry *fgeom,
600 MetaFrameFlags flags,
601 MetaButtonFunction function,
602 MetaTheme *theme)
603{
604
605 /* Firstly, check version-specific things. */
606
607 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
608 {
609 switch (function)
610 {
611 case META_BUTTON_FUNCTION_SHADE:
612 if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
613 return &fgeom->shade_rect;
614 else
615 return NULL((void*)0);
616 case META_BUTTON_FUNCTION_ABOVE:
617 if (!(flags & META_FRAME_ABOVE))
618 return &fgeom->above_rect;
619 else
620 return NULL((void*)0);
621 case META_BUTTON_FUNCTION_STICK:
622 if (!(flags & META_FRAME_STUCK))
623 return &fgeom->stick_rect;
624 else
625 return NULL((void*)0);
626 case META_BUTTON_FUNCTION_UNSHADE:
627 if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
628 return &fgeom->unshade_rect;
629 else
630 return NULL((void*)0);
631 case META_BUTTON_FUNCTION_UNABOVE:
632 if (flags & META_FRAME_ABOVE)
633 return &fgeom->unabove_rect;
634 else
635 return NULL((void*)0);
636 case META_BUTTON_FUNCTION_UNSTICK:
637 if (flags & META_FRAME_STUCK)
638 return &fgeom->unstick_rect;
639 default:
640 /* just go on to the next switch block */;
641 }
642 }
643
644 /* now consider the buttons which exist in all versions */
645
646 switch (function)
647 {
648 case META_BUTTON_FUNCTION_MENU:
649 if (flags & META_FRAME_ALLOWS_MENU)
650 return &fgeom->menu_rect;
651 else
652 return NULL((void*)0);
653 case META_BUTTON_FUNCTION_APPMENU:
654 if (flags & META_FRAME_ALLOWS_APPMENU)
655 return &fgeom->appmenu_rect;
656 else
657 return NULL((void*)0);
658 case META_BUTTON_FUNCTION_MINIMIZE:
659 if (flags & META_FRAME_ALLOWS_MINIMIZE)
660 return &fgeom->min_rect;
661 else
662 return NULL((void*)0);
663 case META_BUTTON_FUNCTION_MAXIMIZE:
664 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
665 return &fgeom->max_rect;
666 else
667 return NULL((void*)0);
668 case META_BUTTON_FUNCTION_CLOSE:
669 if (flags & META_FRAME_ALLOWS_DELETE)
670 return &fgeom->close_rect;
671 else
672 return NULL((void*)0);
673 case META_BUTTON_FUNCTION_STICK:
674 case META_BUTTON_FUNCTION_SHADE:
675 case META_BUTTON_FUNCTION_ABOVE:
676 case META_BUTTON_FUNCTION_UNSTICK:
677 case META_BUTTON_FUNCTION_UNSHADE:
678 case META_BUTTON_FUNCTION_UNABOVE:
679 /* we are being asked for a >v1 button which hasn't been handled yet,
680 * so obviously we're not in a theme which supports that version.
681 * therefore, we don't show the button. return NULL and all will
682 * be well.
683 */
684 return NULL((void*)0);
685
686 case META_BUTTON_FUNCTION_LAST:
687 return NULL((void*)0);
688 }
689
690 return NULL((void*)0);
691}
692
693static gboolean
694strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
695 GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
696 int *n_rects,
697 MetaButtonSpace *to_strip)
698{
699 int i;
700
701 i = 0;
702 while (i < *n_rects)
703 {
704 if (func_rects[i] == to_strip)
705 {
706 *n_rects -= 1;
707
708 /* shift the other rects back in the array */
709 while (i < *n_rects)
710 {
711 func_rects[i] = func_rects[i+1];
712 bg_rects[i] = bg_rects[i+1];
713
714 ++i;
715 }
716
717 func_rects[i] = NULL((void*)0);
718 bg_rects[i] = NULL((void*)0);
719
720 return TRUE(!(0));
721 }
722
723 ++i;
724 }
725
726 return FALSE(0); /* did not strip anything */
727}
728
729void
730meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
731 int text_height,
732 MetaFrameFlags flags,
733 int client_width,
734 int client_height,
735 const MetaButtonLayout *button_layout,
736 MetaFrameGeometry *fgeom,
737 MetaTheme *theme)
738{
739 int i, n_left, n_right, n_left_spacers, n_right_spacers;
740 int x;
741 int button_y;
742 int title_right_edge;
743 int width, height;
744 int button_width, button_height;
745 int min_size_for_rounding;
746
747 /* the left/right rects in order; the max # of rects
748 * is the number of button functions
749 */
750 MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
751 MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
752 GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
753 gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
754 GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
755 gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
756
757 MetaFrameBorders borders;
758
759 meta_frame_layout_get_borders (layout, text_height,
760 flags,
761 &borders);
762
763 fgeom->borders = borders;
764
765 width = client_width + borders.total.left + borders.total.right;
766
767 height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
768 borders.total.top + borders.total.bottom;
769
770 fgeom->width = width;
771 fgeom->height = height;
772
773 fgeom->top_titlebar_edge = layout->title_border.top;
774 fgeom->bottom_titlebar_edge = layout->title_border.bottom;
775 fgeom->left_titlebar_edge = layout->left_titlebar_edge;
776 fgeom->right_titlebar_edge = layout->right_titlebar_edge;
777
778 switch (layout->button_sizing)
779 {
780 case META_BUTTON_SIZING_ASPECT:
781 button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
782 button_width = (int) (((double) button_height) / layout->button_aspect);
783 break;
784 case META_BUTTON_SIZING_FIXED:
785 button_width = layout->button_width;
786 button_height = layout->button_height;
787 break;
788 case META_BUTTON_SIZING_LAST:
789 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 789, ((
const char*) (__func__)), ((void*)0)); } while (0)
;
790 default:
791 button_width = -1;
792 button_height = -1;
793 }
794
795 /* FIXME all this code sort of pretends that duplicate buttons
796 * with the same function are allowed, but that breaks the
797 * code in frames.c, so isn't really allowed right now.
798 * Would need left_close_rect, right_close_rect, etc.
799 */
800
801 /* Init all button rects to 0, lame hack */
802 memset (ADDRESS_OF_BUTTON_RECTS (fgeom)(((char*)(fgeom)) + ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
, '\0',
803 LENGTH_OF_BUTTON_RECTS(((glong) __builtin_offsetof(MetaFrameGeometry, right_single_background
)) + sizeof (GdkRectangle) - ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
);
804
805 n_left = 0;
806 n_right = 0;
807 n_left_spacers = 0;
808 n_right_spacers = 0;
809
810 if (!layout->hide_buttons)
811 {
812 /* Try to fill in rects */
813 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
814 {
815 left_func_rects[n_left] = rect_for_function (fgeom, flags,
816 button_layout->left_buttons[i],
817 theme);
818 if (left_func_rects[n_left] != NULL((void*)0))
819 {
820 left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
821 if (button_layout->left_buttons_has_spacer[i])
822 ++n_left_spacers;
823
824 ++n_left;
825 }
826 }
827
828 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
829 {
830 right_func_rects[n_right] = rect_for_function (fgeom, flags,
831 button_layout->right_buttons[i],
832 theme);
833 if (right_func_rects[n_right] != NULL((void*)0))
834 {
835 right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
836 if (button_layout->right_buttons_has_spacer[i])
837 ++n_right_spacers;
838
839 ++n_right;
840 }
841 }
842 }
843
844 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST; i++)
845 {
846 left_bg_rects[i] = NULL((void*)0);
847 right_bg_rects[i] = NULL((void*)0);
848 }
849
850 for (i = 0; i < n_left; i++)
851 {
852 if (n_left == 1)
853 left_bg_rects[i] = &fgeom->left_single_background;
854 else if (i == 0)
855 left_bg_rects[i] = &fgeom->left_left_background;
856 else if (i == (n_left - 1))
857 left_bg_rects[i] = &fgeom->left_right_background;
858 else
859 left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
860 }
861
862 for (i = 0; i < n_right; i++)
863 {
864 if (n_right == 1)
865 right_bg_rects[i] = &fgeom->right_single_background;
866 else if (i == (n_right - 1))
867 right_bg_rects[i] = &fgeom->right_right_background;
868 else if (i == 0)
869 right_bg_rects[i] = &fgeom->right_left_background;
870 else
871 right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
872 }
873
874 /* Be sure buttons fit */
875 while (n_left > 0 || n_right > 0)
876 {
877 int space_used_by_buttons;
878 int space_available;
879
880 space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
881
882 space_used_by_buttons = 0;
883
884 space_used_by_buttons += button_width * n_left;
885 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_left_spacers));
886 space_used_by_buttons += layout->button_border.left * n_left;
887 space_used_by_buttons += layout->button_border.right * n_left;
888
889 space_used_by_buttons += button_width * n_right;
890 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_right_spacers));
891 space_used_by_buttons += layout->button_border.left * n_right;
892 space_used_by_buttons += layout->button_border.right * n_right;
893
894 if (space_used_by_buttons <= space_available)
895 break; /* Everything fits, bail out */
896
897 /* First try to remove separators */
898 if (n_left_spacers > 0)
899 {
900 left_buttons_has_spacer[--n_left_spacers] = FALSE(0);
901 continue;
902 }
903 else if (n_right_spacers > 0)
904 {
905 right_buttons_has_spacer[--n_right_spacers] = FALSE(0);
906 continue;
907 }
908
909 /* Otherwise we need to shave out a button. Shave
910 * above, stick, shade, min, max, close, then menu (menu is most useful);
911 * prefer the default button locations.
912 */
913 if (strip_button (left_func_rects, left_bg_rects,
914 &n_left, &fgeom->above_rect))
915 continue;
916 else if (strip_button (right_func_rects, right_bg_rects,
917 &n_right, &fgeom->above_rect))
918 continue;
919 else if (strip_button (left_func_rects, left_bg_rects,
920 &n_left, &fgeom->stick_rect))
921 continue;
922 else if (strip_button (right_func_rects, right_bg_rects,
923 &n_right, &fgeom->stick_rect))
924 continue;
925 else if (strip_button (left_func_rects, left_bg_rects,
926 &n_left, &fgeom->shade_rect))
927 continue;
928 else if (strip_button (right_func_rects, right_bg_rects,
929 &n_right, &fgeom->shade_rect))
930 continue;
931 else if (strip_button (left_func_rects, left_bg_rects,
932 &n_left, &fgeom->min_rect))
933 continue;
934 else if (strip_button (right_func_rects, right_bg_rects,
935 &n_right, &fgeom->min_rect))
936 continue;
937 else if (strip_button (left_func_rects, left_bg_rects,
938 &n_left, &fgeom->max_rect))
939 continue;
940 else if (strip_button (right_func_rects, right_bg_rects,
941 &n_right, &fgeom->max_rect))
942 continue;
943 else if (strip_button (left_func_rects, left_bg_rects,
944 &n_left, &fgeom->close_rect))
945 continue;
946 else if (strip_button (right_func_rects, right_bg_rects,
947 &n_right, &fgeom->close_rect))
948 continue;
949 else if (strip_button (right_func_rects, right_bg_rects,
950 &n_right, &fgeom->menu_rect))
951 continue;
952 else if (strip_button (left_func_rects, left_bg_rects,
953 &n_left, &fgeom->menu_rect))
954 continue;
955 else if (strip_button (right_func_rects, right_bg_rects,
956 &n_right, &fgeom->appmenu_rect))
957 continue;
958 else if (strip_button (left_func_rects, left_bg_rects,
959 &n_left, &fgeom->appmenu_rect))
960 continue;
961 else
962 {
963 meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
964 n_left, n_right);
965 }
966 }
967
968 /* Save the button layout */
969 fgeom->button_layout = *button_layout;
970 fgeom->n_left_buttons = n_left;
971 fgeom->n_right_buttons = n_right;
972
973 /* center buttons vertically */
974 button_y = (borders.visible.top -
975 (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + borders.invisible.top;
976
977 /* right edge of farthest-right button */
978 x = width - layout->right_titlebar_edge - borders.invisible.right;
979
980 i = n_right - 1;
981 while (i >= 0)
982 {
983 MetaButtonSpace *rect;
984
985 if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
986 break;
987
988 rect = right_func_rects[i];
989 rect->visible.x = x - layout->button_border.right - button_width;
990 if (right_buttons_has_spacer[i])
991 rect->visible.x -= (int) (0.75 * (double) button_width);
992
993 rect->visible.y = button_y;
994 rect->visible.width = button_width;
995 rect->visible.height = button_height;
996
997 if (flags & META_FRAME_MAXIMIZED ||
998 flags & META_FRAME_TILED_LEFT ||
999 flags & META_FRAME_TILED_RIGHT)
1000 {
1001 rect->clickable.x = rect->visible.x;
1002 rect->clickable.y = rect->visible.y;
1003 rect->clickable.width = button_width;
1004 rect->clickable.height = button_height;
1005
1006 if (i == n_right - 1)
1007 rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
1008
1009 }
1010 else
1011 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1012
1013 *(right_bg_rects[i]) = rect->visible;
1014
1015 x = rect->visible.x - layout->button_border.left;
1016
1017 --i;
1018 }
1019
1020 /* save right edge of titlebar for later use */
1021 title_right_edge = x - layout->title_border.right;
1022
1023 /* Now x changes to be position from the left and we go through
1024 * the left-side buttons
1025 */
1026 x = layout->left_titlebar_edge + borders.invisible.left;
1027 for (i = 0; i < n_left; i++)
1028 {
1029 MetaButtonSpace *rect;
1030
1031 rect = left_func_rects[i];
1032
1033 rect->visible.x = x + layout->button_border.left;
1034 rect->visible.y = button_y;
1035 rect->visible.width = button_width;
1036 rect->visible.height = button_height;
1037
1038 if (flags & META_FRAME_MAXIMIZED)
1039 {
1040 rect->clickable.x = rect->visible.x;
1041 rect->clickable.y = rect->visible.y;
1042 rect->clickable.width = button_width;
1043 rect->clickable.height = button_height;
1044 }
1045 else
1046 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1047
1048 x = rect->visible.x + rect->visible.width + layout->button_border.right;
1049 if (left_buttons_has_spacer[i])
1050 x += (int) (0.75 * (double) button_width);
1051
1052 *(left_bg_rects[i]) = rect->visible;
1053 }
1054
1055 /* We always fill as much vertical space as possible with title rect,
1056 * rather than centering it like the buttons
1057 */
1058 fgeom->title_rect.x = x + layout->title_border.left;
1059 fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
1060 fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
1061 fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
1062
1063 /* Nuke title if it won't fit */
1064 if (fgeom->title_rect.width < 0 ||
1065 fgeom->title_rect.height < 0)
1066 {
1067 fgeom->title_rect.width = 0;
1068 fgeom->title_rect.height = 0;
1069 }
1070
1071 if (flags & META_FRAME_SHADED)
1072 min_size_for_rounding = 0;
1073 else
1074 min_size_for_rounding = 5;
1075
1076 fgeom->top_left_corner_rounded_radius = 0;
1077 fgeom->top_right_corner_rounded_radius = 0;
1078 fgeom->bottom_left_corner_rounded_radius = 0;
1079 fgeom->bottom_right_corner_rounded_radius = 0;
1080
1081 if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
1082 fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
1083 if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
1084 fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
1085
1086 if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
1087 fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
1088 if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
1089 fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
1090}
1091
1092MetaGradientSpec*
1093meta_gradient_spec_new (MetaGradientType type)
1094{
1095 MetaGradientSpec *spec;
1096
1097 spec = g_new (MetaGradientSpec, 1)((MetaGradientSpec *) g_malloc_n ((1), sizeof (MetaGradientSpec
)))
;
1098
1099 spec->type = type;
1100 spec->color_specs = NULL((void*)0);
1101
1102 return spec;
1103}
1104
1105static cairo_pattern_t *
1106create_cairo_pattern_from_gradient_spec (const MetaGradientSpec *spec,
1107 const MetaAlphaGradientSpec *alpha_spec,
1108 GtkStyleContext *context)
1109{
1110 gint n_colors;
1111 cairo_pattern_t *pattern;
1112 GSList *tmp;
1113 gint i;
1114
1115 n_colors = g_slist_length (spec->color_specs);
1116 if (n_colors == 0)
1117 return NULL((void*)0);
1118
1119 if (alpha_spec != NULL((void*)0) && alpha_spec->n_alphas != 1)
1120 g_assert (n_colors == alpha_spec->n_alphas)do { if (n_colors == alpha_spec->n_alphas) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1120, ((const char*) (__func__)), "n_colors == alpha_spec->n_alphas"
); } while (0)
;
1121
1122 if (spec->type == META_GRADIENT_HORIZONTAL)
1123 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1124 else if (spec->type == META_GRADIENT_VERTICAL)
1125 pattern = cairo_pattern_create_linear (0, 0, 0, 1);
1126 else if (spec->type == META_GRADIENT_DIAGONAL)
1127 pattern = cairo_pattern_create_linear (0, 0, 1, 1);
1128 else
1129 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1129, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1130
1131 i = 0;
1132 tmp = spec->color_specs;
1133 while (tmp != NULL((void*)0))
1134 {
1135 GdkRGBA color;
1136
1137 meta_color_spec_render (tmp->data, context, &color);
1138
1139 if (alpha_spec != NULL((void*)0))
1140 {
1141 gdouble alpha;
1142
1143 if (alpha_spec->n_alphas == 1)
1144 alpha = alpha_spec->alphas[0] / 255.0;
1145 else
1146 alpha = alpha_spec->alphas[i] / 255.0;
1147
1148 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_colors - 1),
1149 color.red, color.green, color.blue,
1150 alpha);
1151 }
1152 else
1153 cairo_pattern_add_color_stop_rgb (pattern, i / (gfloat) (n_colors - 1),
1154 color.red, color.green, color.blue);
1155
1156 tmp = tmp->next;
1157 ++i;
1158 }
1159
1160 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1161 {
1162 cairo_pattern_destroy (pattern);
1163 return NULL((void*)0);
1164 }
1165
1166 return pattern;
1167}
1168
1169static void
1170free_color_spec (gpointer spec, gpointer user_data)
1171{
1172 meta_color_spec_free (spec);
1173}
1174
1175void
1176meta_gradient_spec_free (MetaGradientSpec *spec)
1177{
1178 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1179
1180 g_slist_foreach (spec->color_specs, free_color_spec, NULL((void*)0));
1181 g_slist_free (spec->color_specs);
1182
1183 DEBUG_FILL_STRUCT (spec)memset ((spec), 0xef, sizeof (*(spec)));
1184 g_free (spec);
1185}
1186
1187void
1188meta_gradient_spec_render (const MetaGradientSpec *spec,
1189 const MetaAlphaGradientSpec *alpha_spec,
1190 cairo_t *cr,
1191 GtkStyleContext *context,
1192 gint x,
1193 gint y,
1194 gint width,
1195 gint height)
1196{
1197 cairo_pattern_t *pattern;
1198
1199 pattern = create_cairo_pattern_from_gradient_spec (spec, alpha_spec, context);
1200 if (pattern == NULL((void*)0))
1201 return;
1202
1203 cairo_save (cr);
1204
1205 cairo_rectangle (cr, x, y, width, height);
1206
1207 cairo_translate (cr, x, y);
1208 cairo_scale (cr, width, height);
1209
1210 cairo_set_source (cr, pattern);
1211 cairo_fill (cr);
1212 cairo_pattern_destroy (pattern);
1213
1214 cairo_restore (cr);
1215}
1216
1217gboolean
1218meta_gradient_spec_validate (MetaGradientSpec *spec,
1219 GError **error)
1220{
1221 g_return_val_if_fail (spec != NULL, FALSE)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
((0)); } } while (0)
;
1222
1223 if (g_slist_length (spec->color_specs) < 2)
1224 {
1225 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1226 META_THEME_ERROR_FAILED,
1227 _("Gradients should have at least two colors")((char *) g_dgettext ("marco", "Gradients should have at least two colors"
))
);
1228 return FALSE(0);
1229 }
1230
1231 return TRUE(!(0));
1232}
1233
1234MetaAlphaGradientSpec*
1235meta_alpha_gradient_spec_new (MetaGradientType type,
1236 int n_alphas)
1237{
1238 MetaAlphaGradientSpec *spec;
1239
1240 g_return_val_if_fail (n_alphas > 0, NULL)do { if ((n_alphas > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_alphas > 0"); return
(((void*)0)); } } while (0)
;
1241
1242 spec = g_new0 (MetaAlphaGradientSpec, 1)((MetaAlphaGradientSpec *) g_malloc0_n ((1), sizeof (MetaAlphaGradientSpec
)))
;
1243
1244 spec->type = type;
1245 spec->alphas = g_new0 (unsigned char, n_alphas)((unsigned char *) g_malloc0_n ((n_alphas), sizeof (unsigned char
)))
;
1246 spec->n_alphas = n_alphas;
1247
1248 return spec;
1249}
1250
1251void
1252meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
1253{
1254 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1255
1256 g_free (spec->alphas);
1257 g_free (spec);
1258}
1259
1260cairo_pattern_t *
1261meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec)
1262{
1263 gint n_alphas;
1264 cairo_pattern_t *pattern;
1265 gint i;
1266
1267 /* Hardcoded in theme-parser.c */
1268 g_assert (spec->type == META_GRADIENT_HORIZONTAL)do { if (spec->type == META_GRADIENT_HORIZONTAL) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1268, ((const char*) (__func__)), "spec->type == META_GRADIENT_HORIZONTAL"
); } while (0)
;
1269
1270 n_alphas = spec->n_alphas;
1271 if (n_alphas == 0)
1272 return NULL((void*)0);
1273
1274 if (n_alphas == 1)
1275 return cairo_pattern_create_rgba (0, 0, 0, spec->alphas[0] / 255.0);
1276
1277 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1278
1279 for (i = 0; i < n_alphas; i++)
1280 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_alphas - 1),
1281 0, 0, 0, spec->alphas[i] / 255.0);
1282
1283 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1284 {
1285 cairo_pattern_destroy (pattern);
1286 return NULL((void*)0);
1287 }
1288
1289 return pattern;
1290}
1291
1292MetaColorSpec*
1293meta_color_spec_new (MetaColorSpecType type)
1294{
1295 MetaColorSpec *spec;
1296 MetaColorSpec dummy;
1297 int size;
1298
1299 size = G_STRUCT_OFFSET (MetaColorSpec, data)((glong) __builtin_offsetof(MetaColorSpec, data));
1300
1301 switch (type)
2
Control jumps to 'case META_COLOR_SPEC_GTK:' at line 1307
1302 {
1303 case META_COLOR_SPEC_BASIC:
1304 size += sizeof (dummy.data.basic);
1305 break;
1306
1307 case META_COLOR_SPEC_GTK:
1308 size += sizeof (dummy.data.gtk);
1309 break;
1310
1311 case META_COLOR_SPEC_GTK_CUSTOM:
1312 size += sizeof (dummy.data.gtkcustom);
1313 break;
1314
1315 case META_COLOR_SPEC_BLEND:
1316 size += sizeof (dummy.data.blend);
1317 break;
1318
1319 case META_COLOR_SPEC_SHADE:
1320 size += sizeof (dummy.data.shade);
1321 break;
1322 }
1323
1324 spec = g_malloc0 (size);
3
Execution continues on line 1324
4
Cast a region whose size is not a multiple of the destination type size
1325
1326 spec->type = type;
1327
1328 return spec;
1329}
1330
1331void
1332meta_color_spec_free (MetaColorSpec *spec)
1333{
1334 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1335
1336 switch (spec->type)
1337 {
1338 case META_COLOR_SPEC_BASIC:
1339 DEBUG_FILL_STRUCT (&spec->data.basic)memset ((&spec->data.basic), 0xef, sizeof (*(&spec
->data.basic)))
;
1340 break;
1341
1342 case META_COLOR_SPEC_GTK:
1343 DEBUG_FILL_STRUCT (&spec->data.gtk)memset ((&spec->data.gtk), 0xef, sizeof (*(&spec->
data.gtk)))
;
1344 break;
1345
1346 case META_COLOR_SPEC_GTK_CUSTOM:
1347 if (spec->data.gtkcustom.color_name)
1348 g_free (spec->data.gtkcustom.color_name);
1349 if (spec->data.gtkcustom.fallback)
1350 meta_color_spec_free (spec->data.gtkcustom.fallback);
1351 DEBUG_FILL_STRUCT (&spec->data.gtkcustom)memset ((&spec->data.gtkcustom), 0xef, sizeof (*(&
spec->data.gtkcustom)))
;
1352 break;
1353
1354 case META_COLOR_SPEC_BLEND:
1355 if (spec->data.blend.foreground)
1356 meta_color_spec_free (spec->data.blend.foreground);
1357 if (spec->data.blend.background)
1358 meta_color_spec_free (spec->data.blend.background);
1359 DEBUG_FILL_STRUCT (&spec->data.blend)memset ((&spec->data.blend), 0xef, sizeof (*(&spec
->data.blend)))
;
1360 break;
1361
1362 case META_COLOR_SPEC_SHADE:
1363 if (spec->data.shade.base)
1364 meta_color_spec_free (spec->data.shade.base);
1365 DEBUG_FILL_STRUCT (&spec->data.shade)memset ((&spec->data.shade), 0xef, sizeof (*(&spec
->data.shade)))
;
1366 break;
1367 }
1368
1369 g_free (spec);
1370}
1371
1372MetaColorSpec*
1373meta_color_spec_new_from_string (const char *str,
1374 GError **err)
1375{
1376 MetaColorSpec *spec;
1377
1378 spec = NULL((void*)0);
1379
1380 if (strncmp (str, "gtk:custom", 10) == 0)
1381 {
1382 const char *color_name_start, *fallback_str_start, *end;
1383 char *color_name;
1384 MetaColorSpec *fallback = NULL((void*)0);
1385 static gboolean debug, debug_set = FALSE(0);
1386
1387 if (!debug_set)
1388 {
1389 debug = g_getenv ("MARCO_DISABLE_FALLBACK_COLOR") != NULL((void*)0);
1390 debug_set = TRUE(!(0));
1391 }
1392
1393 if (str[10] != '(')
1394 {
1395 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1396 META_THEME_ERROR_FAILED,
1397 _("GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""
))
,
1398 str);
1399 return NULL((void*)0);
1400 }
1401
1402 color_name_start = str + 11;
1403
1404 fallback_str_start = color_name_start;
1405 while (*fallback_str_start && *fallback_str_start != ',')
1406 {
1407 if (!(g_ascii_isalnum (*fallback_str_start)((g_ascii_table[(guchar) (*fallback_str_start)] & G_ASCII_ALNUM
) != 0)
1408 || *fallback_str_start == '-'
1409 || *fallback_str_start == '_'))
1410 {
1411 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1412 META_THEME_ERROR_FAILED,
1413 _("Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid")((char *) g_dgettext ("marco", "Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid"
))
,
1414 *fallback_str_start);
1415 return NULL((void*)0);
1416 }
1417 fallback_str_start++;
1418 }
1419 fallback_str_start++;
1420
1421 end = strrchr (str, ')');
1422
1423 if (color_name_start == NULL((void*)0) || fallback_str_start == NULL((void*)0) || end == NULL((void*)0))
1424 {
1425 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1426 META_THEME_ERROR_FAILED,
1427 _("Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format"
))
,
1428 str);
1429 return NULL((void*)0);
1430 }
1431
1432 if (!debug)
1433 {
1434 char *fallback_str;
1435 fallback_str = g_strndup (fallback_str_start,
1436 end - fallback_str_start);
1437 fallback = meta_color_spec_new_from_string (fallback_str, err);
1438 g_free (fallback_str);
1439 }
1440 else
1441 {
1442 fallback = meta_color_spec_new_from_string ("pink", err);
1443 }
1444
1445 if (fallback == NULL((void*)0))
1446 return NULL((void*)0);
1447
1448 color_name = g_strndup (color_name_start, fallback_str_start - color_name_start - 1);
1449
1450 spec = meta_color_spec_new (META_COLOR_SPEC_GTK_CUSTOM);
1451 spec->data.gtkcustom.color_name = color_name;
1452 spec->data.gtkcustom.fallback = fallback;
1453 }
1454 else if (strncmp (str, "gtk:", 4) == 0)
1455 {
1456 /* GTK color */
1457 const char *bracket;
1458 const char *end_bracket;
1459 char *tmp;
1460 GtkStateFlags state;
1461 MetaGtkColorComponent component;
1462
1463 bracket = str;
1464 while (*bracket && *bracket != '[')
1465 ++bracket;
1466
1467 if (*bracket == '\0')
1468 {
1469 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1470 META_THEME_ERROR_FAILED,
1471 _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1472 str);
1473 return NULL((void*)0);
1474 }
1475
1476 end_bracket = bracket;
1477 ++end_bracket;
1478 while (*end_bracket && *end_bracket != ']')
1479 ++end_bracket;
1480
1481 if (*end_bracket == '\0')
1482 {
1483 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1484 META_THEME_ERROR_FAILED,
1485 _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1486 str);
1487 return NULL((void*)0);
1488 }
1489
1490 tmp = g_strndup (bracket + 1, end_bracket - bracket - 1);
1491 state = meta_gtk_state_from_string (tmp);
1492 if (((int) state) == -1)
1493 {
1494 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1495 META_THEME_ERROR_FAILED,
1496 _("Did not understand state \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand state \"%s\" in color specification"
))
,
1497 tmp);
1498 g_free (tmp);
1499 return NULL((void*)0);
1500 }
1501 g_free (tmp);
1502
1503 tmp = g_strndup (str + 4, bracket - str - 4);
1504 component = meta_color_component_from_string (tmp);
1505 if (component == META_GTK_COLOR_LAST)
1506 {
1507 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1508 META_THEME_ERROR_FAILED,
1509 _("Did not understand color component \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand color component \"%s\" in color specification"
))
,
1510 tmp);
1511 g_free (tmp);
1512 return NULL((void*)0);
1513 }
1514 g_free (tmp);
1515
1516 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1517 spec->data.gtk.state = state;
1518 spec->data.gtk.component = component;
1519 g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST)do { if (spec->data.gtk.component < META_GTK_COLOR_LAST
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 1519
, ((const char*) (__func__)), "spec->data.gtk.component < META_GTK_COLOR_LAST"
); } while (0)
;
1520 }
1521 else if (strncmp (str, "blend/", 6) == 0)
1522 {
1523 /* blend */
1524 char **split;
1525 double alpha;
1526 char *end;
1527 MetaColorSpec *fg;
1528 MetaColorSpec *bg;
1529
1530 split = g_strsplit (str, "/", 4);
1531
1532 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1533 split[2] == NULL((void*)0) || split[3] == NULL((void*)0))
1534 {
1535 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1536 META_THEME_ERROR_FAILED,
1537 _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"
))
,
1538 str);
1539 g_strfreev (split);
1540 return NULL((void*)0);
1541 }
1542
1543 alpha = g_ascii_strtod (split[3], &end);
1544 if (end == split[3])
1545 {
1546 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1547 META_THEME_ERROR_FAILED,
1548 _("Could not parse alpha value \"%s\" in blended color")((char *) g_dgettext ("marco", "Could not parse alpha value \"%s\" in blended color"
))
,
1549 split[3]);
1550 g_strfreev (split);
1551 return NULL((void*)0);
1552 }
1553
1554 if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6))
1555 {
1556 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1557 META_THEME_ERROR_FAILED,
1558 _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0")((char *) g_dgettext ("marco", "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
))
,
1559 split[3]);
1560 g_strfreev (split);
1561 return NULL((void*)0);
1562 }
1563
1564 fg = NULL((void*)0);
1565 bg = NULL((void*)0);
1566
1567 bg = meta_color_spec_new_from_string (split[1], err);
1568 if (bg == NULL((void*)0))
1569 {
1570 g_strfreev (split);
1571 return NULL((void*)0);
1572 }
1573
1574 fg = meta_color_spec_new_from_string (split[2], err);
1575 if (fg == NULL((void*)0))
1576 {
1577 meta_color_spec_free (bg);
1578 g_strfreev (split);
1579 return NULL((void*)0);
1580 }
1581
1582 g_strfreev (split);
1583
1584 spec = meta_color_spec_new (META_COLOR_SPEC_BLEND);
1585 spec->data.blend.alpha = alpha;
1586 spec->data.blend.background = bg;
1587 spec->data.blend.foreground = fg;
1588 }
1589 else if (strncmp (str, "shade/", 6) == 0)
1590 {
1591 /* shade */
1592 char **split;
1593 double factor;
1594 char *end;
1595 MetaColorSpec *base;
1596
1597 split = g_strsplit (str, "/", 3);
1598
1599 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1600 split[2] == NULL((void*)0))
1601 {
1602 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1603 META_THEME_ERROR_FAILED,
1604 _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
))
,
1605 str);
1606 g_strfreev (split);
1607 return NULL((void*)0);
1608 }
1609
1610 factor = g_ascii_strtod (split[2], &end);
1611 if (end == split[2])
1612 {
1613 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1614 META_THEME_ERROR_FAILED,
1615 _("Could not parse shade factor \"%s\" in shaded color")((char *) g_dgettext ("marco", "Could not parse shade factor \"%s\" in shaded color"
))
,
1616 split[2]);
1617 g_strfreev (split);
1618 return NULL((void*)0);
1619 }
1620
1621 if (factor < (0.0 - 1e6))
1622 {
1623 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1624 META_THEME_ERROR_FAILED,
1625 _("Shade factor \"%s\" in shaded color is negative")((char *) g_dgettext ("marco", "Shade factor \"%s\" in shaded color is negative"
))
,
1626 split[2]);
1627 g_strfreev (split);
1628 return NULL((void*)0);
1629 }
1630
1631 base = NULL((void*)0);
1632
1633 base = meta_color_spec_new_from_string (split[1], err);
1634 if (base == NULL((void*)0))
1635 {
1636 g_strfreev (split);
1637 return NULL((void*)0);
1638 }
1639
1640 g_strfreev (split);
1641
1642 spec = meta_color_spec_new (META_COLOR_SPEC_SHADE);
1643 spec->data.shade.factor = factor;
1644 spec->data.shade.base = base;
1645 }
1646 else
1647 {
1648 spec = meta_color_spec_new (META_COLOR_SPEC_BASIC);
1649
1650 if (!gdk_rgba_parse (&spec->data.basic.color, str))
1651 {
1652 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1653 META_THEME_ERROR_FAILED,
1654 _("Could not parse color \"%s\"")((char *) g_dgettext ("marco", "Could not parse color \"%s\""
))
,
1655 str);
1656 meta_color_spec_free (spec);
1657 return NULL((void*)0);
1658 }
1659 }
1660
1661 g_assert (spec)do { if (spec) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 1661, ((const char*) (__func__)), "spec"); } while (0)
;
1662
1663 return spec;
1664}
1665
1666MetaColorSpec*
1667meta_color_spec_new_gtk (MetaGtkColorComponent component,
1668 GtkStateFlags state)
1669{
1670 MetaColorSpec *spec;
1671
1672 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1
Calling 'meta_color_spec_new'
1673
1674 spec->data.gtk.component = component;
1675 spec->data.gtk.state = state;
1676
1677 return spec;
1678}
1679
1680static void
1681get_background_color_real (GtkStyleContext *context,
1682 GtkStateFlags state,
1683 GdkRGBA *color)
1684{
1685 GdkRGBA *c;
1686
1687 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "color != NULL"); return
; } } while (0)
;
1688 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context)); GType __t = ((gtk_style_context_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "GTK_IS_STYLE_CONTEXT (context)"); return; } }
while (0)
;
1689
1690 gtk_style_context_get (context,
1691 state,
1692 "background-color", &c,
1693 NULL((void*)0));
1694
1695 *color = *c;
1696 gdk_rgba_free (c);
1697}
1698
1699static void
1700get_background_color (GtkStyleContext *context,
1701 GtkStateFlags state,
1702 GdkRGBA *color)
1703{
1704 GdkRGBA empty = { 0.0, 0.0, 0.0, 0.0 };
1705 GdkRGBA rgba;
1706
1707 get_background_color_real (context, state, &rgba);
1708
1709 if (gdk_rgba_equal (&rgba, &empty))
1710 {
1711 GtkWidget *toplevel;
1712 GtkStyleContext *tmp;
1713
1714 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1715 tmp = gtk_widget_get_style_context (toplevel);
1716
1717 get_background_color_real (tmp, state, &rgba);
1718
1719 gtk_widget_destroy (toplevel);
1720 }
1721
1722 *color = rgba;
1723}
1724
1725/* Based on set_color() in gtkstyle.c */
1726#define LIGHTNESS_MULT1.3 1.3
1727#define DARKNESS_MULT0.7 0.7
1728void
1729meta_gtk_style_get_light_color (GtkStyleContext *style,
1730 GtkStateFlags state,
1731 GdkRGBA *color)
1732{
1733 get_background_color (style, state, color);
1734 gtk_style_shade (color, color, LIGHTNESS_MULT1.3);
1735}
1736
1737void
1738meta_gtk_style_get_dark_color (GtkStyleContext *style,
1739 GtkStateFlags state,
1740 GdkRGBA *color)
1741{
1742 get_background_color (style, state, color);
1743 gtk_style_shade (color, color, DARKNESS_MULT0.7);
1744}
1745
1746static void
1747meta_set_color_from_style (GdkRGBA *color,
1748 GtkStyleContext *context,
1749 GtkStateFlags state,
1750 MetaGtkColorComponent component)
1751{
1752 GdkRGBA other;
1753
1754 /* Add background class to context to get the correct colors from the GTK+
1755 theme instead of white text over black background. */
1756 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND"background");
1757
1758 switch (component)
1759 {
1760 case META_GTK_COLOR_BG:
1761 case META_GTK_COLOR_BASE:
1762 get_background_color (context, state, color);
1763 break;
1764 case META_GTK_COLOR_FG:
1765 case META_GTK_COLOR_TEXT:
1766 gtk_style_context_get_color (context, state, color);
1767 break;
1768 case META_GTK_COLOR_TEXT_AA:
1769 gtk_style_context_get_color (context, state, color);
1770 meta_set_color_from_style (&other, context, state, META_GTK_COLOR_BASE);
1771
1772 color->red = (color->red + other.red) / 2;
1773 color->green = (color->green + other.green) / 2;
1774 color->blue = (color->blue + other.blue) / 2;
1775 break;
1776 case META_GTK_COLOR_MID:
1777 meta_gtk_style_get_light_color (context, state, color);
1778 meta_gtk_style_get_dark_color (context, state, &other);
1779
1780 color->red = (color->red + other.red) / 2;
1781 color->green = (color->green + other.green) / 2;
1782 color->blue = (color->blue + other.blue) / 2;
1783 break;
1784 case META_GTK_COLOR_LIGHT:
1785 meta_gtk_style_get_light_color (context, state, color);
1786 break;
1787 case META_GTK_COLOR_DARK:
1788 meta_gtk_style_get_dark_color (context, state, color);
1789 break;
1790 case META_GTK_COLOR_LAST:
1791 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1791, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1792 break;
1793 }
1794}
1795
1796static void
1797meta_set_custom_color_from_style (GdkRGBA *color,
1798 GtkStyleContext *context,
1799 char *color_name,
1800 MetaColorSpec *fallback)
1801{
1802 if (!gtk_style_context_lookup_color (context, color_name, color))
1803 meta_color_spec_render (fallback, context, color);
1804}
1805
1806void
1807meta_color_spec_render (MetaColorSpec *spec,
1808 GtkStyleContext *style,
1809 GdkRGBA *color)
1810{
1811 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1812
1813 g_return_if_fail (GTK_IS_STYLE_CONTEXT (style))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((style)); GType __t = ((gtk_style_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GTK_IS_STYLE_CONTEXT (style)"); return; } } while (0)
;
1814
1815 switch (spec->type)
1816 {
1817 case META_COLOR_SPEC_BASIC:
1818 *color = spec->data.basic.color;
1819 break;
1820
1821 case META_COLOR_SPEC_GTK:
1822 meta_set_color_from_style (color,
1823 style,
1824 spec->data.gtk.state,
1825 spec->data.gtk.component);
1826 break;
1827
1828 case META_COLOR_SPEC_GTK_CUSTOM:
1829 meta_set_custom_color_from_style (color,
1830 style,
1831 spec->data.gtkcustom.color_name,
1832 spec->data.gtkcustom.fallback);
1833 break;
1834
1835 case META_COLOR_SPEC_BLEND:
1836 {
1837 GdkRGBA bg, fg;
1838
1839 meta_color_spec_render (spec->data.blend.background, style, &bg);
1840 meta_color_spec_render (spec->data.blend.foreground, style, &fg);
1841
1842 color_composite (&bg, &fg, spec->data.blend.alpha,
1843 &spec->data.blend.color);
1844
1845 *color = spec->data.blend.color;
1846 }
1847 break;
1848
1849 case META_COLOR_SPEC_SHADE:
1850 {
1851 meta_color_spec_render (spec->data.shade.base, style,
1852 &spec->data.shade.color);
1853
1854 gtk_style_shade (&spec->data.shade.color,
1855 &spec->data.shade.color, spec->data.shade.factor);
1856
1857 *color = spec->data.shade.color;
1858 }
1859 break;
1860 }
1861}
1862
1863/**
1864 * Represents an operation as a string.
1865 *
1866 * \param type an operation, such as addition
1867 * \return a string, such as "+"
1868 */
1869static const char*
1870op_name (PosOperatorType type)
1871{
1872 switch (type)
1873 {
1874 case POS_OP_ADD:
1875 return "+";
1876 case POS_OP_SUBTRACT:
1877 return "-";
1878 case POS_OP_MULTIPLY:
1879 return "*";
1880 case POS_OP_DIVIDE:
1881 return "/";
1882 case POS_OP_MOD:
1883 return "%";
1884 case POS_OP_MAX:
1885 return "`max`";
1886 case POS_OP_MIN:
1887 return "`min`";
1888 case POS_OP_NONE:
1889 break;
1890 }
1891
1892 return "<unknown>";
1893}
1894
1895/**
1896 * Parses a string and returns an operation.
1897 *
1898 * \param p a pointer into a string representing an operation; part of an
1899 * expression somewhere, so not null-terminated
1900 * \param len set to the length of the string found. Set to 0 if none is.
1901 * \return the operation found. If none was, returns POS_OP_NONE.
1902 */
1903static PosOperatorType
1904op_from_string (const char *p,
1905 int *len)
1906{
1907 *len = 0;
1908
1909 switch (*p)
1910 {
1911 case '+':
1912 *len = 1;
1913 return POS_OP_ADD;
1914 case '-':
1915 *len = 1;
1916 return POS_OP_SUBTRACT;
1917 case '*':
1918 *len = 1;
1919 return POS_OP_MULTIPLY;
1920 case '/':
1921 *len = 1;
1922 return POS_OP_DIVIDE;
1923 case '%':
1924 *len = 1;
1925 return POS_OP_MOD;
1926
1927 case '`':
1928 if (strncmp (p, "`max`", 5) == 0)
1929 {
1930 *len = 5;
1931 return POS_OP_MAX;
1932 }
1933 else if (strncmp (p, "`min`", 5) == 0)
1934 {
1935 *len = 5;
1936 return POS_OP_MIN;
1937 }
1938 }
1939
1940 return POS_OP_NONE;
1941}
1942
1943/**
1944 * Frees an array of tokens. All the tokens and their associated memory
1945 * will be freed.
1946 *
1947 * \param tokens an array of tokens to be freed
1948 * \param n_tokens how many tokens are in the array.
1949 */
1950static void
1951free_tokens (PosToken *tokens,
1952 int n_tokens)
1953{
1954 int i;
1955
1956 /* n_tokens can be 0 since tokens may have been allocated more than
1957 * it was initialized
1958 */
1959
1960 for (i = 0; i < n_tokens; i++)
1961 if (tokens[i].type == POS_TOKEN_VARIABLE)
1962 g_free (tokens[i].d.v.name);
1963
1964 g_free (tokens);
1965}
1966
1967/**
1968 * Tokenises a number in an expression.
1969 *
1970 * \param p a pointer into a string representing an operation; part of an
1971 * expression somewhere, so not null-terminated
1972 * \param end_return set to a pointer to the end of the number found; but
1973 * not updated if no number was found at all
1974 * \param next set to either an integer or a float token
1975 * \param[out] err set to the problem if there was a problem
1976 * \return TRUE if a valid number was found, FALSE otherwise (and "err" will
1977 * have been set)
1978 *
1979 * \bug The "while (*start)..." part: what's wrong with strchr-ish things?
1980 * \bug The name is wrong: it doesn't parse anything.
1981 * \ingroup tokenizer
1982 */
1983static gboolean
1984parse_number (const char *p,
1985 const char **end_return,
1986 PosToken *next,
1987 GError **err)
1988{
1989 const char *start = p;
1990 char *end;
1991 gboolean is_float;
1992 char *num_str;
1993
1994 while (*p && (*p == '.' || g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0)))
1995 ++p;
1996
1997 if (p == start)
1998 {
1999 char buf[7] = { '\0' };
2000 buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0';
2001 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2002 META_THEME_ERROR_BAD_CHARACTER,
2003 _("Coordinate expression contains character '%s' which is not allowed")((char *) g_dgettext ("marco", "Coordinate expression contains character '%s' which is not allowed"
))
,
2004 buf);
2005 return FALSE(0);
2006 }
2007
2008 *end_return = p;
2009
2010 /* we need this to exclude floats like "1e6" */
2011 num_str = g_strndup (start, p - start);
2012 start = num_str;
2013 is_float = FALSE(0);
2014 while (*start)
2015 {
2016 if (*start == '.')
2017 is_float = TRUE(!(0));
2018 ++start;
2019 }
2020
2021 if (is_float)
2022 {
2023 next->type = POS_TOKEN_DOUBLE;
2024 next->d.d.val = g_ascii_strtod (num_str, &end);
2025
2026 if (end == num_str)
2027 {
2028 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2029 META_THEME_ERROR_FAILED,
2030 _("Coordinate expression contains floating point number '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains floating point number '%s' which could not be parsed"
))
,
2031 num_str);
2032 g_free (num_str);
2033 return FALSE(0);
2034 }
2035 }
2036 else
2037 {
2038 next->type = POS_TOKEN_INT;
2039 next->d.i.val = strtol (num_str, &end, 10);
2040 if (end == num_str)
2041 {
2042 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2043 META_THEME_ERROR_FAILED,
2044 _("Coordinate expression contains integer '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains integer '%s' which could not be parsed"
))
,
2045 num_str);
2046 g_free (num_str);
2047 return FALSE(0);
2048 }
2049 }
2050
2051 g_free (num_str);
2052
2053 g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE)do { if (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 2053
, ((const char*) (__func__)), "next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE"
); } while (0)
;
2054
2055 return TRUE(!(0));
2056}
2057
2058/**
2059 * Whether a variable can validly appear as part of the name of a variable.
2060 */
2061#define IS_VARIABLE_CHAR(c)(((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) ||
(c) == '_')
(g_ascii_isalpha ((c))((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) || (c) == '_')
2062
2063#if 0
2064static void
2065debug_print_tokens (PosToken *tokens,
2066 int n_tokens)
2067{
2068 int i;
2069
2070 for (i = 0; i < n_tokens; i++)
2071 {
2072 PosToken *t = &tokens[i];
2073
2074 g_print (" ");
2075
2076 switch (t->type)
2077 {
2078 case POS_TOKEN_INT:
2079 g_print ("\"%d\"", t->d.i.val);
2080 break;
2081 case POS_TOKEN_DOUBLE:
2082 g_print ("\"%g\"", t->d.d.val);
2083 break;
2084 case POS_TOKEN_OPEN_PAREN:
2085 g_print ("\"(\"");
2086 break;
2087 case POS_TOKEN_CLOSE_PAREN:
2088 g_print ("\")\"");
2089 break;
2090 case POS_TOKEN_VARIABLE:
2091 g_print ("\"%s\"", t->d.v.name);
2092 break;
2093 case POS_TOKEN_OPERATOR:
2094 g_print ("\"%s\"", op_name (t->d.o.op));
2095 break;
2096 }
2097 }
2098
2099 g_print ("\n");
2100}
2101#endif
2102
2103/**
2104 * Tokenises an expression.
2105 *
2106 * \param expr The expression
2107 * \param[out] tokens_p The resulting tokens
2108 * \param[out] n_tokens_p The number of resulting tokens
2109 * \param[out] err set to the problem if there was a problem
2110 *
2111 * \return True if the expression was successfully tokenised; false otherwise.
2112 *
2113 * \ingroup tokenizer
2114 */
2115static gboolean
2116pos_tokenize (const char *expr,
2117 PosToken **tokens_p,
2118 int *n_tokens_p,
2119 GError **err)
2120{
2121 PosToken *tokens;
2122 int n_tokens;
2123 int allocated;
2124 const char *p;
2125
2126 *tokens_p = NULL((void*)0);
2127 *n_tokens_p = 0;
2128
2129 allocated = 3;
2130 n_tokens = 0;
2131 tokens = g_new (PosToken, allocated)((PosToken *) g_malloc_n ((allocated), sizeof (PosToken)));
2132
2133 p = expr;
2134 while (*p)
2135 {
2136 PosToken *next;
2137 int len;
2138
2139 if (n_tokens == allocated)
2140 {
2141 allocated *= 2;
2142 tokens = g_renew (PosToken, tokens, allocated)((PosToken *) g_realloc_n (tokens, (allocated), sizeof (PosToken
)))
;
2143 }
2144
2145 next = &tokens[n_tokens];
2146
2147 switch (*p)
2148 {
2149 case '*':
2150 case '/':
2151 case '+':
2152 case '-': /* negative numbers aren't allowed so this is easy */
2153 case '%':
2154 case '`':
2155 next->type = POS_TOKEN_OPERATOR;
2156 next->d.o.op = op_from_string (p, &len);
2157 if (next->d.o.op != POS_OP_NONE)
2158 {
2159 ++n_tokens;
2160 p = p + (len - 1); /* -1 since we ++p later */
2161 }
2162 else
2163 {
2164 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2165 META_THEME_ERROR_FAILED,
2166 _("Coordinate expression contained unknown operator at the start of this text: \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression contained unknown operator at the start of this text: \"%s\""
))
,
2167 p);
2168
2169 goto error;
2170 }
2171 break;
2172
2173 case '(':
2174 next->type = POS_TOKEN_OPEN_PAREN;
2175 ++n_tokens;
2176 break;
2177
2178 case ')':
2179 next->type = POS_TOKEN_CLOSE_PAREN;
2180 ++n_tokens;
2181 break;
2182
2183 case ' ':
2184 case '\t':
2185 case '\n':
2186 break;
2187
2188 default:
2189 if (IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2190 {
2191 /* Assume variable */
2192 const char *start = p;
2193 while (*p && IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2194 ++p;
2195 g_assert (p != start)do { if (p != start) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2195, ((const char*) (__func__)), "p != start"
); } while (0)
;
2196 next->type = POS_TOKEN_VARIABLE;
2197 next->d.v.name = g_strndup (start, p - start);
2198 ++n_tokens;
2199 --p; /* since we ++p again at the end of while loop */
2200 }
2201 else
2202 {
2203 /* Assume number */
2204 const char *end;
2205
2206 if (!parse_number (p, &end, next, err))
2207 goto error;
2208
2209 ++n_tokens;
2210 p = end - 1; /* -1 since we ++p again at the end of while loop */
2211 }
2212
2213 break;
2214 }
2215
2216 ++p;
2217 }
2218
2219 if (n_tokens == 0)
2220 {
2221 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2222 META_THEME_ERROR_FAILED,
2223 _("Coordinate expression was empty or not understood")((char *) g_dgettext ("marco", "Coordinate expression was empty or not understood"
))
);
2224
2225 goto error;
2226 }
2227
2228 *tokens_p = tokens;
2229 *n_tokens_p = n_tokens;
2230
2231 return TRUE(!(0));
2232
2233 error:
2234 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2234, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2235
2236 free_tokens (tokens, n_tokens);
2237 return FALSE(0);
2238}
2239
2240/**
2241 * The type of a PosExpr: either integer, double, or an operation.
2242 * \ingroup parser
2243 */
2244typedef enum
2245{
2246 POS_EXPR_INT,
2247 POS_EXPR_DOUBLE,
2248 POS_EXPR_OPERATOR
2249} PosExprType;
2250
2251/**
2252 * Type and value of an expression in a parsed sequence. We don't
2253 * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR,
2254 * the arguments of the operator will be in the array positions
2255 * immediately preceding and following this operator; they cannot
2256 * themselves be operators.
2257 *
2258 * \bug operator is char; it should really be of PosOperatorType.
2259 * \ingroup parser
2260 */
2261typedef struct
2262{
2263 PosExprType type;
2264 union
2265 {
2266 double double_val;
2267 int int_val;
2268 char operator;
2269 } d;
2270} PosExpr;
2271
2272#if 0
2273static void
2274debug_print_exprs (PosExpr *exprs,
2275 int n_exprs)
2276{
2277 int i;
2278
2279 for (i = 0; i < n_exprs; i++)
2280 {
2281 switch (exprs[i].type)
2282 {
2283 case POS_EXPR_INT:
2284 g_print (" %d", exprs[i].d.int_val);
2285 break;
2286 case POS_EXPR_DOUBLE:
2287 g_print (" %g", exprs[i].d.double_val);
2288 break;
2289 case POS_EXPR_OPERATOR:
2290 g_print (" %s", op_name (exprs[i].d.operator));
2291 break;
2292 }
2293 }
2294 g_print ("\n");
2295}
2296#endif
2297
2298static gboolean
2299do_operation (PosExpr *a,
2300 PosExpr *b,
2301 PosOperatorType op,
2302 GError **err)
2303{
2304 /* Promote types to double if required */
2305 if (a->type == POS_EXPR_DOUBLE ||
2306 b->type == POS_EXPR_DOUBLE)
2307 {
2308 if (a->type != POS_EXPR_DOUBLE)
2309 {
2310 a->type = POS_EXPR_DOUBLE;
2311 a->d.double_val = a->d.int_val;
2312 }
2313 if (b->type != POS_EXPR_DOUBLE)
2314 {
2315 b->type = POS_EXPR_DOUBLE;
2316 b->d.double_val = b->d.int_val;
2317 }
2318 }
2319
2320 g_assert (a->type == b->type)do { if (a->type == b->type) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2320, ((const char*) (__func__)), "a->type == b->type"
); } while (0)
;
2321
2322 if (a->type == POS_EXPR_INT)
2323 {
2324 switch (op)
2325 {
2326 case POS_OP_MULTIPLY:
2327 a->d.int_val = a->d.int_val * b->d.int_val;
2328 break;
2329 case POS_OP_DIVIDE:
2330 if (b->d.int_val == 0)
2331 {
2332 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2333 META_THEME_ERROR_DIVIDE_BY_ZERO,
2334 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2335 return FALSE(0);
2336 }
2337 a->d.int_val = a->d.int_val / b->d.int_val;
2338 break;
2339 case POS_OP_MOD:
2340 if (b->d.int_val == 0)
2341 {
2342 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2343 META_THEME_ERROR_DIVIDE_BY_ZERO,
2344 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2345 return FALSE(0);
2346 }
2347 a->d.int_val = a->d.int_val % b->d.int_val;
2348 break;
2349 case POS_OP_ADD:
2350 a->d.int_val = a->d.int_val + b->d.int_val;
2351 break;
2352 case POS_OP_SUBTRACT:
2353 a->d.int_val = a->d.int_val - b->d.int_val;
2354 break;
2355 case POS_OP_MAX:
2356 a->d.int_val = MAX (a->d.int_val, b->d.int_val)(((a->d.int_val) > (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2357 break;
2358 case POS_OP_MIN:
2359 a->d.int_val = MIN (a->d.int_val, b->d.int_val)(((a->d.int_val) < (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2360 break;
2361 case POS_OP_NONE:
2362 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2362, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2363 break;
2364 }
2365 }
2366 else if (a->type == POS_EXPR_DOUBLE)
2367 {
2368 switch (op)
2369 {
2370 case POS_OP_MULTIPLY:
2371 a->d.double_val = a->d.double_val * b->d.double_val;
2372 break;
2373 case POS_OP_DIVIDE:
2374 if (b->d.double_val == 0.0)
2375 {
2376 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2377 META_THEME_ERROR_DIVIDE_BY_ZERO,
2378 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2379 return FALSE(0);
2380 }
2381 a->d.double_val = a->d.double_val / b->d.double_val;
2382 break;
2383 case POS_OP_MOD:
2384 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2385 META_THEME_ERROR_MOD_ON_FLOAT,
2386 _("Coordinate expression tries to use mod operator on a floating-point number")((char *) g_dgettext ("marco", "Coordinate expression tries to use mod operator on a floating-point number"
))
);
2387 return FALSE(0);
2388 case POS_OP_ADD:
2389 a->d.double_val = a->d.double_val + b->d.double_val;
2390 break;
2391 case POS_OP_SUBTRACT:
2392 a->d.double_val = a->d.double_val - b->d.double_val;
2393 break;
2394 case POS_OP_MAX:
2395 a->d.double_val = MAX (a->d.double_val, b->d.double_val)(((a->d.double_val) > (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2396 break;
2397 case POS_OP_MIN:
2398 a->d.double_val = MIN (a->d.double_val, b->d.double_val)(((a->d.double_val) < (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2399 break;
2400 case POS_OP_NONE:
2401 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2401, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2402 break;
2403 }
2404 }
2405 else
2406 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2406, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2407
2408 return TRUE(!(0));
2409}
2410
2411static gboolean
2412do_operations (PosExpr *exprs,
2413 int *n_exprs,
2414 int precedence,
2415 GError **err)
2416{
2417 int i;
2418
2419#if 0
2420 g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs);
2421 debug_print_exprs (exprs, *n_exprs);
2422#endif
2423
2424 i = 1;
2425 while (i < *n_exprs)
2426 {
2427 gboolean compress;
2428
2429 /* exprs[i-1] first operand
2430 * exprs[i] operator
2431 * exprs[i+1] second operand
2432 *
2433 * we replace first operand with result of mul/div/mod,
2434 * or skip over operator and second operand if we have
2435 * an add/subtract
2436 */
2437
2438 if (exprs[i-1].type == POS_EXPR_OPERATOR)
2439 {
2440 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2441 META_THEME_ERROR_FAILED,
2442 _("Coordinate expression has an operator \"%s\" where an operand was expected")((char *) g_dgettext ("marco", "Coordinate expression has an operator \"%s\" where an operand was expected"
))
,
2443 op_name (exprs[i-1].d.operator));
2444 return FALSE(0);
2445 }
2446
2447 if (exprs[i].type != POS_EXPR_OPERATOR)
2448 {
2449 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2450 META_THEME_ERROR_FAILED,
2451 _("Coordinate expression had an operand where an operator was expected")((char *) g_dgettext ("marco", "Coordinate expression had an operand where an operator was expected"
))
);
2452 return FALSE(0);
2453 }
2454
2455 if (i == (*n_exprs - 1))
2456 {
2457 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2458 META_THEME_ERROR_FAILED,
2459 _("Coordinate expression ended with an operator instead of an operand")((char *) g_dgettext ("marco", "Coordinate expression ended with an operator instead of an operand"
))
);
2460 return FALSE(0);
2461 }
2462
2463 g_assert ((i+1) < *n_exprs)do { if ((i+1) < *n_exprs) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2463, ((const char*) (__func__)), "(i+1) < *n_exprs"
); } while (0)
;
2464
2465 if (exprs[i+1].type == POS_EXPR_OPERATOR)
2466 {
2467 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2468 META_THEME_ERROR_FAILED,
2469 _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between")((char *) g_dgettext ("marco", "Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"
))
,
2470 exprs[i+1].d.operator,
2471 exprs[i].d.operator);
2472 return FALSE(0);
2473 }
2474
2475 compress = FALSE(0);
2476
2477 switch (precedence)
2478 {
2479 case 2:
2480 switch (exprs[i].d.operator)
2481 {
2482 case POS_OP_DIVIDE:
2483 case POS_OP_MOD:
2484 case POS_OP_MULTIPLY:
2485 compress = TRUE(!(0));
2486 if (!do_operation (&exprs[i-1], &exprs[i+1],
2487 exprs[i].d.operator,
2488 err))
2489 return FALSE(0);
2490 break;
2491 }
2492 break;
2493 case 1:
2494 switch (exprs[i].d.operator)
2495 {
2496 case POS_OP_ADD:
2497 case POS_OP_SUBTRACT:
2498 compress = TRUE(!(0));
2499 if (!do_operation (&exprs[i-1], &exprs[i+1],
2500 exprs[i].d.operator,
2501 err))
2502 return FALSE(0);
2503 break;
2504 }
2505 break;
2506 /* I have no rationale at all for making these low-precedence */
2507 case 0:
2508 switch (exprs[i].d.operator)
2509 {
2510 case POS_OP_MAX:
2511 case POS_OP_MIN:
2512 compress = TRUE(!(0));
2513 if (!do_operation (&exprs[i-1], &exprs[i+1],
2514 exprs[i].d.operator,
2515 err))
2516 return FALSE(0);
2517 break;
2518 }
2519 break;
2520 }
2521
2522 if (compress)
2523 {
2524 /* exprs[i-1] first operand (now result)
2525 * exprs[i] operator
2526 * exprs[i+1] second operand
2527 * exprs[i+2] new operator
2528 *
2529 * we move new operator just after first operand
2530 */
2531 if ((i+2) < *n_exprs)
2532 {
2533 memmove (&exprs[i], &exprs[i+2],
2534 sizeof (PosExpr) * (*n_exprs - i - 2));
2535 }
2536
2537 *n_exprs -= 2;
2538 }
2539 else
2540 {
2541 /* Skip operator and next operand */
2542 i += 2;
2543 }
2544 }
2545
2546 return TRUE(!(0));
2547}
2548
2549/**
2550 * There is a predefined set of variables which can appear in an expression.
2551 * Here we take a token representing a variable, and return the current value
2552 * of that variable in a particular environment.
2553 * (The value is always an integer.)
2554 *
2555 * There are supposedly some circumstances in which this function can be
2556 * called from outside Marco, in which case env->theme will be NULL, and
2557 * therefore we can't use it to find out quark values, so we do the comparison
2558 * using strcmp, which is slower.
2559 *
2560 * \param t The token representing a variable
2561 * \param[out] result The value of that variable; not set if the token did
2562 * not represent a known variable
2563 * \param env The environment within which t should be evaluated
2564 * \param[out] err set to the problem if there was a problem
2565 *
2566 * \return true if we found the variable asked for, false if we didn't
2567 *
2568 * \bug shouldn't t be const?
2569 * \bug we should perhaps consider some sort of lookup arrangement into an
2570 * array; also, the duplication of code is unlovely; perhaps using glib
2571 * string hashes instead of quarks would fix both problems?
2572 * \ingroup parser
2573 */
2574static gboolean
2575pos_eval_get_variable (PosToken *t,
2576 int *result,
2577 const MetaPositionExprEnv *env,
2578 GError **err)
2579{
2580 if (env->theme)
2581 {
2582 if (t->d.v.name_quark == env->theme->quark_width)
2583 *result = env->rect.width;
2584 else if (t->d.v.name_quark == env->theme->quark_height)
2585 *result = env->rect.height;
2586 else if (env->object_width >= 0 &&
2587 t->d.v.name_quark == env->theme->quark_object_width)
2588 *result = env->object_width;
2589 else if (env->object_height >= 0 &&
2590 t->d.v.name_quark == env->theme->quark_object_height)
2591 *result = env->object_height;
2592 else if (t->d.v.name_quark == env->theme->quark_left_width)
2593 *result = env->left_width;
2594 else if (t->d.v.name_quark == env->theme->quark_right_width)
2595 *result = env->right_width;
2596 else if (t->d.v.name_quark == env->theme->quark_top_height)
2597 *result = env->top_height;
2598 else if (t->d.v.name_quark == env->theme->quark_bottom_height)
2599 *result = env->bottom_height;
2600 else if (t->d.v.name_quark == env->theme->quark_mini_icon_width)
2601 *result = env->mini_icon_width;
2602 else if (t->d.v.name_quark == env->theme->quark_mini_icon_height)
2603 *result = env->mini_icon_height;
2604 else if (t->d.v.name_quark == env->theme->quark_icon_width)
2605 *result = env->icon_width;
2606 else if (t->d.v.name_quark == env->theme->quark_icon_height)
2607 *result = env->icon_height;
2608 else if (t->d.v.name_quark == env->theme->quark_title_width)
2609 *result = env->title_width;
2610 else if (t->d.v.name_quark == env->theme->quark_title_height)
2611 *result = env->title_height;
2612 else if (t->d.v.name_quark == env->theme->quark_frame_x_center)
2613 *result = env->frame_x_center;
2614 else if (t->d.v.name_quark == env->theme->quark_frame_y_center)
2615 *result = env->frame_y_center;
2616 else
2617 {
2618 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2619 META_THEME_ERROR_UNKNOWN_VARIABLE,
2620 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2621 t->d.v.name);
2622 return FALSE(0);
2623 }
2624 }
2625 else
2626 {
2627 if (strcmp (t->d.v.name, "width") == 0)
2628 *result = env->rect.width;
2629 else if (strcmp (t->d.v.name, "height") == 0)
2630 *result = env->rect.height;
2631 else if (env->object_width >= 0 &&
2632 strcmp (t->d.v.name, "object_width") == 0)
2633 *result = env->object_width;
2634 else if (env->object_height >= 0 &&
2635 strcmp (t->d.v.name, "object_height") == 0)
2636 *result = env->object_height;
2637 else if (strcmp (t->d.v.name, "left_width") == 0)
2638 *result = env->left_width;
2639 else if (strcmp (t->d.v.name, "right_width") == 0)
2640 *result = env->right_width;
2641 else if (strcmp (t->d.v.name, "top_height") == 0)
2642 *result = env->top_height;
2643 else if (strcmp (t->d.v.name, "bottom_height") == 0)
2644 *result = env->bottom_height;
2645 else if (strcmp (t->d.v.name, "mini_icon_width") == 0)
2646 *result = env->mini_icon_width;
2647 else if (strcmp (t->d.v.name, "mini_icon_height") == 0)
2648 *result = env->mini_icon_height;
2649 else if (strcmp (t->d.v.name, "icon_width") == 0)
2650 *result = env->icon_width;
2651 else if (strcmp (t->d.v.name, "icon_height") == 0)
2652 *result = env->icon_height;
2653 else if (strcmp (t->d.v.name, "title_width") == 0)
2654 *result = env->title_width;
2655 else if (strcmp (t->d.v.name, "title_height") == 0)
2656 *result = env->title_height;
2657 else if (strcmp (t->d.v.name, "frame_x_center") == 0)
2658 *result = env->frame_x_center;
2659 else if (strcmp (t->d.v.name, "frame_y_center") == 0)
2660 *result = env->frame_y_center;
2661 else
2662 {
2663 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2664 META_THEME_ERROR_UNKNOWN_VARIABLE,
2665 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2666 t->d.v.name);
2667 return FALSE(0);
2668 }
2669 }
2670
2671 return TRUE(!(0));
2672}
2673
2674/**
2675 * Evaluates a sequence of tokens within a particular environment context,
2676 * and returns the current value. May recur if parantheses are found.
2677 *
2678 * \param tokens A list of tokens to evaluate.
2679 * \param n_tokens How many tokens are in the list.
2680 * \param env The environment context in which to evaluate the expression.
2681 * \param[out] result The current value of the expression
2682 *
2683 * \bug Yes, we really do reparse the expression every time it's evaluated.
2684 * We should keep the parse tree around all the time and just
2685 * run the new values through it.
2686 * \ingroup parser
2687 */
2688static gboolean
2689pos_eval_helper (PosToken *tokens,
2690 int n_tokens,
2691 const MetaPositionExprEnv *env,
2692 PosExpr *result,
2693 GError **err)
2694{
2695 /* Lazy-ass hardcoded limit on number of terms in expression */
2696#define MAX_EXPRS32 32
2697 int paren_level;
2698 int first_paren;
2699 int i;
2700 PosExpr exprs[MAX_EXPRS32];
2701 int n_exprs;
2702 int precedence;
2703
2704 /* Our first goal is to get a list of PosExpr, essentially
2705 * substituting variables and handling parentheses.
2706 */
2707
2708 first_paren = 0;
2709 paren_level = 0;
2710 n_exprs = 0;
2711 for (i = 0; i < n_tokens; i++)
2712 {
2713 PosToken *t = &tokens[i];
2714
2715 if (n_exprs >= MAX_EXPRS32)
2716 {
2717 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2718 META_THEME_ERROR_FAILED,
2719 _("Coordinate expression parser overflowed its buffer.")((char *) g_dgettext ("marco", "Coordinate expression parser overflowed its buffer."
))
);
2720 return FALSE(0);
2721 }
2722
2723 if (paren_level == 0)
2724 {
2725 switch (t->type)
2726 {
2727 case POS_TOKEN_INT:
2728 exprs[n_exprs].type = POS_EXPR_INT;
2729 exprs[n_exprs].d.int_val = t->d.i.val;
2730 ++n_exprs;
2731 break;
2732
2733 case POS_TOKEN_DOUBLE:
2734 exprs[n_exprs].type = POS_EXPR_DOUBLE;
2735 exprs[n_exprs].d.double_val = t->d.d.val;
2736 ++n_exprs;
2737 break;
2738
2739 case POS_TOKEN_OPEN_PAREN:
2740 ++paren_level;
2741 if (paren_level == 1)
2742 first_paren = i;
2743 break;
2744
2745 case POS_TOKEN_CLOSE_PAREN:
2746 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2747 META_THEME_ERROR_BAD_PARENS,
2748 _("Coordinate expression had a close parenthesis with no open parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had a close parenthesis with no open parenthesis"
))
);
2749 return FALSE(0);
2750
2751 case POS_TOKEN_VARIABLE:
2752 exprs[n_exprs].type = POS_EXPR_INT;
2753
2754 /* FIXME we should just dump all this crap
2755 * in a hash, maybe keep width/height out
2756 * for optimization purposes
2757 */
2758 if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err))
2759 return FALSE(0);
2760
2761 ++n_exprs;
2762 break;
2763
2764 case POS_TOKEN_OPERATOR:
2765 exprs[n_exprs].type = POS_EXPR_OPERATOR;
2766 exprs[n_exprs].d.operator = t->d.o.op;
2767 ++n_exprs;
2768 break;
2769 }
2770 }
2771 else
2772 {
2773 g_assert (paren_level > 0)do { if (paren_level > 0) ; else g_assertion_message_expr (
"marco", "ui/theme.c", 2773, ((const char*) (__func__)), "paren_level > 0"
); } while (0)
;
2774
2775 switch (t->type)
2776 {
2777 case POS_TOKEN_INT:
2778 case POS_TOKEN_DOUBLE:
2779 case POS_TOKEN_VARIABLE:
2780 case POS_TOKEN_OPERATOR:
2781 break;
2782
2783 case POS_TOKEN_OPEN_PAREN:
2784 ++paren_level;
2785 break;
2786
2787 case POS_TOKEN_CLOSE_PAREN:
2788 if (paren_level == 1)
2789 {
2790 /* We closed a toplevel paren group, so recurse */
2791 if (!pos_eval_helper (&tokens[first_paren+1],
2792 i - first_paren - 1,
2793 env,
2794 &exprs[n_exprs],
2795 err))
2796 return FALSE(0);
2797
2798 ++n_exprs;
2799 }
2800
2801 --paren_level;
2802 break;
2803
2804 }
2805 }
2806 }
2807
2808 if (paren_level > 0)
2809 {
2810 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2811 META_THEME_ERROR_BAD_PARENS,
2812 _("Coordinate expression had an open parenthesis with no close parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had an open parenthesis with no close parenthesis"
))
);
2813 return FALSE(0);
2814 }
2815
2816 /* Now we have no parens and no vars; so we just do all the multiplies
2817 * and divides, then all the add and subtract.
2818 */
2819 if (n_exprs == 0)
2820 {
2821 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2822 META_THEME_ERROR_FAILED,
2823 _("Coordinate expression doesn't seem to have any operators or operands")((char *) g_dgettext ("marco", "Coordinate expression doesn't seem to have any operators or operands"
))
);
2824 return FALSE(0);
2825 }
2826
2827 /* precedence 1 ops */
2828 precedence = 2;
2829 while (precedence >= 0)
2830 {
2831 if (!do_operations (exprs, &n_exprs, precedence, err))
2832 return FALSE(0);
2833 --precedence;
2834 }
2835
2836 g_assert (n_exprs == 1)do { if (n_exprs == 1) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2836, ((const char*) (__func__)), "n_exprs == 1"
); } while (0)
;
2837
2838 *result = *exprs;
2839
2840 return TRUE(!(0));
2841}
2842
2843/*
2844 * expr = int | double | expr * expr | expr / expr |
2845 * expr + expr | expr - expr | (expr)
2846 *
2847 * so very not worth fooling with bison, yet so very painful by hand.
2848 */
2849/**
2850 * Evaluates an expression.
2851 *
2852 * \param spec The expression to evaluate.
2853 * \param env The environment context to evaluate the expression in.
2854 * \param[out] val_p The integer value of the expression; if the expression
2855 * is of type float, this will be rounded. If we return
2856 * FALSE because the expression is invalid, this will be
2857 * zero.
2858 * \param[out] err The error, if anything went wrong.
2859 *
2860 * \return True if we evaluated the expression successfully; false otherwise.
2861 *
2862 * \bug Shouldn't spec be const?
2863 * \ingroup parser
2864 */
2865static gboolean
2866pos_eval (MetaDrawSpec *spec,
2867 const MetaPositionExprEnv *env,
2868 int *val_p,
2869 GError **err)
2870{
2871 PosExpr expr;
2872
2873 *val_p = 0;
2874
2875 if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err))
2876 {
2877 switch (expr.type)
2878 {
2879 case POS_EXPR_INT:
2880 *val_p = expr.d.int_val;
2881 break;
2882 case POS_EXPR_DOUBLE:
2883 *val_p = (int) expr.d.double_val;
2884 break;
2885 case POS_EXPR_OPERATOR:
2886 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2886, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2887 break;
2888 }
2889 return TRUE(!(0));
2890 }
2891 else
2892 {
2893 return FALSE(0);
2894 }
2895}
2896
2897/* We always return both X and Y, but only one will be meaningful in
2898 * most contexts.
2899 */
2900
2901gboolean
2902meta_parse_position_expression (MetaDrawSpec *spec,
2903 const MetaPositionExprEnv *env,
2904 int *x_return,
2905 int *y_return,
2906 GError **err)
2907{
2908 /* All positions are in a coordinate system with x, y at the origin.
2909 * The expression can have -, +, *, / as operators, floating point
2910 * or integer constants, and the variables "width" and "height" and
2911 * optionally "object_width" and object_height". Negative numbers
2912 * aren't allowed.
2913 */
2914 int val;
2915
2916 if (spec->constant)
2917 val = spec->value;
2918 else
2919 {
2920 if (!pos_eval (spec, env, &spec->value, err))
2921 {
2922 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2922, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2923 return FALSE(0);
2924 }
2925
2926 val = spec->value;
2927 }
2928
2929 if (x_return)
2930 *x_return = env->rect.x + val;
2931 if (y_return)
2932 *y_return = env->rect.y + val;
2933
2934 return TRUE(!(0));
2935}
2936
2937gboolean
2938meta_parse_size_expression (MetaDrawSpec *spec,
2939 const MetaPositionExprEnv *env,
2940 int *val_return,
2941 GError **err)
2942{
2943 int val;
2944
2945 if (spec->constant)
2946 val = spec->value;
2947 else
2948 {
2949 if (!pos_eval (spec, env, &spec->value, err))
2950 {
2951 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2951, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2952 return FALSE(0);
2953 }
2954
2955 val = spec->value;
2956 }
2957
2958 if (val_return)
2959 *val_return = MAX (val, 1)(((val) > (1)) ? (val) : (1)); /* require that sizes be at least 1x1 */
2960
2961 return TRUE(!(0));
2962}
2963
2964/* To do this we tokenize, replace variable tokens
2965 * that are constants, then reassemble. The purpose
2966 * here is to optimize expressions so we don't do hash
2967 * lookups to eval them. Obviously it's a tradeoff that
2968 * slows down theme load times.
2969 */
2970gboolean
2971meta_theme_replace_constants (MetaTheme *theme,
2972 PosToken *tokens,
2973 int n_tokens,
2974 GError **err)
2975{
2976 int i;
2977 double dval;
2978 int ival;
2979 gboolean is_constant = TRUE(!(0));
2980
2981 /* Loop through tokenized string looking for variables to replace */
2982 for (i = 0; i < n_tokens; i++)
2983 {
2984 PosToken *t = &tokens[i];
2985
2986 if (t->type == POS_TOKEN_VARIABLE)
2987 {
2988 if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival))
2989 {
2990 g_free (t->d.v.name);
2991 t->type = POS_TOKEN_INT;
2992 t->d.i.val = ival;
2993 }
2994 else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval))
2995 {
2996 g_free (t->d.v.name);
2997 t->type = POS_TOKEN_DOUBLE;
2998 t->d.d.val = dval;
2999 }
3000 else
3001 {
3002 /* If we've found a variable that cannot be replaced then the
3003 expression is not a constant expression and we want to
3004 replace it with a GQuark */
3005
3006 t->d.v.name_quark = g_quark_from_string (t->d.v.name);
3007 is_constant = FALSE(0);
3008 }
3009 }
3010 }
3011
3012 return is_constant;
3013}
3014
3015static int
3016parse_x_position_unchecked (MetaDrawSpec *spec,
3017 const MetaPositionExprEnv *env)
3018{
3019 int retval;
3020 GError *error;
3021
3022 retval = 0;
3023 error = NULL((void*)0);
3024 if (!meta_parse_position_expression (spec, env, &retval, NULL((void*)0), &error))
3025 {
3026 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3027 error->message);
3028
3029 g_error_free (error);
3030 }
3031
3032 return retval;
3033}
3034
3035static int
3036parse_y_position_unchecked (MetaDrawSpec *spec,
3037 const MetaPositionExprEnv *env)
3038{
3039 int retval;
3040 GError *error;
3041
3042 retval = 0;
3043 error = NULL((void*)0);
3044 if (!meta_parse_position_expression (spec, env, NULL((void*)0), &retval, &error))
3045 {
3046 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3047 error->message);
3048
3049 g_error_free (error);
3050 }
3051
3052 return retval;
3053}
3054
3055static int
3056parse_size_unchecked (MetaDrawSpec *spec,
3057 MetaPositionExprEnv *env)
3058{
3059 int retval;
3060 GError *error;
3061
3062 retval = 0;
3063 error = NULL((void*)0);
3064 if (!meta_parse_size_expression (spec, env, &retval, &error))
3065 {
3066 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3067 error->message);
3068
3069 g_error_free (error);
3070 }
3071
3072 return retval;
3073}
3074
3075void
3076meta_draw_spec_free (MetaDrawSpec *spec)
3077{
3078 if (!spec) return;
3079 free_tokens (spec->tokens, spec->n_tokens);
3080 g_slice_free (MetaDrawSpec, spec)do { if (1) g_slice_free1 (sizeof (MetaDrawSpec), (spec)); else
(void) ((MetaDrawSpec*) 0 == (spec)); } while (0)
;
3081}
3082
3083MetaDrawSpec *
3084meta_draw_spec_new (MetaTheme *theme,
3085 const char *expr,
3086 GError **error)
3087{
3088 MetaDrawSpec *spec;
3089
3090 spec = g_slice_new0 (MetaDrawSpec)((MetaDrawSpec*) g_slice_alloc0 (sizeof (MetaDrawSpec)));
3091
3092 pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL((void*)0));
3093
3094 spec->constant = meta_theme_replace_constants (theme, spec->tokens,
3095 spec->n_tokens, NULL((void*)0));
3096 if (spec->constant)
3097 {
3098 if (!pos_eval (spec, NULL((void*)0), &spec->value, error))
3099 {
3100 meta_draw_spec_free (spec);
3101 return NULL((void*)0);
3102 }
3103 }
3104
3105 return spec;
3106}
3107
3108MetaDrawOp*
3109meta_draw_op_new (MetaDrawType type)
3110{
3111 MetaDrawOp *op;
3112 MetaDrawOp dummy;
3113 int size;
3114
3115 size = G_STRUCT_OFFSET (MetaDrawOp, data)((glong) __builtin_offsetof(MetaDrawOp, data));
3116
3117 switch (type)
3118 {
3119 case META_DRAW_LINE:
3120 size += sizeof (dummy.data.line);
3121 break;
3122
3123 case META_DRAW_RECTANGLE:
3124 size += sizeof (dummy.data.rectangle);
3125 break;
3126
3127 case META_DRAW_ARC:
3128 size += sizeof (dummy.data.arc);
3129 break;
3130
3131 case META_DRAW_CLIP:
3132 size += sizeof (dummy.data.clip);
3133 break;
3134
3135 case META_DRAW_TINT:
3136 size += sizeof (dummy.data.tint);
3137 break;
3138
3139 case META_DRAW_GRADIENT:
3140 size += sizeof (dummy.data.gradient);
3141 break;
3142
3143 case META_DRAW_IMAGE:
3144 size += sizeof (dummy.data.image);
3145 break;
3146
3147 case META_DRAW_GTK_ARROW:
3148 size += sizeof (dummy.data.gtk_arrow);
3149 break;
3150
3151 case META_DRAW_GTK_BOX:
3152 size += sizeof (dummy.data.gtk_box);
3153 break;
3154
3155 case META_DRAW_GTK_VLINE:
3156 size += sizeof (dummy.data.gtk_vline);
3157 break;
3158
3159 case META_DRAW_ICON:
3160 size += sizeof (dummy.data.icon);
3161 break;
3162
3163 case META_DRAW_TITLE:
3164 size += sizeof (dummy.data.title);
3165 break;
3166 case META_DRAW_OP_LIST:
3167 size += sizeof (dummy.data.op_list);
3168 break;
3169 case META_DRAW_TILE:
3170 size += sizeof (dummy.data.tile);
3171 break;
3172 }
3173
3174 op = g_malloc0 (size);
3175
3176 op->type = type;
3177
3178 return op;
3179}
3180
3181void
3182meta_draw_op_free (MetaDrawOp *op)
3183{
3184 g_return_if_fail (op != NULL)do { if ((op != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op != NULL"); return;
} } while (0)
;
3185
3186 switch (op->type)
3187 {
3188 case META_DRAW_LINE:
3189 if (op->data.line.color_spec)
3190 meta_color_spec_free (op->data.line.color_spec);
3191
3192 meta_draw_spec_free (op->data.line.x1);
3193 meta_draw_spec_free (op->data.line.y1);
3194 meta_draw_spec_free (op->data.line.x2);
3195 meta_draw_spec_free (op->data.line.y2);
3196 break;
3197
3198 case META_DRAW_RECTANGLE:
3199 if (op->data.rectangle.color_spec)
3200 g_free (op->data.rectangle.color_spec);
3201
3202 meta_draw_spec_free (op->data.rectangle.x);
3203 meta_draw_spec_free (op->data.rectangle.y);
3204 meta_draw_spec_free (op->data.rectangle.width);
3205 meta_draw_spec_free (op->data.rectangle.height);
3206 break;
3207
3208 case META_DRAW_ARC:
3209 if (op->data.arc.color_spec)
3210 g_free (op->data.arc.color_spec);
3211
3212 meta_draw_spec_free (op->data.arc.x);
3213 meta_draw_spec_free (op->data.arc.y);
3214 meta_draw_spec_free (op->data.arc.width);
3215 meta_draw_spec_free (op->data.arc.height);
3216 break;
3217
3218 case META_DRAW_CLIP:
3219 meta_draw_spec_free (op->data.clip.x);
3220 meta_draw_spec_free (op->data.clip.y);
3221 meta_draw_spec_free (op->data.clip.width);
3222 meta_draw_spec_free (op->data.clip.height);
3223 break;
3224
3225 case META_DRAW_TINT:
3226 if (op->data.tint.color_spec)
3227 meta_color_spec_free (op->data.tint.color_spec);
3228
3229 if (op->data.tint.alpha_spec)
3230 meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
3231
3232 meta_draw_spec_free (op->data.tint.x);
3233 meta_draw_spec_free (op->data.tint.y);
3234 meta_draw_spec_free (op->data.tint.width);
3235 meta_draw_spec_free (op->data.tint.height);
3236 break;
3237
3238 case META_DRAW_GRADIENT:
3239 if (op->data.gradient.gradient_spec)
3240 meta_gradient_spec_free (op->data.gradient.gradient_spec);
3241
3242 if (op->data.gradient.alpha_spec)
3243 meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
3244
3245 meta_draw_spec_free (op->data.gradient.x);
3246 meta_draw_spec_free (op->data.gradient.y);
3247 meta_draw_spec_free (op->data.gradient.width);
3248 meta_draw_spec_free (op->data.gradient.height);
3249 break;
3250
3251 case META_DRAW_IMAGE:
3252 if (op->data.image.alpha_spec)
3253 meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
3254
3255 if (op->data.image.pixbuf)
3256 g_object_unref (G_OBJECT (op->data.image.pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.pixbuf)), (((GType) ((20) << (2)
)))))))
);
3257
3258 if (op->data.image.colorize_spec)
3259 meta_color_spec_free (op->data.image.colorize_spec);
3260
3261 if (op->data.image.colorize_cache_pixbuf)
3262 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3263
3264 meta_draw_spec_free (op->data.image.x);
3265 meta_draw_spec_free (op->data.image.y);
3266 meta_draw_spec_free (op->data.image.width);
3267 meta_draw_spec_free (op->data.image.height);
3268 break;
3269
3270 case META_DRAW_GTK_ARROW:
3271 meta_draw_spec_free (op->data.gtk_arrow.x);
3272 meta_draw_spec_free (op->data.gtk_arrow.y);
3273 meta_draw_spec_free (op->data.gtk_arrow.width);
3274 meta_draw_spec_free (op->data.gtk_arrow.height);
3275 break;
3276
3277 case META_DRAW_GTK_BOX:
3278 meta_draw_spec_free (op->data.gtk_box.x);
3279 meta_draw_spec_free (op->data.gtk_box.y);
3280 meta_draw_spec_free (op->data.gtk_box.width);
3281 meta_draw_spec_free (op->data.gtk_box.height);
3282 break;
3283
3284 case META_DRAW_GTK_VLINE:
3285 meta_draw_spec_free (op->data.gtk_vline.x);
3286 meta_draw_spec_free (op->data.gtk_vline.y1);
3287 meta_draw_spec_free (op->data.gtk_vline.y2);
3288 break;
3289
3290 case META_DRAW_ICON:
3291 if (op->data.icon.alpha_spec)
3292 meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
3293
3294 meta_draw_spec_free (op->data.icon.x);
3295 meta_draw_spec_free (op->data.icon.y);
3296 meta_draw_spec_free (op->data.icon.width);
3297 meta_draw_spec_free (op->data.icon.height);
3298 break;
3299
3300 case META_DRAW_TITLE:
3301 if (op->data.title.color_spec)
3302 meta_color_spec_free (op->data.title.color_spec);
3303
3304 meta_draw_spec_free (op->data.title.x);
3305 meta_draw_spec_free (op->data.title.y);
3306 if (op->data.title.ellipsize_width)
3307 meta_draw_spec_free (op->data.title.ellipsize_width);
3308 break;
3309
3310 case META_DRAW_OP_LIST:
3311 if (op->data.op_list.op_list)
3312 meta_draw_op_list_unref (op->data.op_list.op_list);
3313
3314 meta_draw_spec_free (op->data.op_list.x);
3315 meta_draw_spec_free (op->data.op_list.y);
3316 meta_draw_spec_free (op->data.op_list.width);
3317 meta_draw_spec_free (op->data.op_list.height);
3318 break;
3319
3320 case META_DRAW_TILE:
3321 if (op->data.tile.op_list)
3322 meta_draw_op_list_unref (op->data.tile.op_list);
3323
3324 meta_draw_spec_free (op->data.tile.x);
3325 meta_draw_spec_free (op->data.tile.y);
3326 meta_draw_spec_free (op->data.tile.width);
3327 meta_draw_spec_free (op->data.tile.height);
3328 meta_draw_spec_free (op->data.tile.tile_xoffset);
3329 meta_draw_spec_free (op->data.tile.tile_yoffset);
3330 meta_draw_spec_free (op->data.tile.tile_width);
3331 meta_draw_spec_free (op->data.tile.tile_height);
3332 break;
3333 }
3334
3335 g_free (op);
3336}
3337
3338static GdkPixbuf*
3339apply_alpha (GdkPixbuf *pixbuf,
3340 MetaAlphaGradientSpec *spec,
3341 gboolean force_copy)
3342{
3343 GdkPixbuf *new_pixbuf;
3344 gboolean needs_alpha;
3345
3346 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return (((void*)0)); } } while
(0)
;
3347
3348 needs_alpha = spec && (spec->n_alphas > 1 ||
3349 spec->alphas[0] != 0xff);
3350
3351 if (!needs_alpha)
3352 return pixbuf;
3353
3354 if (!gdk_pixbuf_get_has_alpha (pixbuf))
3355 {
3356 new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE(0), 0, 0, 0);
3357 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3358 pixbuf = new_pixbuf;
3359 }
3360 else if (force_copy)
3361 {
3362 new_pixbuf = gdk_pixbuf_copy (pixbuf);
3363 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3364 pixbuf = new_pixbuf;
3365 }
3366
3367 g_assert (gdk_pixbuf_get_has_alpha (pixbuf))do { if (gdk_pixbuf_get_has_alpha (pixbuf)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 3367, ((const char*) (__func__)), "gdk_pixbuf_get_has_alpha (pixbuf)"
); } while (0)
;
3368
3369 meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
3370
3371 return pixbuf;
3372}
3373
3374static GdkPixbuf*
3375pixbuf_tile (GdkPixbuf *tile,
3376 int width,
3377 int height)
3378{
3379 GdkPixbuf *pixbuf;
3380 int tile_width;
3381 int tile_height;
3382 int i, j;
3383
3384 tile_width = gdk_pixbuf_get_width (tile);
3385 tile_height = gdk_pixbuf_get_height (tile);
3386
3387 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3388 gdk_pixbuf_get_has_alpha (tile),
3389 8, width, height);
3390
3391 i = 0;
3392 while (i < width)
3393 {
3394 j = 0;
3395 while (j < height)
3396 {
3397 int w, h;
3398
3399 w = MIN (tile_width, width - i)(((tile_width) < (width - i)) ? (tile_width) : (width - i)
)
;
3400 h = MIN (tile_height, height - j)(((tile_height) < (height - j)) ? (tile_height) : (height -
j))
;
3401
3402 gdk_pixbuf_copy_area (tile,
3403 0, 0,
3404 w, h,
3405 pixbuf,
3406 i, j);
3407
3408 j += tile_height;
3409 }
3410
3411 i += tile_width;
3412 }
3413
3414 return pixbuf;
3415}
3416
3417static GdkPixbuf *
3418replicate_rows (GdkPixbuf *src,
3419 int src_x,
3420 int src_y,
3421 int width,
3422 int height)
3423{
3424 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3425 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3426 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3427 * n_channels);
3428 unsigned char *dest_pixels;
3429 GdkPixbuf *result;
3430 unsigned int dest_rowstride;
3431 int i;
3432
3433 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3434 width, height);
3435 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3436 dest_pixels = gdk_pixbuf_get_pixels (result);
3437
3438 for (i = 0; i < height; i++)
3439 memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
3440
3441 return result;
3442}
3443
3444static GdkPixbuf *
3445replicate_cols (GdkPixbuf *src,
3446 int src_x,
3447 int src_y,
3448 int width,
3449 int height)
3450{
3451 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3452 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3453 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3454 * n_channels);
3455 unsigned char *dest_pixels;
3456 GdkPixbuf *result;
3457 unsigned int dest_rowstride;
3458 int i, j;
3459
3460 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3461 width, height);
3462 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3463 dest_pixels = gdk_pixbuf_get_pixels (result);
3464
3465 for (i = 0; i < height; i++)
3466 {
3467 unsigned char *p = dest_pixels + dest_rowstride * i;
3468 unsigned char *q = pixels + src_rowstride * i;
3469
3470 unsigned char r = *(q++);
3471 unsigned char g = *(q++);
3472 unsigned char b = *(q++);
3473
3474 if (n_channels == 4)
3475 {
3476 unsigned char a;
3477
3478 a = *(q++);
3479
3480 for (j = 0; j < width; j++)
3481 {
3482 *(p++) = r;
3483 *(p++) = g;
3484 *(p++) = b;
3485 *(p++) = a;
3486 }
3487 }
3488 else
3489 {
3490 for (j = 0; j < width; j++)
3491 {
3492 *(p++) = r;
3493 *(p++) = g;
3494 *(p++) = b;
3495 }
3496 }
3497 }
3498
3499 return result;
3500}
3501
3502static GdkPixbuf*
3503scale_and_alpha_pixbuf (GdkPixbuf *src,
3504 MetaAlphaGradientSpec *alpha_spec,
3505 MetaImageFillType fill_type,
3506 int width,
3507 int height,
3508 gboolean vertical_stripes,
3509 gboolean horizontal_stripes)
3510{
3511 GdkPixbuf *pixbuf;
3512 GdkPixbuf *temp_pixbuf;
3513
3514 pixbuf = NULL((void*)0);
3515
3516 pixbuf = src;
3517
3518 if (gdk_pixbuf_get_width (pixbuf) == width &&
3519 gdk_pixbuf_get_height (pixbuf) == height)
3520 {
3521 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
3522 }
3523 else
3524 {
3525 if (fill_type == META_IMAGE_FILL_TILE)
3526 {
3527 pixbuf = pixbuf_tile (pixbuf, width, height);
3528 }
3529 else
3530 {
3531 int src_h, src_w, dest_h, dest_w;
3532 src_h = gdk_pixbuf_get_height (src);
3533 src_w = gdk_pixbuf_get_width (src);
3534
3535 /* prefer to replicate_cols if possible, as that
3536 * is faster (no memory reads)
3537 */
3538 if (horizontal_stripes)
3539 {
3540 dest_w = gdk_pixbuf_get_width (src);
3541 dest_h = height;
3542 }
3543 else if (vertical_stripes)
3544 {
3545 dest_w = width;
3546 dest_h = gdk_pixbuf_get_height (src);
3547 }
3548
3549 else
3550 {
3551 dest_w = width;
3552 dest_h = height;
3553 }
3554
3555 if (dest_w == src_w && dest_h == src_h)
3556 {
3557 temp_pixbuf = src;
3558 g_object_ref (G_OBJECT (temp_pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2)))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2))))))))))
;
3559 }
3560 else
3561 {
3562 temp_pixbuf = gdk_pixbuf_scale_simple (src,
3563 dest_w, dest_h,
3564 GDK_INTERP_BILINEAR);
3565 }
3566
3567 /* prefer to replicate_cols if possible, as that
3568 * is faster (no memory reads)
3569 */
3570 if (horizontal_stripes)
3571 {
3572 pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
3573 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3574 }
3575 else if (vertical_stripes)
3576 {
3577 pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
3578 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3579 }
3580 else
3581 {
3582 pixbuf = temp_pixbuf;
3583 }
3584 }
3585 }
3586
3587 if (pixbuf)
3588 pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
3589
3590 return pixbuf;
3591}
3592
3593static GdkPixbuf*
3594draw_op_as_pixbuf (const MetaDrawOp *op,
3595 GtkStyleContext *style,
3596 const MetaDrawInfo *info,
3597 int width,
3598 int height)
3599{
3600 /* Try to get the op as a pixbuf, assuming w/h in the op
3601 * matches the width/height passed in. return NULL
3602 * if the op can't be converted to an equivalent pixbuf.
3603 */
3604 GdkPixbuf *pixbuf;
3605
3606 pixbuf = NULL((void*)0);
3607
3608 switch (op->type)
3609 {
3610 case META_DRAW_LINE:
3611 break;
3612
3613 case META_DRAW_RECTANGLE:
3614 if (op->data.rectangle.filled)
3615 {
3616 GdkRGBA color;
3617
3618 meta_color_spec_render (op->data.rectangle.color_spec,
3619 style,
3620 &color);
3621
3622 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3623 FALSE(0),
3624 8, width, height);
3625
3626 gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
);
3627 }
3628 break;
3629
3630 case META_DRAW_ARC:
3631 break;
3632
3633 case META_DRAW_CLIP:
3634 break;
3635
3636 case META_DRAW_TINT:
3637 {
3638 GdkRGBA color;
3639 guint32 rgba;
3640 gboolean has_alpha;
3641
3642 meta_color_spec_render (op->data.rectangle.color_spec,
3643 style,
3644 &color);
3645
3646 has_alpha =
3647 op->data.tint.alpha_spec &&
3648 (op->data.tint.alpha_spec->n_alphas > 1 ||
3649 op->data.tint.alpha_spec->alphas[0] != 0xff);
3650
3651 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3652 has_alpha,
3653 8, width, height);
3654
3655 if (!has_alpha)
3656 {
3657 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3658
3659 gdk_pixbuf_fill (pixbuf, rgba);
3660 }
3661 else if (op->data.tint.alpha_spec->n_alphas == 1)
3662 {
3663 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3664 rgba &= ~0xff;
3665 rgba |= op->data.tint.alpha_spec->alphas[0];
3666
3667 gdk_pixbuf_fill (pixbuf, rgba);
3668 }
3669 else
3670 {
3671 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3672
3673 gdk_pixbuf_fill (pixbuf, rgba);
3674
3675 meta_gradient_add_alpha (pixbuf,
3676 op->data.tint.alpha_spec->alphas,
3677 op->data.tint.alpha_spec->n_alphas,
3678 op->data.tint.alpha_spec->type);
3679 }
3680 }
3681 break;
3682
3683 case META_DRAW_IMAGE:
3684 {
3685 if (op->data.image.colorize_spec)
3686 {
3687 GdkRGBA color;
3688
3689 meta_color_spec_render (op->data.image.colorize_spec,
3690 style, &color);
3691
3692 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3693 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3694 {
3695 if (op->data.image.colorize_cache_pixbuf)
3696 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3697
3698 /* const cast here */
3699 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3700 colorize_pixbuf (op->data.image.pixbuf,
3701 &color);
3702 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3703 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3704 }
3705
3706 if (op->data.image.colorize_cache_pixbuf)
3707 {
3708 pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
3709 op->data.image.alpha_spec,
3710 op->data.image.fill_type,
3711 width, height,
3712 op->data.image.vertical_stripes,
3713 op->data.image.horizontal_stripes);
3714 }
3715 }
3716 else
3717 {
3718 pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
3719 op->data.image.alpha_spec,
3720 op->data.image.fill_type,
3721 width, height,
3722 op->data.image.vertical_stripes,
3723 op->data.image.horizontal_stripes);
3724 }
3725 break;
3726 }
3727
3728 case META_DRAW_GRADIENT:
3729 case META_DRAW_GTK_ARROW:
3730 case META_DRAW_GTK_BOX:
3731 case META_DRAW_GTK_VLINE:
3732 break;
3733
3734 case META_DRAW_ICON:
3735 if (info->mini_icon &&
3736 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3737 height <= gdk_pixbuf_get_height (info->mini_icon))
3738 pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
3739 op->data.icon.alpha_spec,
3740 op->data.icon.fill_type,
3741 width, height,
3742 FALSE(0), FALSE(0));
3743 else if (info->icon)
3744 pixbuf = scale_and_alpha_pixbuf (info->icon,
3745 op->data.icon.alpha_spec,
3746 op->data.icon.fill_type,
3747 width, height,
3748 FALSE(0), FALSE(0));
3749 break;
3750
3751 case META_DRAW_TITLE:
3752 break;
3753
3754 case META_DRAW_OP_LIST:
3755 break;
3756
3757 case META_DRAW_TILE:
3758 break;
3759 }
3760
3761 return pixbuf;
3762}
3763
3764static cairo_surface_t *
3765draw_op_as_surface (const MetaDrawOp *op,
3766 GtkStyleContext *style,
3767 const MetaDrawInfo *info,
3768 gdouble width,
3769 gdouble height)
3770{
3771 cairo_surface_t *surface;
3772
3773 surface = NULL((void*)0);
3774
3775 switch (op->type)
3776 {
3777 case META_DRAW_IMAGE:
3778 {
3779 if (op->data.image.colorize_spec)
3780 {
3781 GdkRGBA color;
3782
3783 meta_color_spec_render (op->data.image.colorize_spec,
3784 style, &color);
3785
3786 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3787 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3788 {
3789 if (op->data.image.colorize_cache_pixbuf)
3790 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3791
3792 /* const cast here */
3793 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3794 colorize_pixbuf (op->data.image.pixbuf,
3795 &color);
3796 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3797 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3798 }
3799
3800 if (op->data.image.colorize_cache_pixbuf)
3801 {
3802 surface = get_surface_from_pixbuf (op->data.image.colorize_cache_pixbuf,
3803 op->data.image.fill_type,
3804 width, height,
3805 op->data.image.vertical_stripes,
3806 op->data.image.horizontal_stripes);
3807 }
3808 }
3809 else
3810 {
3811 surface = get_surface_from_pixbuf (op->data.image.pixbuf,
3812 op->data.image.fill_type,
3813 width, height,
3814 op->data.image.vertical_stripes,
3815 op->data.image.horizontal_stripes);
3816 }
3817 break;
3818 }
3819
3820 case META_DRAW_ICON:
3821 if (info->mini_icon &&
3822 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3823 height <= gdk_pixbuf_get_height (info->mini_icon))
3824 surface = get_surface_from_pixbuf (info->mini_icon, op->data.icon.fill_type,
3825 width, height, FALSE(0), FALSE(0));
3826 else if (info->icon)
3827 surface = get_surface_from_pixbuf (info->icon, op->data.icon.fill_type,
3828 width, height, FALSE(0), FALSE(0));
3829 break;
3830
3831 case META_DRAW_TINT:
3832 case META_DRAW_LINE:
3833 case META_DRAW_RECTANGLE:
3834 case META_DRAW_ARC:
3835 case META_DRAW_CLIP:
3836 case META_DRAW_GRADIENT:
3837 case META_DRAW_GTK_ARROW:
3838 case META_DRAW_GTK_BOX:
3839 case META_DRAW_GTK_VLINE:
3840 case META_DRAW_TITLE:
3841 case META_DRAW_OP_LIST:
3842 case META_DRAW_TILE:
3843 break;
3844
3845 default:
3846 break;
3847 }
3848
3849 return surface;
3850}
3851
3852static void
3853fill_env (MetaPositionExprEnv *env,
3854 const MetaDrawInfo *info,
3855 MetaRectangle logical_region)
3856{
3857 /* FIXME this stuff could be raised into draw_op_list_draw() probably
3858 */
3859 env->rect = logical_region;
3860 env->object_width = -1;
3861 env->object_height = -1;
3862 if (info->fgeom)
3863 {
3864 env->left_width = info->fgeom->borders.visible.left;
3865 env->right_width = info->fgeom->borders.visible.right;
3866 env->top_height = info->fgeom->borders.visible.top;
3867 env->bottom_height = info->fgeom->borders.visible.bottom;
3868 env->frame_x_center = info->fgeom->width / 2 - logical_region.x;
3869 env->frame_y_center = info->fgeom->height / 2 - logical_region.y;
3870 }
3871 else
3872 {
3873 env->left_width = 0;
3874 env->right_width = 0;
3875 env->top_height = 0;
3876 env->bottom_height = 0;
3877 env->frame_x_center = 0;
3878 env->frame_y_center = 0;
3879 }
3880
3881 env->mini_icon_width = info->mini_icon ? gdk_pixbuf_get_width (info->mini_icon) : 0;
3882 env->mini_icon_height = info->mini_icon ? gdk_pixbuf_get_height (info->mini_icon) : 0;
3883 env->icon_width = info->icon ? gdk_pixbuf_get_width (info->icon) : 0;
3884 env->icon_height = info->icon ? gdk_pixbuf_get_height (info->icon) : 0;
3885
3886 env->title_width = info->title_layout_width;
3887 env->title_height = info->title_layout_height;
3888 env->theme = meta_current_theme;
3889}
3890
3891/* This code was originally rendering anti-aliased using X primitives, and
3892 * now has been switched to draw anti-aliased using cairo. In general, the
3893 * closest correspondence between X rendering and cairo rendering is given
3894 * by offsetting the geometry by 0.5 pixels in both directions before rendering
3895 * with cairo. This is because X samples at the upper left corner of the
3896 * pixel while cairo averages over the entire pixel. However, in the cases
3897 * where the X rendering was an exact rectangle with no "jaggies"
3898 * we need to be a bit careful about applying the offset. We want to produce
3899 * the exact same pixel-aligned rectangle, rather than a rectangle with
3900 * fuzz around the edges.
3901 */
3902static void
3903meta_draw_op_draw_with_env (const MetaDrawOp *op,
3904 GtkStyleContext *style_gtk,
3905 cairo_t *cr,
3906 const MetaDrawInfo *info,
3907 MetaRectangle rect,
3908 MetaPositionExprEnv *env)
3909{
3910 GdkRGBA color;
3911
3912 cairo_save (cr);
3913 gtk_style_context_save (style_gtk);
3914
3915 cairo_set_line_width (cr, 1.0);
3916
3917 switch (op->type)
3918 {
3919 case META_DRAW_LINE:
3920 {
3921 int x1, x2, y1, y2;
3922
3923 meta_color_spec_render (op->data.line.color_spec, style_gtk, &color);
3924 gdk_cairo_set_source_rgba (cr, &color);
3925
3926 if (op->data.line.width > 0)
3927 cairo_set_line_width (cr, op->data.line.width);
3928
3929 if (op->data.line.dash_on_length > 0 &&
3930 op->data.line.dash_off_length > 0)
3931 {
3932 double dash_list[2];
3933 dash_list[0] = op->data.line.dash_on_length;
3934 dash_list[1] = op->data.line.dash_off_length;
3935 cairo_set_dash (cr, dash_list, 2, 0);
3936 }
3937
3938 x1 = parse_x_position_unchecked (op->data.line.x1, env);
3939 y1 = parse_y_position_unchecked (op->data.line.y1, env);
3940
3941 if (!op->data.line.x2 &&
3942 !op->data.line.y2 &&
3943 op->data.line.width==0)
3944 {
3945 cairo_rectangle (cr, x1, y1, 1, 1);
3946 cairo_fill (cr);
3947 }
3948 else
3949 {
3950 if (op->data.line.x2)
3951 x2 = parse_x_position_unchecked (op->data.line.x2, env);
3952 else
3953 x2 = x1;
3954
3955 if (op->data.line.y2)
3956 y2 = parse_y_position_unchecked (op->data.line.y2, env);
3957 else
3958 y2 = y1;
3959
3960 /* This is one of the cases where we are matching the exact
3961 * pixel aligned rectangle produced by X; for zero-width lines
3962 * the generic algorithm produces the right result so we don't
3963 * need to handle them here.
3964 */
3965 if ((y1 == y2 || x1 == x2) && op->data.line.width != 0)
3966 {
3967 double offset = op->data.line.width % 2 ? .5 : 0;
3968
3969 if (y1 == y2)
3970 {
3971 cairo_move_to (cr, x1, y1 + offset);
3972 cairo_line_to (cr, x2, y2 + offset);
3973 }
3974 else
3975 {
3976 cairo_move_to (cr, x1 + offset, y1);
3977 cairo_line_to (cr, x2 + offset, y2);
3978 }
3979 }
3980 else
3981 {
3982 /* zero-width lines include both end-points in X, unlike wide lines */
3983 if (op->data.line.width == 0)
3984 cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
3985
3986 cairo_move_to (cr, x1 + .5, y1 + .5);
3987 cairo_line_to (cr, x2 + .5, y2 + .5);
3988 }
3989 cairo_stroke (cr);
3990 }
3991 }
3992 break;
3993
3994 case META_DRAW_RECTANGLE:
3995 {
3996 int rx, ry, rwidth, rheight;
3997
3998 meta_color_spec_render (op->data.rectangle.color_spec, style_gtk, &color);
3999 gdk_cairo_set_source_rgba (cr, &color);
4000
4001 rx = parse_x_position_unchecked (op->data.rectangle.x, env);
4002 ry = parse_y_position_unchecked (op->data.rectangle.y, env);
4003 rwidth = parse_size_unchecked (op->data.rectangle.width, env);
4004 rheight = parse_size_unchecked (op->data.rectangle.height, env);
4005
4006 /* Filled and stroked rectangles are the other cases
4007 * we pixel-align to X rasterization
4008 */
4009 if (op->data.rectangle.filled)
4010 {
4011 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4012 cairo_fill (cr);
4013 }
4014 else
4015 {
4016 cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight);
4017 cairo_stroke (cr);
4018 }
4019 }
4020 break;
4021
4022 case META_DRAW_ARC:
4023 {
4024 int rx, ry, rwidth, rheight;
4025 double start_angle, end_angle;
4026 double center_x, center_y;
4027
4028 meta_color_spec_render (op->data.arc.color_spec, style_gtk, &color);
4029 gdk_cairo_set_source_rgba (cr, &color);
4030
4031 rx = parse_x_position_unchecked (op->data.arc.x, env);
4032 ry = parse_y_position_unchecked (op->data.arc.y, env);
4033 rwidth = parse_size_unchecked (op->data.arc.width, env);
4034 rheight = parse_size_unchecked (op->data.arc.height, env);
4035
4036 start_angle = op->data.arc.start_angle * (M_PI3.14159265358979323846 / 180.)
4037 - (.5 * M_PI3.14159265358979323846); /* start at 12 instead of 3 oclock */
4038 end_angle = start_angle + op->data.arc.extent_angle * (M_PI3.14159265358979323846 / 180.);
4039 center_x = rx + (double)rwidth / 2. + .5;
4040 center_y = ry + (double)rheight / 2. + .5;
4041
4042 cairo_save (cr);
4043
4044 cairo_translate (cr, center_x, center_y);
4045 cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.);
4046
4047 if (op->data.arc.extent_angle >= 0)
4048 cairo_arc (cr, 0, 0, 1, start_angle, end_angle);
4049 else
4050 cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle);
4051
4052 cairo_restore (cr);
4053
4054 if (op->data.arc.filled)
4055 {
4056 cairo_line_to (cr, center_x, center_y);
4057 cairo_fill (cr);
4058 }
4059 else
4060 cairo_stroke (cr);
4061 }
4062 break;
4063
4064 case META_DRAW_CLIP:
4065 break;
4066
4067 case META_DRAW_TINT:
4068 {
4069 int rx, ry, rwidth, rheight;
4070 gboolean needs_alpha;
4071
4072 needs_alpha = op->data.tint.alpha_spec &&
4073 (op->data.tint.alpha_spec->n_alphas > 1 ||
4074 op->data.tint.alpha_spec->alphas[0] != 0xff);
4075
4076 rx = parse_x_position_unchecked (op->data.tint.x, env);
4077 ry = parse_y_position_unchecked (op->data.tint.y, env);
4078 rwidth = parse_size_unchecked (op->data.tint.width, env);
4079 rheight = parse_size_unchecked (op->data.tint.height, env);
4080
4081 if (!needs_alpha)
4082 {
4083 meta_color_spec_render (op->data.tint.color_spec, style_gtk, &color);
4084 gdk_cairo_set_source_rgba (cr, &color);
4085
4086 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4087 cairo_fill (cr);
4088 }
4089 else
4090 {
4091 GdkPixbuf *pixbuf;
4092
4093 pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
4094 rwidth, rheight);
4095
4096 if (pixbuf)
4097 {
4098 gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
4099 cairo_paint (cr);
4100
4101 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
4102 }
4103 }
4104 }
4105 break;
4106
4107 case META_DRAW_GRADIENT:
4108 {
4109 int rx, ry, rwidth, rheight;
4110
4111 rx = parse_x_position_unchecked (op->data.gradient.x, env);
4112 ry = parse_y_position_unchecked (op->data.gradient.y, env);
4113 rwidth = parse_size_unchecked (op->data.gradient.width, env);
4114 rheight = parse_size_unchecked (op->data.gradient.height, env);
4115
4116 meta_gradient_spec_render (op->data.gradient.gradient_spec,
4117 op->data.gradient.alpha_spec,
4118 cr, style_gtk, rx, ry, rwidth, rheight);
4119 }
4120 break;
4121
4122 case META_DRAW_IMAGE:
4123 {
4124 gint scale;
4125 gdouble rx, ry, rwidth, rheight;
4126 cairo_surface_t *surface;
4127
4128 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4129 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4130
4131 if (op->data.image.pixbuf)
4132 {
4133 env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf) / scale;
4134 env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf) / scale;
4135 }
4136
4137 rwidth = parse_size_unchecked (op->data.image.width, env) * scale;
4138 rheight = parse_size_unchecked (op->data.image.height, env) * scale;
4139
4140 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4141
4142 if (surface)
4143 {
4144 rx = parse_x_position_unchecked (op->data.image.x, env) * scale;
4145 ry = parse_y_position_unchecked (op->data.image.y, env) * scale;
4146
4147 cairo_set_source_surface (cr, surface, rx, ry);
4148
4149 if (op->data.image.alpha_spec)
4150 {
4151 cairo_pattern_t *pattern;
4152
4153 cairo_translate (cr, rx, ry);
4154 cairo_scale (cr, rwidth, rheight);
4155
4156 pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec);
4157 cairo_mask (cr, pattern);
4158
4159 cairo_pattern_destroy (pattern);
4160 }
4161 else
4162 {
4163 cairo_paint (cr);
4164 }
4165
4166 cairo_surface_destroy (surface);
4167 }
4168 }
4169 break;
4170
4171 case META_DRAW_GTK_ARROW:
4172 {
4173 int rx, ry, rwidth, rheight;
4174
4175 rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
4176 ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
4177 rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
4178 rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
4179
4180 double size = MAX(rwidth, rheight)(((rwidth) > (rheight)) ? (rwidth) : (rheight)), angle = 0;
4181
4182 switch (op->data.gtk_arrow.arrow)
4183 {
4184 case GTK_ARROW_UP:
4185 angle = 0;
4186 break;
4187 case GTK_ARROW_RIGHT:
4188 angle = M_PI3.14159265358979323846 / 2;
4189 break;
4190 case GTK_ARROW_DOWN:
4191 angle = M_PI3.14159265358979323846;
4192 break;
4193 case GTK_ARROW_LEFT:
4194 angle = 3 * M_PI3.14159265358979323846 / 2;
4195 break;
4196 case GTK_ARROW_NONE:
4197 return;
4198 }
4199
4200 gtk_style_context_set_state (style_gtk, op->data.gtk_arrow.state);
4201 gtk_render_arrow (style_gtk, cr, angle, rx, ry, size);
4202 }
4203 break;
4204
4205 case META_DRAW_GTK_BOX:
4206 {
4207 int rx, ry, rwidth, rheight;
4208
4209 rx = parse_x_position_unchecked (op->data.gtk_box.x, env);
4210 ry = parse_y_position_unchecked (op->data.gtk_box.y, env);
4211 rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
4212 rheight = parse_size_unchecked (op->data.gtk_box.height, env);
4213
4214 gtk_style_context_set_state (style_gtk, op->data.gtk_box.state);
4215 gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight);
4216 gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight);
4217 }
4218 break;
4219
4220 case META_DRAW_GTK_VLINE:
4221 {
4222 int rx, ry1, ry2;
4223
4224 rx = parse_x_position_unchecked (op->data.gtk_vline.x, env);
4225 ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
4226 ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
4227
4228 gtk_style_context_set_state (style_gtk, op->data.gtk_vline.state);
4229 gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2);
4230 }
4231 break;
4232
4233 case META_DRAW_ICON:
4234 {
4235 gint scale;
4236 gdouble rx, ry, rwidth, rheight;
4237 cairo_surface_t *surface;
4238
4239 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4240 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4241
4242 rwidth = parse_size_unchecked (op->data.icon.width, env) * scale;
4243 rheight = parse_size_unchecked (op->data.icon.height, env) * scale;
4244
4245 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4246
4247 if (surface)
4248 {
4249 rx = parse_x_position_unchecked (op->data.icon.x, env) * scale;
4250 ry = parse_y_position_unchecked (op->data.icon.y, env) * scale;
4251
4252 cairo_set_source_surface (cr, surface, rx, ry);
4253
4254 if (op->data.icon.alpha_spec)
4255 {
4256 cairo_pattern_t *pattern;
4257
4258 cairo_translate (cr, rx, ry);
4259 cairo_scale (cr, rwidth, rheight);
4260
4261 pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec);
4262 cairo_mask (cr, pattern);
4263
4264 cairo_pattern_destroy (pattern);
4265 }
4266 else
4267 {
4268 cairo_paint (cr);
4269 }
4270
4271 cairo_surface_destroy (surface);
4272 }
4273 }
4274 break;
4275
4276 case META_DRAW_TITLE:
4277 if (info->title_layout)
4278 {
4279 int rx, ry;
4280 PangoRectangle ink_rect, logical_rect;
4281
4282 meta_color_spec_render (op->data.title.color_spec, style_gtk, &color);
4283 gdk_cairo_set_source_rgba (cr, &color);
4284
4285 rx = parse_x_position_unchecked (op->data.title.x, env);
4286 ry = parse_y_position_unchecked (op->data.title.y, env);
4287
4288 if (op->data.title.ellipsize_width)
4289 {
4290 int ellipsize_width;
4291 int right_bearing;
4292
4293 ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env);
4294 /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */
4295 ellipsize_width -= env->rect.x;
4296
4297 pango_layout_set_width (info->title_layout, -1);
4298 pango_layout_get_pixel_extents (info->title_layout,
4299 &ink_rect, &logical_rect);
4300
4301 /* Pango's idea of ellipsization is with respect to the logical rect.
4302 * correct for this, by reducing the ellipsization width by the overflow
4303 * of the un-ellipsized text on the right... it's always the visual
4304 * right we want regardless of bidi, since since the X we pass in to
4305 * cairo_move_to() is always the left edge of the line.
4306 */
4307 right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width);
4308 right_bearing = MAX (right_bearing, 0)(((right_bearing) > (0)) ? (right_bearing) : (0));
4309
4310 ellipsize_width -= right_bearing;
4311 ellipsize_width = MAX (ellipsize_width, 0)(((ellipsize_width) > (0)) ? (ellipsize_width) : (0));
4312
4313 /* Only ellipsizing when necessary is a performance optimization -
4314 * pango_layout_set_width() will force a relayout if it isn't the
4315 * same as the current width of -1.
4316 */
4317 if (ellipsize_width < logical_rect.width)
4318 pango_layout_set_width (info->title_layout, PANGO_SCALE1024 * ellipsize_width);
4319 }
4320 else if (rx - env->rect.x + env->title_width >= env->rect.width)
4321 {
4322 const double alpha_margin = 30.0;
4323 int text_space = env->rect.x + env->rect.width -
4324 (rx - env->rect.x) - env->right_width;
4325
4326 double startalpha = 1.0 - (alpha_margin/((double)text_space));
4327
4328 cairo_pattern_t *linpat;
4329 linpat = cairo_pattern_create_linear (rx, ry, text_space,
4330 env->title_height);
4331 cairo_pattern_add_color_stop_rgba (linpat, 0, color.red,
4332 color.green,
4333 color.blue,
4334 color.alpha);
4335 cairo_pattern_add_color_stop_rgba (linpat, startalpha,
4336 color.red,
4337 color.green,
4338 color.blue,
4339 color.alpha);
4340 cairo_pattern_add_color_stop_rgba (linpat, 1, color.red,
4341 color.green,
4342 color.blue, 0);
4343 cairo_set_source(cr, linpat);
4344 cairo_pattern_destroy(linpat);
4345 }
4346
4347 cairo_move_to (cr, rx, ry);
4348 pango_cairo_show_layout (cr, info->title_layout);
4349
4350 /* Remove any ellipsization we might have set; will short-circuit
4351 * if the width is already -1 */
4352 pango_layout_set_width (info->title_layout, -1);
4353 }
4354 break;
4355
4356 case META_DRAW_OP_LIST:
4357 {
4358 MetaRectangle d_rect;
4359
4360 d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env);
4361 d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env);
4362 d_rect.width = parse_size_unchecked (op->data.op_list.width, env);
4363 d_rect.height = parse_size_unchecked (op->data.op_list.height, env);
4364
4365 meta_draw_op_list_draw_with_style (op->data.op_list.op_list,
4366 style_gtk,
4367 cr,
4368 info, d_rect);
4369 }
4370 break;
4371
4372 case META_DRAW_TILE:
4373 {
4374 int rx, ry, rwidth, rheight;
4375 int tile_xoffset, tile_yoffset;
4376 MetaRectangle tile;
4377
4378 rx = parse_x_position_unchecked (op->data.tile.x, env);
4379 ry = parse_y_position_unchecked (op->data.tile.y, env);
4380 rwidth = parse_size_unchecked (op->data.tile.width, env);
4381 rheight = parse_size_unchecked (op->data.tile.height, env);
4382
4383 cairo_save (cr);
4384
4385 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4386 cairo_clip (cr);
4387
4388 tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env);
4389 tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env);
4390 /* tile offset should not include x/y */
4391 tile_xoffset -= rect.x;
4392 tile_yoffset -= rect.y;
4393
4394 tile.width = parse_size_unchecked (op->data.tile.tile_width, env);
4395 tile.height = parse_size_unchecked (op->data.tile.tile_height, env);
4396
4397 tile.x = rx - tile_xoffset;
4398
4399 while (tile.x < (rx + rwidth))
4400 {
4401 tile.y = ry - tile_yoffset;
4402 while (tile.y < (ry + rheight))
4403 {
4404 meta_draw_op_list_draw_with_style (op->data.tile.op_list,
4405 style_gtk, cr, info,
4406 tile);
4407
4408 tile.y += tile.height;
4409 }
4410
4411 tile.x += tile.width;
4412 }
4413 cairo_restore (cr);
4414 }
4415 break;
4416 }
4417
4418 cairo_restore (cr);
4419 gtk_style_context_restore (style_gtk);
4420}
4421
4422void
4423meta_draw_op_draw_with_style (const MetaDrawOp *op,
4424 GtkStyleContext *style_gtk,
4425 cairo_t *cr,
4426 const MetaDrawInfo *info,
4427 MetaRectangle logical_region)
4428{
4429 MetaPositionExprEnv env;
4430
4431 fill_env (&env, info, logical_region);
4432
4433 meta_draw_op_draw_with_env (op,
4434 style_gtk,
4435 cr,
4436 info, logical_region,
4437 &env);
4438
4439}
4440
4441void
4442meta_draw_op_draw (const MetaDrawOp *op,
4443 GtkWidget *widget,
4444 cairo_t *cr,
4445 const MetaDrawInfo *info,
4446 MetaRectangle logical_region)
4447{
4448 meta_draw_op_draw_with_style (op,
4449 gtk_widget_get_style_context (widget),
4450 cr,
4451 info, logical_region);
4452}
4453
4454MetaDrawOpList*
4455meta_draw_op_list_new (int n_preallocs)
4456{
4457 MetaDrawOpList *op_list;
4458
4459 g_return_val_if_fail (n_preallocs >= 0, NULL)do { if ((n_preallocs >= 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_preallocs >= 0")
; return (((void*)0)); } } while (0)
;
4460
4461 op_list = g_new (MetaDrawOpList, 1)((MetaDrawOpList *) g_malloc_n ((1), sizeof (MetaDrawOpList))
)
;
4462
4463 op_list->refcount = 1;
4464 op_list->n_allocated = n_preallocs;
4465 op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated)((MetaDrawOp* *) g_malloc_n ((op_list->n_allocated), sizeof
(MetaDrawOp*)))
;
4466 op_list->n_ops = 0;
4467
4468 return op_list;
4469}
4470
4471void
4472meta_draw_op_list_ref (MetaDrawOpList *op_list)
4473{
4474 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4475
4476 op_list->refcount += 1;
4477}
4478
4479void
4480meta_draw_op_list_unref (MetaDrawOpList *op_list)
4481{
4482 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4483 g_return_if_fail (op_list->refcount > 0)do { if ((op_list->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list->refcount > 0"
); return; } } while (0)
;
4484
4485 op_list->refcount -= 1;
4486
4487 if (op_list->refcount == 0)
4488 {
4489 int i;
4490
4491 for (i = 0; i < op_list->n_ops; i++)
4492 meta_draw_op_free (op_list->ops[i]);
4493
4494 g_free (op_list->ops);
4495
4496 DEBUG_FILL_STRUCT (op_list)memset ((op_list), 0xef, sizeof (*(op_list)));
4497 g_free (op_list);
4498 }
4499}
4500
4501void
4502meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
4503 GtkStyleContext *style_gtk,
4504 cairo_t *cr,
4505 const MetaDrawInfo *info,
4506 MetaRectangle rect)
4507{
4508 /* BOOKMARK */
4509
4510 int i;
4511 MetaPositionExprEnv env;
4512
4513 if (op_list->n_ops == 0)
4514 return;
4515
4516 fill_env (&env, info, rect);
4517
4518 /* FIXME this can be optimized, potentially a lot, by
4519 * compressing multiple ops when possible. For example,
4520 * anything convertible to a pixbuf can be composited
4521 * client-side, and putting a color tint over a pixbuf
4522 * can be done without creating the solid-color pixbuf.
4523 *
4524 * To implement this my plan is to have the idea of a
4525 * compiled draw op (with the string expressions already
4526 * evaluated), we make an array of those, and then fold
4527 * adjacent items when possible.
4528 */
4529
4530 cairo_save (cr);
4531
4532 for (i = 0; i < op_list->n_ops; i++)
4533 {
4534 MetaDrawOp *op = op_list->ops[i];
4535
4536 if (op->type == META_DRAW_CLIP)
4537 {
4538 cairo_restore (cr);
4539
4540 cairo_rectangle (cr,
4541 parse_x_position_unchecked (op->data.clip.x, &env),
4542 parse_y_position_unchecked (op->data.clip.y, &env),
4543 parse_size_unchecked (op->data.clip.width, &env),
4544 parse_size_unchecked (op->data.clip.height, &env));
4545 cairo_clip (cr);
4546
4547 cairo_save (cr);
4548 }
4549 else if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
4550 {
4551 meta_draw_op_draw_with_env (op, style_gtk, cr, info, rect, &env);
4552 }
4553 }
4554
4555 cairo_restore (cr);
4556}
4557
4558void
4559meta_draw_op_list_draw (const MetaDrawOpList *op_list,
4560 GtkWidget *widget,
4561 cairo_t *cr,
4562 const MetaDrawInfo *info,
4563 MetaRectangle rect)
4564
4565{
4566 meta_draw_op_list_draw_with_style (op_list,
4567 gtk_widget_get_style_context (widget),
4568 cr,
4569 info, rect);
4570}
4571
4572void
4573meta_draw_op_list_append (MetaDrawOpList *op_list,
4574 MetaDrawOp *op)
4575{
4576 if (op_list->n_ops == op_list->n_allocated)
4577 {
4578 op_list->n_allocated *= 2;
4579 op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated)((MetaDrawOp* *) g_realloc_n (op_list->ops, (op_list->n_allocated
), sizeof (MetaDrawOp*)))
;
4580 }
4581
4582 op_list->ops[op_list->n_ops] = op;
4583 op_list->n_ops += 1;
4584}
4585
4586gboolean
4587meta_draw_op_list_validate (MetaDrawOpList *op_list,
4588 GError **error)
4589{
4590 g_return_val_if_fail (op_list != NULL, FALSE)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
((0)); } } while (0)
;
4591
4592 /* empty lists are OK, nothing else to check really */
4593
4594 return TRUE(!(0));
4595}
4596
4597/* This is not done in validate, since we wouldn't know the name
4598 * of the list to report the error. It might be nice to
4599 * store names inside the list sometime.
4600 */
4601gboolean
4602meta_draw_op_list_contains (MetaDrawOpList *op_list,
4603 MetaDrawOpList *child)
4604{
4605 int i;
4606
4607 /* mmm, huge tree recursion */
4608
4609 for (i = 0; i < op_list->n_ops; i++)
4610 {
4611 if (op_list->ops[i]->type == META_DRAW_OP_LIST)
4612 {
4613 if (op_list->ops[i]->data.op_list.op_list == child)
4614 return TRUE(!(0));
4615
4616 if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list,
4617 child))
4618 return TRUE(!(0));
4619 }
4620 else if (op_list->ops[i]->type == META_DRAW_TILE)
4621 {
4622 if (op_list->ops[i]->data.tile.op_list == child)
4623 return TRUE(!(0));
4624
4625 if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list,
4626 child))
4627 return TRUE(!(0));
4628 }
4629 }
4630
4631 return FALSE(0);
4632}
4633
4634/**
4635 * Constructor for a MetaFrameStyle.
4636 *
4637 * \param parent The parent style. Data not filled in here will be
4638 * looked for in the parent style, and in its parent
4639 * style, and so on.
4640 *
4641 * \return The newly-constructed style.
4642 */
4643MetaFrameStyle*
4644meta_frame_style_new (MetaFrameStyle *parent)
4645{
4646 MetaFrameStyle *style;
4647
4648 style = g_new0 (MetaFrameStyle, 1)((MetaFrameStyle *) g_malloc0_n ((1), sizeof (MetaFrameStyle)
))
;
4649
4650 style->refcount = 1;
4651
4652 /* Default alpha is fully opaque */
4653 style->window_background_alpha = 255;
4654
4655 style->parent = parent;
4656 if (parent)
4657 meta_frame_style_ref (parent);
4658
4659 return style;
4660}
4661
4662/**
4663 * Increases the reference count of a frame style.
4664 * If the style is NULL, this is a no-op.
4665 *
4666 * \param style The style.
4667 */
4668void
4669meta_frame_style_ref (MetaFrameStyle *style)
4670{
4671 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4672
4673 style->refcount += 1;
4674}
4675
4676static void
4677free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
4678{
4679 int i, j;
4680
4681 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4682 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4683 if (op_lists[i][j])
4684 meta_draw_op_list_unref (op_lists[i][j]);
4685}
4686
4687void
4688meta_frame_style_unref (MetaFrameStyle *style)
4689{
4690 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4691 g_return_if_fail (style->refcount > 0)do { if ((style->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->refcount > 0"
); return; } } while (0)
;
4692
4693 style->refcount -= 1;
4694
4695 if (style->refcount == 0)
4696 {
4697 int i;
4698
4699 free_button_ops (style->buttons);
4700
4701 for (i = 0; i < META_FRAME_PIECE_LAST; i++)
4702 if (style->pieces[i])
4703 meta_draw_op_list_unref (style->pieces[i]);
4704
4705 if (style->layout)
4706 meta_frame_layout_unref (style->layout);
4707
4708 if (style->window_background_color)
4709 meta_color_spec_free (style->window_background_color);
4710
4711 /* we hold a reference to any parent style */
4712 if (style->parent)
4713 meta_frame_style_unref (style->parent);
4714
4715 DEBUG_FILL_STRUCT (style)memset ((style), 0xef, sizeof (*(style)));
4716 g_free (style);
4717 }
4718}
4719
4720static MetaButtonState
4721map_button_state (MetaButtonType button_type,
4722 const MetaFrameGeometry *fgeom,
4723 int middle_bg_offset,
4724 MetaButtonState button_states[META_BUTTON_TYPE_LAST])
4725{
4726 MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
4727
4728 switch (button_type)
4729 {
4730 /* First handle functions, which map directly */
4731 case META_BUTTON_TYPE_SHADE:
4732 case META_BUTTON_TYPE_ABOVE:
4733 case META_BUTTON_TYPE_STICK:
4734 case META_BUTTON_TYPE_UNSHADE:
4735 case META_BUTTON_TYPE_UNABOVE:
4736 case META_BUTTON_TYPE_UNSTICK:
4737 case META_BUTTON_TYPE_MENU:
4738 case META_BUTTON_TYPE_APPMENU:
4739 case META_BUTTON_TYPE_MINIMIZE:
4740 case META_BUTTON_TYPE_MAXIMIZE:
4741 case META_BUTTON_TYPE_CLOSE:
4742 return button_states[button_type];
4743
4744 /* Map position buttons to the corresponding function */
4745 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4746 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4747 if (fgeom->n_right_buttons > 0)
4748 function = fgeom->button_layout.right_buttons[0];
4749 break;
4750 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4751 if (fgeom->n_right_buttons > 0)
4752 function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
4753 break;
4754 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4755 if (middle_bg_offset + 1 < fgeom->n_right_buttons)
4756 function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
4757 break;
4758 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4759 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4760 if (fgeom->n_left_buttons > 0)
4761 function = fgeom->button_layout.left_buttons[0];
4762 break;
4763 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4764 if (fgeom->n_left_buttons > 0)
4765 function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
4766 break;
4767 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4768 if (middle_bg_offset + 1 < fgeom->n_left_buttons)
4769 function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
4770 break;
4771 case META_BUTTON_TYPE_LAST:
4772 break;
4773 }
4774
4775 if (function != META_BUTTON_FUNCTION_LAST)
4776 return button_states[map_button_function_to_type (function)];
4777
4778 return META_BUTTON_STATE_LAST;
4779}
4780
4781static MetaDrawOpList*
4782get_button (MetaFrameStyle *style,
4783 MetaButtonType type,
4784 MetaButtonState state)
4785{
4786 MetaDrawOpList *op_list;
4787 MetaFrameStyle *parent;
4788
4789 parent = style;
4790 op_list = NULL((void*)0);
4791 while (parent && op_list == NULL((void*)0))
4792 {
4793 op_list = parent->buttons[type][state];
4794 parent = parent->parent;
4795 }
4796
4797 /* We fall back to the side buttons if we don't have
4798 * single button backgrounds, and to middle button
4799 * backgrounds if we don't have the ones on the sides
4800 */
4801
4802 if (op_list == NULL((void*)0) &&
4803 type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND)
4804 return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state);
4805
4806 if (op_list == NULL((void*)0) &&
4807 type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND)
4808 return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state);
4809
4810 if (op_list == NULL((void*)0) &&
4811 (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
4812 type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
4813 return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
4814 state);
4815
4816 if (op_list == NULL((void*)0) &&
4817 (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND ||
4818 type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND))
4819 return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
4820 state);
4821
4822 /* We fall back to normal if no prelight */
4823 if (op_list == NULL((void*)0) &&
4824 state == META_BUTTON_STATE_PRELIGHT)
4825 return get_button (style, type, META_BUTTON_STATE_NORMAL);
4826
4827 return op_list;
4828}
4829
4830gboolean
4831meta_frame_style_validate (MetaFrameStyle *style,
4832 guint current_theme_version,
4833 GError **error)
4834{
4835 int i, j;
4836
4837 g_return_val_if_fail (style != NULL, FALSE)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
((0)); } } while (0)
;
4838 g_return_val_if_fail (style->layout != NULL, FALSE)do { if ((style->layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->layout != NULL"
); return ((0)); } } while (0)
;
4839
4840 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4841 {
4842 /* for now the "positional" buttons are optional */
4843 if (i >= META_BUTTON_TYPE_CLOSE)
4844 {
4845 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4846 {
4847 if (get_button (style, i, j) == NULL((void*)0) &&
4848 meta_theme_earliest_version_with_button (i) <= current_theme_version
4849 )
4850 {
4851 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
4852 META_THEME_ERROR_FAILED,
4853 _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style")((char *) g_dgettext ("marco", "<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"
))
,
4854 meta_button_type_to_string (i),
4855 meta_button_state_to_string (j));
4856 return FALSE(0);
4857 }
4858 }
4859 }
4860 }
4861
4862 return TRUE(!(0));
4863}
4864
4865static void
4866get_button_rect (MetaButtonType type,
4867 const MetaFrameGeometry *fgeom,
4868 int middle_background_offset,
4869 GdkRectangle *rect)
4870{
4871 switch (type)
4872 {
4873 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4874 *rect = fgeom->left_left_background;
4875 break;
4876
4877 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4878 *rect = fgeom->left_middle_backgrounds[middle_background_offset];
4879 break;
4880
4881 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4882 *rect = fgeom->left_right_background;
4883 break;
4884
4885 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4886 *rect = fgeom->left_single_background;
4887 break;
4888
4889 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4890 *rect = fgeom->right_left_background;
4891 break;
4892
4893 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4894 *rect = fgeom->right_middle_backgrounds[middle_background_offset];
4895 break;
4896
4897 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4898 *rect = fgeom->right_right_background;
4899 break;
4900
4901 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4902 *rect = fgeom->right_single_background;
4903 break;
4904
4905 case META_BUTTON_TYPE_CLOSE:
4906 *rect = fgeom->close_rect.visible;
4907 break;
4908
4909 case META_BUTTON_TYPE_SHADE:
4910 *rect = fgeom->shade_rect.visible;
4911 break;
4912
4913 case META_BUTTON_TYPE_UNSHADE:
4914 *rect = fgeom->unshade_rect.visible;
4915 break;
4916
4917 case META_BUTTON_TYPE_ABOVE:
4918 *rect = fgeom->above_rect.visible;
4919 break;
4920
4921 case META_BUTTON_TYPE_UNABOVE:
4922 *rect = fgeom->unabove_rect.visible;
4923 break;
4924
4925 case META_BUTTON_TYPE_STICK:
4926 *rect = fgeom->stick_rect.visible;
4927 break;
4928
4929 case META_BUTTON_TYPE_UNSTICK:
4930 *rect = fgeom->unstick_rect.visible;
4931 break;
4932
4933 case META_BUTTON_TYPE_MAXIMIZE:
4934 *rect = fgeom->max_rect.visible;
4935 break;
4936
4937 case META_BUTTON_TYPE_MINIMIZE:
4938 *rect = fgeom->min_rect.visible;
4939 break;
4940
4941 case META_BUTTON_TYPE_MENU:
4942 *rect = fgeom->menu_rect.visible;
4943 break;
4944
4945 case META_BUTTON_TYPE_APPMENU:
4946 *rect = fgeom->appmenu_rect.visible;
4947 break;
4948
4949 case META_BUTTON_TYPE_LAST:
4950 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 4950, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
4951 break;
4952 }
4953}
4954
4955void
4956meta_frame_style_draw_with_style (MetaFrameStyle *style,
4957 GtkStyleContext *style_gtk,
4958 cairo_t *cr,
4959 const MetaFrameGeometry *fgeom,
4960 int client_width,
4961 int client_height,
4962 PangoLayout *title_layout,
4963 int text_height,
4964 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
4965 GdkPixbuf *mini_icon,
4966 GdkPixbuf *icon)
4967{
4968 /* BOOKMARK */
4969 int i, j;
4970 GdkRectangle visible_rect;
4971 GdkRectangle titlebar_rect;
4972 GdkRectangle left_titlebar_edge;
4973 GdkRectangle right_titlebar_edge;
4974 GdkRectangle bottom_titlebar_edge;
4975 GdkRectangle top_titlebar_edge;
4976 GdkRectangle left_edge, right_edge, bottom_edge;
4977 PangoRectangle extents;
4978 MetaDrawInfo draw_info;
4979 const MetaFrameBorders *borders;
4980
4981 borders = &fgeom->borders;
4982
4983 visible_rect.x = borders->invisible.left;
4984 visible_rect.y = borders->invisible.top;
4985 visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
4986 visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
4987
4988 titlebar_rect.x = visible_rect.x;
4989 titlebar_rect.y = visible_rect.y;
4990 titlebar_rect.width = visible_rect.width;
4991 titlebar_rect.height = borders->visible.top;
4992
4993 left_titlebar_edge.x = titlebar_rect.x;
4994 left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
4995 left_titlebar_edge.width = fgeom->left_titlebar_edge;
4996 left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
4997
4998 right_titlebar_edge.y = left_titlebar_edge.y;
4999 right_titlebar_edge.height = left_titlebar_edge.height;
5000 right_titlebar_edge.width = fgeom->right_titlebar_edge;
5001 right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
5002
5003 top_titlebar_edge.x = titlebar_rect.x;
5004 top_titlebar_edge.y = titlebar_rect.y;
5005 top_titlebar_edge.width = titlebar_rect.width;
5006 top_titlebar_edge.height = fgeom->top_titlebar_edge;
5007
5008 bottom_titlebar_edge.x = titlebar_rect.x;
5009 bottom_titlebar_edge.width = titlebar_rect.width;
5010 bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
5011 bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
5012
5013 left_edge.x = visible_rect.x;
5014 left_edge.y = visible_rect.y + borders->visible.top;
5015 left_edge.width = borders->visible.left;
5016 left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5017
5018 right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
5019 right_edge.y = visible_rect.y + borders->visible.top;
5020 right_edge.width = borders->visible.right;
5021 right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5022
5023 bottom_edge.x = visible_rect.x;
5024 bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
5025 bottom_edge.width = visible_rect.width;
5026 bottom_edge.height = borders->visible.bottom;
5027
5028 if (title_layout)
5029 pango_layout_get_pixel_extents (title_layout,
5030 NULL((void*)0), &extents);
5031
5032 draw_info.mini_icon = mini_icon;
5033 draw_info.icon = icon;
5034 draw_info.title_layout = title_layout;
5035 draw_info.title_layout_width = title_layout ? extents.width : 0;
5036 draw_info.title_layout_height = title_layout ? extents.height : 0;
5037 draw_info.fgeom = fgeom;
5038
5039 /* The enum is in the order the pieces should be rendered. */
5040 i = 0;
5041 while (i < META_FRAME_PIECE_LAST)
5042 {
5043 GdkRectangle rect;
5044
5045 switch ((MetaFramePiece) i)
5046 {
5047 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
5048 rect = visible_rect;
5049 break;
5050
5051 case META_FRAME_PIECE_TITLEBAR:
5052 rect = titlebar_rect;
5053 break;
5054
5055 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
5056 rect = left_titlebar_edge;
5057 break;
5058
5059 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
5060 rect = right_titlebar_edge;
5061 break;
5062
5063 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
5064 rect = top_titlebar_edge;
5065 break;
5066
5067 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
5068 rect = bottom_titlebar_edge;
5069 break;
5070
5071 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
5072 rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
5073 rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
5074 rect.width = titlebar_rect.width - left_titlebar_edge.width -
5075 right_titlebar_edge.width;
5076 rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
5077 break;
5078
5079 case META_FRAME_PIECE_TITLE:
5080 rect = fgeom->title_rect;
5081 break;
5082
5083 case META_FRAME_PIECE_LEFT_EDGE:
5084 rect = left_edge;
5085 break;
5086
5087 case META_FRAME_PIECE_RIGHT_EDGE:
5088 rect = right_edge;
5089 break;
5090
5091 case META_FRAME_PIECE_BOTTOM_EDGE:
5092 rect = bottom_edge;
5093 break;
5094
5095 case META_FRAME_PIECE_OVERLAY:
5096 rect = visible_rect;
5097 break;
5098
5099 case META_FRAME_PIECE_LAST:
5100 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5100, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5101 break;
5102 }
5103
5104 cairo_save (cr);
5105
5106 gdk_cairo_rectangle (cr, &rect);
5107 cairo_clip (cr);
5108
5109 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5110 {
5111 MetaDrawOpList *op_list;
5112 MetaFrameStyle *parent;
5113
5114 parent = style;
5115 op_list = NULL((void*)0);
5116 while (parent && op_list == NULL((void*)0))
5117 {
5118 op_list = parent->pieces[i];
5119 parent = parent->parent;
5120 }
5121
5122 if (op_list)
5123 {
5124 MetaRectangle m_rect;
5125 m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
5126 meta_draw_op_list_draw_with_style (op_list,
5127 style_gtk,
5128 cr,
5129 &draw_info,
5130 m_rect);
5131 }
5132 }
5133
5134 cairo_restore (cr);
5135
5136 /* Draw buttons just before overlay */
5137 if ((i + 1) == META_FRAME_PIECE_OVERLAY)
5138 {
5139 MetaDrawOpList *op_list;
5140 int middle_bg_offset;
5141
5142 middle_bg_offset = 0;
5143 j = 0;
5144 while (j < META_BUTTON_TYPE_LAST)
5145 {
5146 MetaButtonState button_state;
5147
5148 get_button_rect (j, fgeom, middle_bg_offset, &rect);
5149
5150 button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
5151 op_list = get_button (style, j, button_state);
5152
5153 if (op_list)
5154 {
5155 cairo_save (cr);
5156 gdk_cairo_rectangle (cr, &rect);
5157 cairo_clip (cr);
5158
5159 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5160 {
5161 MetaRectangle m_rect;
5162
5163 m_rect = meta_rect (rect.x, rect.y,
5164 rect.width, rect.height);
5165
5166 meta_draw_op_list_draw_with_style (op_list,
5167 style_gtk,
5168 cr,
5169 &draw_info,
5170 m_rect);
5171 }
5172
5173 cairo_restore (cr);
5174 }
5175
5176 /* MIDDLE_BACKGROUND type may get drawn more than once */
5177 if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
5178 j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
5179 middle_bg_offset < MAX_MIDDLE_BACKGROUNDS(META_BUTTON_FUNCTION_LAST - 2))
5180 {
5181 ++middle_bg_offset;
5182 }
5183 else
5184 {
5185 middle_bg_offset = 0;
5186 ++j;
5187 }
5188 }
5189 }
5190
5191 ++i;
5192 }
5193}
5194
5195void
5196meta_frame_style_draw (MetaFrameStyle *style,
5197 GtkWidget *widget,
5198 cairo_t *cr,
5199 const MetaFrameGeometry *fgeom,
5200 int client_width,
5201 int client_height,
5202 PangoLayout *title_layout,
5203 int text_height,
5204 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5205 GdkPixbuf *mini_icon,
5206 GdkPixbuf *icon)
5207{
5208 meta_frame_style_draw_with_style (style,
5209 gtk_widget_get_style_context (widget),
5210 cr,
5211 fgeom, client_width, client_height,
5212 title_layout, text_height,
5213 button_states, mini_icon, icon);
5214}
5215
5216MetaFrameStyleSet*
5217meta_frame_style_set_new (MetaFrameStyleSet *parent)
5218{
5219 MetaFrameStyleSet *style_set;
5220
5221 style_set = g_new0 (MetaFrameStyleSet, 1)((MetaFrameStyleSet *) g_malloc0_n ((1), sizeof (MetaFrameStyleSet
)))
;
5222
5223 style_set->parent = parent;
5224 if (parent)
5225 meta_frame_style_set_ref (parent);
5226
5227 style_set->refcount = 1;
5228
5229 return style_set;
5230}
5231
5232static void
5233free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST])
5234{
5235 int i;
5236
5237 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5238 if (focus_styles[i])
5239 meta_frame_style_unref (focus_styles[i]);
5240}
5241
5242void
5243meta_frame_style_set_ref (MetaFrameStyleSet *style_set)
5244{
5245 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5246
5247 style_set->refcount += 1;
5248}
5249
5250void
5251meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
5252{
5253 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5254 g_return_if_fail (style_set->refcount > 0)do { if ((style_set->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set->refcount > 0"
); return; } } while (0)
;
5255
5256 style_set->refcount -= 1;
5257
5258 if (style_set->refcount == 0)
5259 {
5260 int i;
5261
5262 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5263 {
5264 free_focus_styles (style_set->normal_styles[i]);
5265 free_focus_styles (style_set->shaded_styles[i]);
5266 }
5267
5268 free_focus_styles (style_set->maximized_styles);
5269 free_focus_styles (style_set->tiled_left_styles);
5270 free_focus_styles (style_set->tiled_right_styles);
5271 free_focus_styles (style_set->maximized_and_shaded_styles);
5272 free_focus_styles (style_set->tiled_left_and_shaded_styles);
5273 free_focus_styles (style_set->tiled_right_and_shaded_styles);
5274
5275 if (style_set->parent)
5276 meta_frame_style_set_unref (style_set->parent);
5277
5278 DEBUG_FILL_STRUCT (style_set)memset ((style_set), 0xef, sizeof (*(style_set)));
5279 g_free (style_set);
5280 }
5281}
5282
5283static MetaFrameStyle*
5284get_style (MetaFrameStyleSet *style_set,
5285 MetaFrameState state,
5286 MetaFrameResize resize,
5287 MetaFrameFocus focus)
5288{
5289 MetaFrameStyle *style;
5290
5291 style = NULL((void*)0);
5292
5293 switch (state)
5294 {
5295 case META_FRAME_STATE_NORMAL:
5296 case META_FRAME_STATE_SHADED:
5297 {
5298 if (state == META_FRAME_STATE_SHADED)
5299 style = style_set->shaded_styles[resize][focus];
5300 else
5301 style = style_set->normal_styles[resize][focus];
5302
5303 /* Try parent if we failed here */
5304 if (style == NULL((void*)0) && style_set->parent)
5305 style = get_style (style_set->parent, state, resize, focus);
5306
5307 /* Allow people to omit the vert/horz/none resize modes */
5308 if (style == NULL((void*)0) &&
5309 resize != META_FRAME_RESIZE_BOTH)
5310 style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
5311 }
5312 break;
5313 default:
5314 {
5315 MetaFrameStyle **styles;
5316
5317 styles = NULL((void*)0);
5318
5319 switch (state)
5320 {
5321 case META_FRAME_STATE_MAXIMIZED:
5322 styles = style_set->maximized_styles;
5323 break;
5324 case META_FRAME_STATE_TILED_LEFT:
5325 styles = style_set->tiled_left_styles;
5326 break;
5327 case META_FRAME_STATE_TILED_RIGHT:
5328 styles = style_set->tiled_right_styles;
5329 break;
5330 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
5331 styles = style_set->maximized_and_shaded_styles;
5332 break;
5333 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
5334 styles = style_set->tiled_left_and_shaded_styles;
5335 break;
5336 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
5337 styles = style_set->tiled_right_and_shaded_styles;
5338 break;
5339 case META_FRAME_STATE_NORMAL:
5340 case META_FRAME_STATE_SHADED:
5341 case META_FRAME_STATE_LAST:
5342 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5342, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5343 break;
5344 }
5345
5346 style = styles[focus];
5347
5348 /* Tiled states are optional, try falling back to non-tiled states */
5349 if (style == NULL((void*)0))
5350 {
5351 if (state == META_FRAME_STATE_TILED_LEFT ||
5352 state == META_FRAME_STATE_TILED_RIGHT)
5353 style = get_style (style_set, META_FRAME_STATE_NORMAL,
5354 resize, focus);
5355 else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED ||
5356 state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED)
5357 style = get_style (style_set, META_FRAME_STATE_SHADED,
5358 resize, focus);
5359 }
5360
5361 /* Try parent if we failed here */
5362 if (style == NULL((void*)0) && style_set->parent)
5363 style = get_style (style_set->parent, state, resize, focus);
5364 }
5365 }
5366
5367 return style;
5368}
5369
5370static gboolean
5371check_state (MetaFrameStyleSet *style_set,
5372 MetaFrameState state,
5373 GError **error)
5374{
5375 int i;
5376
5377 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5378 {
5379 if (get_style (style_set, state,
5380 META_FRAME_RESIZE_NONE, i) == NULL((void*)0))
5381 {
5382 /* Translators: This error occurs when a <frame> tag is missing
5383 * in theme XML. The "<frame ...>" is intended as a noun phrase,
5384 * and the "missing" qualifies it. You should translate "whatever".
5385 */
5386 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5387 META_THEME_ERROR_FAILED,
5388 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5389 meta_frame_state_to_string (state),
5390 meta_frame_resize_to_string (META_FRAME_RESIZE_NONE),
5391 meta_frame_focus_to_string (i));
5392 return FALSE(0);
5393 }
5394 }
5395
5396 return TRUE(!(0));
5397}
5398
5399gboolean
5400meta_frame_style_set_validate (MetaFrameStyleSet *style_set,
5401 GError **error)
5402{
5403 int i, j;
5404
5405 g_return_val_if_fail (style_set != NULL, FALSE)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
((0)); } } while (0)
;
5406
5407 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5408 for (j = 0; j < META_FRAME_FOCUS_LAST; j++)
5409 if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL((void*)0))
5410 {
5411 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5412 META_THEME_ERROR_FAILED,
5413 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5414 meta_frame_state_to_string (META_FRAME_STATE_NORMAL),
5415 meta_frame_resize_to_string (i),
5416 meta_frame_focus_to_string (j));
5417 return FALSE(0);
5418 }
5419
5420 if (!check_state (style_set, META_FRAME_STATE_SHADED, error))
5421 return FALSE(0);
5422
5423 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error))
5424 return FALSE(0);
5425
5426 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error))
5427 return FALSE(0);
5428
5429 return TRUE(!(0));
5430}
5431
5432MetaTheme*
5433meta_theme_get_current (void)
5434{
5435 return meta_current_theme;
5436}
5437
5438void
5439meta_theme_set_current (const char *name,
5440 gboolean force_reload)
5441{
5442 MetaTheme *new_theme;
5443 GError *err;
5444
5445 meta_topicmeta_topic_real (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name);
5446
5447 if (!force_reload &&
5448 meta_current_theme &&
5449 strcmp (name, meta_current_theme->name) == 0)
5450 return;
5451
5452 err = NULL((void*)0);
5453 new_theme = meta_theme_load (name, &err);
5454
5455 if (new_theme == NULL((void*)0))
5456 {
5457 meta_warning (_("Failed to load theme \"%s\": %s\n")((char *) g_dgettext ("marco", "Failed to load theme \"%s\": %s\n"
))
,
5458 name, err->message);
5459 g_error_free (err);
5460 }
5461 else
5462 {
5463 if (meta_current_theme)
5464 meta_theme_free (meta_current_theme);
5465
5466 meta_current_theme = new_theme;
5467
5468 meta_topicmeta_topic_real (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name);
5469 }
5470}
5471
5472MetaTheme*
5473meta_theme_new (void)
5474{
5475 MetaTheme *theme;
5476
5477 theme = g_new0 (MetaTheme, 1)((MetaTheme *) g_malloc0_n ((1), sizeof (MetaTheme)));
5478
5479 theme->images_by_filename =
5480 g_hash_table_new_full (g_str_hash,
5481 g_str_equal,
5482 g_free,
5483 g_object_unref);
5484
5485 theme->layouts_by_name =
5486 g_hash_table_new_full (g_str_hash,
5487 g_str_equal,
5488 g_free,
5489 (GDestroyNotify) meta_frame_layout_unref);
5490
5491 theme->draw_op_lists_by_name =
5492 g_hash_table_new_full (g_str_hash,
5493 g_str_equal,
5494 g_free,
5495 (GDestroyNotify) meta_draw_op_list_unref);
5496
5497 theme->styles_by_name =
5498 g_hash_table_new_full (g_str_hash,
5499 g_str_equal,
5500 g_free,
5501 (GDestroyNotify) meta_frame_style_unref);
5502
5503 theme->style_sets_by_name =
5504 g_hash_table_new_full (g_str_hash,
5505 g_str_equal,
5506 g_free,
5507 (GDestroyNotify) meta_frame_style_set_unref);
5508
5509 /* Create our variable quarks so we can look up variables without
5510 having to strcmp for the names */
5511 theme->quark_width = g_quark_from_static_string ("width");
5512 theme->quark_height = g_quark_from_static_string ("height");
5513 theme->quark_object_width = g_quark_from_static_string ("object_width");
5514 theme->quark_object_height = g_quark_from_static_string ("object_height");
5515 theme->quark_left_width = g_quark_from_static_string ("left_width");
5516 theme->quark_right_width = g_quark_from_static_string ("right_width");
5517 theme->quark_top_height = g_quark_from_static_string ("top_height");
5518 theme->quark_bottom_height = g_quark_from_static_string ("bottom_height");
5519 theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width");
5520 theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height");
5521 theme->quark_icon_width = g_quark_from_static_string ("icon_width");
5522 theme->quark_icon_height = g_quark_from_static_string ("icon_height");
5523 theme->quark_title_width = g_quark_from_static_string ("title_width");
5524 theme->quark_title_height = g_quark_from_static_string ("title_height");
5525 theme->quark_frame_x_center = g_quark_from_static_string ("frame_x_center");
5526 theme->quark_frame_y_center = g_quark_from_static_string ("frame_y_center");
5527 return theme;
5528}
5529
5530void
5531meta_theme_free (MetaTheme *theme)
5532{
5533 int i;
5534
5535 g_return_if_fail (theme != NULL)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
; } } while (0)
;
5536
5537 g_free (theme->name);
5538 g_free (theme->dirname);
5539 g_free (theme->filename);
5540 g_free (theme->readable_name);
5541 g_free (theme->date);
5542 g_free (theme->description);
5543 g_free (theme->author);
5544 g_free (theme->copyright);
5545
5546 /* be more careful when destroying the theme hash tables,
5547 since they are only constructed as needed, and may be NULL. */
5548 if (theme->integer_constants)
5549 g_hash_table_destroy (theme->integer_constants);
5550 if (theme->images_by_filename)
5551 g_hash_table_destroy (theme->images_by_filename);
5552 if (theme->layouts_by_name)
5553 g_hash_table_destroy (theme->layouts_by_name);
5554 if (theme->draw_op_lists_by_name)
5555 g_hash_table_destroy (theme->draw_op_lists_by_name);
5556 if (theme->styles_by_name)
5557 g_hash_table_destroy (theme->styles_by_name);
5558 if (theme->style_sets_by_name)
5559 g_hash_table_destroy (theme->style_sets_by_name);
5560
5561 for (i = 0; i < META_FRAME_TYPE_LAST; i++)
5562 if (theme->style_sets_by_type[i])
5563 meta_frame_style_set_unref (theme->style_sets_by_type[i]);
5564
5565 DEBUG_FILL_STRUCT (theme)memset ((theme), 0xef, sizeof (*(theme)));
5566 g_free (theme);
5567}
5568
5569gboolean
5570meta_theme_validate (MetaTheme *theme,
5571 GError **error)
5572{
5573 int i;
5574
5575 g_return_val_if_fail (theme != NULL, FALSE)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
((0)); } } while (0)
;
5576
5577 /* FIXME what else should be checked? */
5578
5579 g_assert (theme->name)do { if (theme->name) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 5579, ((const char*) (__func__)), "theme->name"
); } while (0)
;
5580
5581 if (theme->readable_name == NULL((void*)0))
5582 {
5583 /* Translators: This error means that a necessary XML tag (whose name
5584 * is given in angle brackets) was not found in a given theme (whose
5585 * name is given second, in quotation marks).
5586 */
5587 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5588 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "name", theme->name);
5589 return FALSE(0);
5590 }
5591
5592 if (theme->author == NULL((void*)0))
5593 {
5594 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5595 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "author", theme->name);
5596 return FALSE(0);
5597 }
5598
5599 if (theme->date == NULL((void*)0))
5600 {
5601 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5602 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "date", theme->name);
5603 return FALSE(0);
5604 }
5605
5606 if (theme->description == NULL((void*)0))
5607 {
5608 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5609 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "description", theme->name);
5610 return FALSE(0);
5611 }
5612
5613 if (theme->copyright == NULL((void*)0))
5614 {
5615 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5616 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "copyright", theme->name);
5617 return FALSE(0);
5618 }
5619
5620 for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
5621 if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL((void*)0))
5622 {
5623 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5624 _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element")((char *) g_dgettext ("marco", "No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"
))
,
5625 meta_frame_type_to_string (i),
5626 theme->name,
5627 meta_frame_type_to_string (i));
5628
5629 return FALSE(0);
5630 }
5631
5632 return TRUE(!(0));
5633}
5634
5635GdkPixbuf*
5636meta_theme_load_image (MetaTheme *theme,
5637 const char *filename,
5638 guint size_of_theme_icons,
5639 GError **error)
5640{
5641 GdkPixbuf *pixbuf;
5642 int scale;
5643
5644 pixbuf = g_hash_table_lookup (theme->images_by_filename,
5645 filename);
5646
5647 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
5648
5649 if (pixbuf == NULL((void*)0))
5650 {
5651
5652 if (g_str_has_prefix (filename, "theme:")(__builtin_constant_p ("theme:")? __extension__ ({ const char
* const __str = (filename); const char * const __prefix = ("theme:"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (filename, "theme:") )
&&
5653 META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES)(theme->format_version >= 2))
5654 {
5655 pixbuf = gtk_icon_theme_load_icon_for_scale (
5656 gtk_icon_theme_get_default (),
5657 filename+6,
5658 size_of_theme_icons,
5659 scale,
5660 0,
5661 error);
5662 if (pixbuf == NULL((void*)0)) return NULL((void*)0);
5663 }
5664 else
5665 {
5666 char *full_path;
5667 full_path = g_build_filename (theme->dirname, filename, NULL((void*)0));
5668
5669 gint width, height;
5670
5671 if (gdk_pixbuf_get_file_info (full_path, &width, &height) == NULL((void*)0))
5672 {
5673 g_free (full_path);
5674 return NULL((void*)0);
5675 }
5676
5677 width *= scale;
5678 height *= scale;
5679
5680 pixbuf = gdk_pixbuf_new_from_file_at_size (full_path, width, height, error);
5681
5682 if (pixbuf == NULL((void*)0))
5683 {
5684 g_free (full_path);
5685 return NULL((void*)0);
5686 }
5687
5688 g_free (full_path);
5689 }
5690 g_hash_table_replace (theme->images_by_filename,
5691 g_strdup (filename)g_strdup_inline (filename),
5692 pixbuf);
5693 }
5694
5695 g_assert (pixbuf)do { if (pixbuf) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 5695, ((const char*) (__func__)), "pixbuf"); } while (0)
;
5696
5697 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
5698
5699 return pixbuf;
5700}
5701
5702static MetaFrameStyle*
5703theme_get_style (MetaTheme *theme,
5704 MetaFrameType type,
5705 MetaFrameFlags flags)
5706{
5707 MetaFrameState state;
5708 MetaFrameResize resize;
5709 MetaFrameFocus focus;
5710 MetaFrameStyle *style;
5711 MetaFrameStyleSet *style_set;
5712
5713 style_set = theme->style_sets_by_type[type];
5714
5715 if (style_set == NULL((void*)0) && type == META_FRAME_TYPE_ATTACHED)
5716 style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER];
5717
5718 /* Right now the parser forces a style set for all other types,
5719 * but this fallback code is here in case I take that out.
5720 */
5721 if (style_set == NULL((void*)0))
5722 style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL];
5723 if (style_set == NULL((void*)0))
5724 return NULL((void*)0);
5725
5726 switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT))
5727 {
5728 case 0:
5729 state = META_FRAME_STATE_NORMAL;
5730 break;
5731 case META_FRAME_MAXIMIZED:
5732 state = META_FRAME_STATE_MAXIMIZED;
5733 break;
5734 case META_FRAME_TILED_LEFT:
5735 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_LEFT):
5736 state = META_FRAME_STATE_TILED_LEFT;
5737 break;
5738 case META_FRAME_TILED_RIGHT:
5739 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_RIGHT):
5740 state = META_FRAME_STATE_TILED_RIGHT;
5741 break;
5742 case META_FRAME_SHADED:
5743 state = META_FRAME_STATE_SHADED;
5744 break;
5745 case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
5746 state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
5747 break;
5748 case (META_FRAME_TILED_LEFT | META_FRAME_SHADED):
5749 state = META_FRAME_STATE_TILED_LEFT_AND_SHADED;
5750 break;
5751 case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED):
5752 state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
5753 break;
5754 default:
5755 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5755, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5756 state = META_FRAME_STATE_LAST; /* compiler */
5757 break;
5758 }
5759
5760 switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
5761 {
5762 case 0:
5763 resize = META_FRAME_RESIZE_NONE;
5764 break;
5765 case META_FRAME_ALLOWS_VERTICAL_RESIZE:
5766 resize = META_FRAME_RESIZE_VERTICAL;
5767 break;
5768 case META_FRAME_ALLOWS_HORIZONTAL_RESIZE:
5769 resize = META_FRAME_RESIZE_HORIZONTAL;
5770 break;
5771 case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE):
5772 resize = META_FRAME_RESIZE_BOTH;
5773 break;
5774 default:
5775 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5775, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5776 resize = META_FRAME_RESIZE_LAST; /* compiler */
5777 break;
5778 }
5779
5780 /* re invert the styles used for focus/unfocussed while flashing a frame */
5781 if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
5782 || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
5783 focus = META_FRAME_FOCUS_YES;
5784 else
5785 focus = META_FRAME_FOCUS_NO;
5786
5787 style = get_style (style_set, state, resize, focus);
5788
5789 return style;
5790}
5791
5792MetaFrameStyle*
5793meta_theme_get_frame_style (MetaTheme *theme,
5794 MetaFrameType type,
5795 MetaFrameFlags flags)
5796{
5797 MetaFrameStyle *style;
5798
5799 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (((void*)0)); } } while (0)
;
5800
5801 style = theme_get_style (theme, type, flags);
5802
5803 return style;
5804}
5805
5806double
5807meta_theme_get_title_scale (MetaTheme *theme,
5808 MetaFrameType type,
5809 MetaFrameFlags flags)
5810{
5811 MetaFrameStyle *style;
5812
5813 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (1.0); } } while (0)
;
5814
5815 style = theme_get_style (theme, type, flags);
5816
5817 /* Parser is not supposed to allow this currently */
5818 if (style == NULL((void*)0))
5819 return 1.0;
5820
5821 return style->layout->title_scale;
5822}
5823
5824void
5825meta_theme_draw_frame (MetaTheme *theme,
5826 GtkStyleContext *style_gtk,
5827 cairo_t *cr,
5828 MetaFrameType type,
5829 MetaFrameFlags flags,
5830 int client_width,
5831 int client_height,
5832 PangoLayout *title_layout,
5833 int text_height,
5834 const MetaButtonLayout *button_layout,
5835 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5836 GdkPixbuf *mini_icon,
5837 GdkPixbuf *icon)
5838{
5839 MetaFrameGeometry fgeom;
5840 MetaFrameStyle *style;
5841
5842 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5843
5844 style = theme_get_style (theme, type, flags);
5845
5846 /* Parser is not supposed to allow this currently */
5847 if (style == NULL((void*)0))
5848 return;
5849
5850 meta_frame_layout_calc_geometry (style->layout,
5851 text_height,
5852 flags,
5853 client_width, client_height,
5854 button_layout,
5855 &fgeom,
5856 theme);
5857
5858 meta_frame_style_draw_with_style (style,
5859 style_gtk,
5860 cr,
5861 &fgeom,
5862 client_width, client_height,
5863 title_layout,
5864 text_height,
5865 button_states,
5866 mini_icon, icon);
5867}
5868
5869void
5870meta_theme_draw_frame_by_name (MetaTheme *theme,
5871 GtkWidget *widget,
5872 cairo_t *cr,
5873 const gchar *style_name,
5874 MetaFrameFlags flags,
5875 int client_width,
5876 int client_height,
5877 PangoLayout *title_layout,
5878 int text_height,
5879 const MetaButtonLayout *button_layout,
5880 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5881 GdkPixbuf *mini_icon,
5882 GdkPixbuf *icon)
5883{
5884 MetaFrameGeometry fgeom;
5885 MetaFrameStyle *style;
5886
5887 style = meta_theme_lookup_style (theme, style_name);
5888
5889 /* Parser is not supposed to allow this currently */
5890 if (style == NULL((void*)0))
5891 return;
5892
5893 meta_frame_layout_calc_geometry (style->layout,
5894 text_height,
5895 flags,
5896 client_width, client_height,
5897 button_layout,
5898 &fgeom,
5899 theme);
5900
5901 meta_frame_style_draw (style,
5902 widget,
5903 cr,
5904 &fgeom,
5905 client_width, client_height,
5906 title_layout,
5907 text_height,
5908 button_states,
5909 mini_icon, icon);
5910}
5911
5912void
5913meta_theme_get_frame_borders (MetaTheme *theme,
5914 MetaFrameType type,
5915 int text_height,
5916 MetaFrameFlags flags,
5917 MetaFrameBorders *borders)
5918{
5919 MetaFrameStyle *style;
5920
5921 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5922
5923 style = theme_get_style (theme, type, flags);
5924
5925 meta_frame_borders_clear (borders);
5926
5927 /* Parser is not supposed to allow this currently */
5928 if (style == NULL((void*)0))
5929 return;
5930
5931 meta_frame_layout_get_borders (style->layout,
5932 text_height,
5933 flags,
5934 borders);
5935}
5936
5937void
5938meta_theme_calc_geometry (MetaTheme *theme,
5939 MetaFrameType type,
5940 int text_height,
5941 MetaFrameFlags flags,
5942 int client_width,
5943 int client_height,
5944 const MetaButtonLayout *button_layout,
5945 MetaFrameGeometry *fgeom)
5946{
5947 MetaFrameStyle *style;
5948
5949 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5950
5951 style = theme_get_style (theme, type, flags);
5952
5953 /* Parser is not supposed to allow this currently */
5954 if (style == NULL((void*)0))
5955 return;
5956
5957 meta_frame_layout_calc_geometry (style->layout,
5958 text_height,
5959 flags,
5960 client_width, client_height,
5961 button_layout,
5962 fgeom,
5963 theme);
5964}
5965
5966MetaFrameLayout*
5967meta_theme_lookup_layout (MetaTheme *theme,
5968 const char *name)
5969{
5970 return g_hash_table_lookup (theme->layouts_by_name, name);
5971}
5972
5973void
5974meta_theme_insert_layout (MetaTheme *theme,
5975 const char *name,
5976 MetaFrameLayout *layout)
5977{
5978 meta_frame_layout_ref (layout);
5979 g_hash_table_replace (theme->layouts_by_name, g_strdup (name)g_strdup_inline (name), layout);
5980}
5981
5982MetaDrawOpList*
5983meta_theme_lookup_draw_op_list (MetaTheme *theme,
5984 const char *name)
5985{
5986 return g_hash_table_lookup (theme->draw_op_lists_by_name, name);
5987}
5988
5989void
5990meta_theme_insert_draw_op_list (MetaTheme *theme,
5991 const char *name,
5992 MetaDrawOpList *op_list)
5993{
5994 meta_draw_op_list_ref (op_list);
5995 g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name)g_strdup_inline (name), op_list);
5996}
5997
5998MetaFrameStyle*
5999meta_theme_lookup_style (MetaTheme *theme,
6000 const char *name)
6001{
6002 return g_hash_table_lookup (theme->styles_by_name, name);
6003}
6004
6005void
6006meta_theme_insert_style (MetaTheme *theme,
6007 const char *name,
6008 MetaFrameStyle *style)
6009{
6010 meta_frame_style_ref (style);
6011 g_hash_table_replace (theme->styles_by_name, g_strdup (name)g_strdup_inline (name), style);
6012}
6013
6014MetaFrameStyleSet*
6015meta_theme_lookup_style_set (MetaTheme *theme,
6016 const char *name)
6017{
6018 return g_hash_table_lookup (theme->style_sets_by_name, name);
6019}
6020
6021void
6022meta_theme_insert_style_set (MetaTheme *theme,
6023 const char *name,
6024 MetaFrameStyleSet *style_set)
6025{
6026 meta_frame_style_set_ref (style_set);
6027 g_hash_table_replace (theme->style_sets_by_name, g_strdup (name)g_strdup_inline (name), style_set);
6028}
6029
6030static gboolean
6031first_uppercase (const char *str)
6032{
6033 return g_ascii_isupper (*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_UPPER) != 0);
6034}
6035
6036gboolean
6037meta_theme_define_int_constant (MetaTheme *theme,
6038 const char *name,
6039 int value,
6040 GError **error)
6041{
6042 if (theme->integer_constants == NULL((void*)0))
6043 theme->integer_constants = g_hash_table_new_full (g_str_hash,
6044 g_str_equal,
6045 g_free,
6046 NULL((void*)0));
6047
6048 if (!first_uppercase (name))
6049 {
6050 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6051 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6052 name);
6053 return FALSE(0);
6054 }
6055
6056 if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL((void*)0), NULL((void*)0)))
6057 {
6058 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6059 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6060 name);
6061
6062 return FALSE(0);
6063 }
6064
6065 g_hash_table_insert (theme->integer_constants,
6066 g_strdup (name)g_strdup_inline (name),
6067 GINT_TO_POINTER (value)((gpointer) (glong) (value)));
6068
6069 return TRUE(!(0));
6070}
6071
6072gboolean
6073meta_theme_lookup_int_constant (MetaTheme *theme,
6074 const char *name,
6075 int *value)
6076{
6077 gpointer old_value;
6078
6079 *value = 0;
6080
6081 if (theme->integer_constants == NULL((void*)0))
6082 return FALSE(0);
6083
6084 if (g_hash_table_lookup_extended (theme->integer_constants,
6085 name, NULL((void*)0), &old_value))
6086 {
6087 *value = GPOINTER_TO_INT (old_value)((gint) (glong) (old_value));
6088 return TRUE(!(0));
6089 }
6090 else
6091 {
6092 return FALSE(0);
6093 }
6094}
6095
6096gboolean
6097meta_theme_define_float_constant (MetaTheme *theme,
6098 const char *name,
6099 double value,
6100 GError **error)
6101{
6102 double *d;
6103
6104 if (theme->float_constants == NULL((void*)0))
6105 theme->float_constants = g_hash_table_new_full (g_str_hash,
6106 g_str_equal,
6107 g_free,
6108 g_free);
6109
6110 if (!first_uppercase (name))
6111 {
6112 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6113 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6114 name);
6115 return FALSE(0);
6116 }
6117
6118 if (g_hash_table_lookup_extended (theme->float_constants, name, NULL((void*)0), NULL((void*)0)))
6119 {
6120 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6121 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6122 name);
6123
6124 return FALSE(0);
6125 }
6126
6127 d = g_new (double, 1)((double *) g_malloc_n ((1), sizeof (double)));
6128 *d = value;
6129
6130 g_hash_table_insert (theme->float_constants,
6131 g_strdup (name)g_strdup_inline (name), d);
6132
6133 return TRUE(!(0));
6134}
6135
6136gboolean
6137meta_theme_lookup_float_constant (MetaTheme *theme,
6138 const char *name,
6139 double *value)
6140{
6141 double *d;
6142
6143 *value = 0.0;
6144
6145 if (theme->float_constants == NULL((void*)0))
6146 return FALSE(0);
6147
6148 d = g_hash_table_lookup (theme->float_constants, name);
6149
6150 if (d)
6151 {
6152 *value = *d;
6153 return TRUE(!(0));
6154 }
6155 else
6156 {
6157 return FALSE(0);
6158 }
6159}
6160
6161gboolean
6162meta_theme_define_color_constant (MetaTheme *theme,
6163 const char *name,
6164 const char *value,
6165 GError **error)
6166{
6167 if (theme->color_constants == NULL((void*)0))
6168 theme->color_constants = g_hash_table_new_full (g_str_hash,
6169 g_str_equal,
6170 g_free,
6171 NULL((void*)0));
6172
6173 if (!first_uppercase (name))
6174 {
6175 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6176 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6177 name);
6178 return FALSE(0);
6179 }
6180
6181 if (g_hash_table_lookup_extended (theme->color_constants, name, NULL((void*)0), NULL((void*)0)))
6182 {
6183 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6184 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6185 name);
6186
6187 return FALSE(0);
6188 }
6189
6190 g_hash_table_insert (theme->color_constants,
6191 g_strdup (name)g_strdup_inline (name),
6192 g_strdup (value)g_strdup_inline (value));
6193
6194 return TRUE(!(0));
6195}
6196
6197/**
6198 * Looks up a colour constant.
6199 *
6200 * \param theme the theme containing the constant
6201 * \param name the name of the constant
6202 * \param value [out] the string representation of the colour, or NULL if it
6203 * doesn't exist
6204 * \return TRUE if it exists, FALSE otherwise
6205 */
6206gboolean
6207meta_theme_lookup_color_constant (MetaTheme *theme,
6208 const char *name,
6209 char **value)
6210{
6211 char *result;
6212
6213 *value = NULL((void*)0);
6214
6215 if (theme->color_constants == NULL((void*)0))
6216 return FALSE(0);
6217
6218 result = g_hash_table_lookup (theme->color_constants, name);
6219
6220 if (result)
6221 {
6222 *value = result;
6223 return TRUE(!(0));
6224 }
6225 else
6226 {
6227 return FALSE(0);
6228 }
6229}
6230
6231PangoFontDescription*
6232meta_gtk_widget_get_font_desc (GtkWidget *widget,
6233 double scale,
6234 const PangoFontDescription *override)
6235{
6236 PangoFontDescription *font_desc;
6237 gint font_size;
6238
6239 GtkStyleContext *style = gtk_widget_get_style_context (widget);
6240 GtkStateFlags state = gtk_widget_get_state_flags (widget);
6241 gtk_style_context_get(style, state, GTK_STYLE_PROPERTY_FONT"font", &font_desc, NULL((void*)0));
6242
6243 if (override)
6244 pango_font_description_merge (font_desc, override, TRUE(!(0)));
6245
6246 font_size = pango_font_description_get_size (font_desc);
6247 pango_font_description_set_size (font_desc,
6248 MAX ((gint) (scale * (double) font_size), 1)((((gint) (scale * (double) font_size)) > (1)) ? ((gint) (
scale * (double) font_size)) : (1))
);
6249
6250 return font_desc;
6251}
6252
6253/**
6254 * Returns the height of the letters in a particular font.
6255 *
6256 * \param font_desc the font
6257 * \param context the context of the font
6258 * \return the height of the letters
6259 */
6260int
6261meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
6262 PangoContext *context)
6263{
6264 PangoFontMetrics *metrics;
6265 PangoLanguage *lang;
6266 int retval;
6267
6268 lang = pango_context_get_language (context);
6269 metrics = pango_context_get_metrics (context, font_desc, lang);
6270
6271 retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
6272 pango_font_metrics_get_descent (metrics))(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
;
6273
6274 pango_font_metrics_unref (metrics);
6275
6276 return retval;
6277}
6278
6279MetaGtkColorComponent
6280meta_color_component_from_string (const char *str)
6281{
6282 if (strcmp ("fg", str) == 0)
6283 return META_GTK_COLOR_FG;
6284 else if (strcmp ("bg", str) == 0)
6285 return META_GTK_COLOR_BG;
6286 else if (strcmp ("light", str) == 0)
6287 return META_GTK_COLOR_LIGHT;
6288 else if (strcmp ("dark", str) == 0)
6289 return META_GTK_COLOR_DARK;
6290 else if (strcmp ("mid", str) == 0)
6291 return META_GTK_COLOR_MID;
6292 else if (strcmp ("text", str) == 0)
6293 return META_GTK_COLOR_TEXT;
6294 else if (strcmp ("base", str) == 0)
6295 return META_GTK_COLOR_BASE;
6296 else if (strcmp ("text_aa", str) == 0)
6297 return META_GTK_COLOR_TEXT_AA;
6298 else
6299 return META_GTK_COLOR_LAST;
6300}
6301
6302const char*
6303meta_color_component_to_string (MetaGtkColorComponent component)
6304{
6305 switch (component)
6306 {
6307 case META_GTK_COLOR_FG:
6308 return "fg";
6309 case META_GTK_COLOR_BG:
6310 return "bg";
6311 case META_GTK_COLOR_LIGHT:
6312 return "light";
6313 case META_GTK_COLOR_DARK:
6314 return "dark";
6315 case META_GTK_COLOR_MID:
6316 return "mid";
6317 case META_GTK_COLOR_TEXT:
6318 return "text";
6319 case META_GTK_COLOR_BASE:
6320 return "base";
6321 case META_GTK_COLOR_TEXT_AA:
6322 return "text_aa";
6323 case META_GTK_COLOR_LAST:
6324 break;
6325 }
6326
6327 return "<unknown>";
6328}
6329
6330MetaButtonState
6331meta_button_state_from_string (const char *str)
6332{
6333 if (strcmp ("normal", str) == 0)
6334 return META_BUTTON_STATE_NORMAL;
6335 else if (strcmp ("pressed", str) == 0)
6336 return META_BUTTON_STATE_PRESSED;
6337 else if (strcmp ("prelight", str) == 0)
6338 return META_BUTTON_STATE_PRELIGHT;
6339 else
6340 return META_BUTTON_STATE_LAST;
6341}
6342
6343const char*
6344meta_button_state_to_string (MetaButtonState state)
6345{
6346 switch (state)
6347 {
6348 case META_BUTTON_STATE_NORMAL:
6349 return "normal";
6350 case META_BUTTON_STATE_PRESSED:
6351 return "pressed";
6352 case META_BUTTON_STATE_PRELIGHT:
6353 return "prelight";
6354 case META_BUTTON_STATE_LAST:
6355 break;
6356 }
6357
6358 return "<unknown>";
6359}
6360
6361MetaButtonType
6362meta_button_type_from_string (const char *str, MetaTheme *theme)
6363{
6364 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
6365 {
6366 if (strcmp ("shade", str) == 0)
6367 return META_BUTTON_TYPE_SHADE;
6368 else if (strcmp ("above", str) == 0)
6369 return META_BUTTON_TYPE_ABOVE;
6370 else if (strcmp ("stick", str) == 0)
6371 return META_BUTTON_TYPE_STICK;
6372 else if (strcmp ("unshade", str) == 0)
6373 return META_BUTTON_TYPE_UNSHADE;
6374 else if (strcmp ("unabove", str) == 0)
6375 return META_BUTTON_TYPE_UNABOVE;
6376 else if (strcmp ("unstick", str) == 0)
6377 return META_BUTTON_TYPE_UNSTICK;
6378 }
6379
6380 if (strcmp ("close", str) == 0)
6381 return META_BUTTON_TYPE_CLOSE;
6382 else if (strcmp ("maximize", str) == 0)
6383 return META_BUTTON_TYPE_MAXIMIZE;
6384 else if (strcmp ("minimize", str) == 0)
6385 return META_BUTTON_TYPE_MINIMIZE;
6386 else if (strcmp ("menu", str) == 0)
6387 return META_BUTTON_TYPE_MENU;
6388 else if (strcmp ("appmenu", str) == 0)
6389 return META_BUTTON_TYPE_APPMENU;
6390 else if (strcmp ("left_left_background", str) == 0)
6391 return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
6392 else if (strcmp ("left_middle_background", str) == 0)
6393 return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
6394 else if (strcmp ("left_right_background", str) == 0)
6395 return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
6396 else if (strcmp ("left_single_background", str) == 0)
6397 return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND;
6398 else if (strcmp ("right_left_background", str) == 0)
6399 return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
6400 else if (strcmp ("right_middle_background", str) == 0)
6401 return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
6402 else if (strcmp ("right_right_background", str) == 0)
6403 return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
6404 else if (strcmp ("right_single_background", str) == 0)
6405 return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND;
6406 else
6407 return META_BUTTON_TYPE_LAST;
6408}
6409
6410const char*
6411meta_button_type_to_string (MetaButtonType type)
6412{
6413 switch (type)
6414 {
6415 case META_BUTTON_TYPE_CLOSE:
6416 return "close";
6417 case META_BUTTON_TYPE_MAXIMIZE:
6418 return "maximize";
6419 case META_BUTTON_TYPE_MINIMIZE:
6420 return "minimize";
6421 case META_BUTTON_TYPE_SHADE:
6422 return "shade";
6423 case META_BUTTON_TYPE_ABOVE:
6424 return "above";
6425 case META_BUTTON_TYPE_STICK:
6426 return "stick";
6427 case META_BUTTON_TYPE_UNSHADE:
6428 return "unshade";
6429 case META_BUTTON_TYPE_UNABOVE:
6430 return "unabove";
6431 case META_BUTTON_TYPE_UNSTICK:
6432 return "unstick";
6433 case META_BUTTON_TYPE_MENU:
6434 return "menu";
6435 case META_BUTTON_TYPE_APPMENU:
6436 return "appmenu";
6437 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
6438 return "left_left_background";
6439 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
6440 return "left_middle_background";
6441 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
6442 return "left_right_background";
6443 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
6444 return "left_single_background";
6445 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
6446 return "right_left_background";
6447 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
6448 return "right_middle_background";
6449 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
6450 return "right_right_background";
6451 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
6452 return "right_single_background";
6453 case META_BUTTON_TYPE_LAST:
6454 break;
6455 }
6456
6457 return "<unknown>";
6458}
6459
6460MetaFramePiece
6461meta_frame_piece_from_string (const char *str)
6462{
6463 if (strcmp ("entire_background", str) == 0)
6464 return META_FRAME_PIECE_ENTIRE_BACKGROUND;
6465 else if (strcmp ("titlebar", str) == 0)
6466 return META_FRAME_PIECE_TITLEBAR;
6467 else if (strcmp ("titlebar_middle", str) == 0)
6468 return META_FRAME_PIECE_TITLEBAR_MIDDLE;
6469 else if (strcmp ("left_titlebar_edge", str) == 0)
6470 return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE;
6471 else if (strcmp ("right_titlebar_edge", str) == 0)
6472 return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE;
6473 else if (strcmp ("top_titlebar_edge", str) == 0)
6474 return META_FRAME_PIECE_TOP_TITLEBAR_EDGE;
6475 else if (strcmp ("bottom_titlebar_edge", str) == 0)
6476 return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE;
6477 else if (strcmp ("title", str) == 0)
6478 return META_FRAME_PIECE_TITLE;
6479 else if (strcmp ("left_edge", str) == 0)
6480 return META_FRAME_PIECE_LEFT_EDGE;
6481 else if (strcmp ("right_edge", str) == 0)
6482 return META_FRAME_PIECE_RIGHT_EDGE;
6483 else if (strcmp ("bottom_edge", str) == 0)
6484 return META_FRAME_PIECE_BOTTOM_EDGE;
6485 else if (strcmp ("overlay", str) == 0)
6486 return META_FRAME_PIECE_OVERLAY;
6487 else
6488 return META_FRAME_PIECE_LAST;
6489}
6490
6491const char*
6492meta_frame_piece_to_string (MetaFramePiece piece)
6493{
6494 switch (piece)
6495 {
6496 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
6497 return "entire_background";
6498 case META_FRAME_PIECE_TITLEBAR:
6499 return "titlebar";
6500 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
6501 return "titlebar_middle";
6502 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
6503 return "left_titlebar_edge";
6504 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
6505 return "right_titlebar_edge";
6506 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
6507 return "top_titlebar_edge";
6508 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
6509 return "bottom_titlebar_edge";
6510 case META_FRAME_PIECE_TITLE:
6511 return "title";
6512 case META_FRAME_PIECE_LEFT_EDGE:
6513 return "left_edge";
6514 case META_FRAME_PIECE_RIGHT_EDGE:
6515 return "right_edge";
6516 case META_FRAME_PIECE_BOTTOM_EDGE:
6517 return "bottom_edge";
6518 case META_FRAME_PIECE_OVERLAY:
6519 return "overlay";
6520 case META_FRAME_PIECE_LAST:
6521 break;
6522 }
6523
6524 return "<unknown>";
6525}
6526
6527MetaFrameState
6528meta_frame_state_from_string (const char *str)
6529{
6530 if (strcmp ("normal", str) == 0)
6531 return META_FRAME_STATE_NORMAL;
6532 else if (strcmp ("maximized", str) == 0)
6533 return META_FRAME_STATE_MAXIMIZED;
6534 else if (strcmp ("tiled_left", str) == 0)
6535 return META_FRAME_STATE_TILED_LEFT;
6536 else if (strcmp ("tiled_right", str) == 0)
6537 return META_FRAME_STATE_TILED_RIGHT;
6538 else if (strcmp ("shaded", str) == 0)
6539 return META_FRAME_STATE_SHADED;
6540 else if (strcmp ("maximized_and_shaded", str) == 0)
6541 return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
6542 else if (strcmp ("tiled_left_and_shaded", str) == 0)
6543 return META_FRAME_STATE_TILED_LEFT_AND_SHADED;
6544 else if (strcmp ("tiled_right_and_shaded", str) == 0)
6545 return META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
6546 else
6547 return META_FRAME_STATE_LAST;
6548}
6549
6550const char*
6551meta_frame_state_to_string (MetaFrameState state)
6552{
6553 switch (state)
6554 {
6555 case META_FRAME_STATE_NORMAL:
6556 return "normal";
6557 case META_FRAME_STATE_MAXIMIZED:
6558 return "maximized";
6559 case META_FRAME_STATE_TILED_LEFT:
6560 return "tiled_left";
6561 case META_FRAME_STATE_TILED_RIGHT:
6562 return "tiled_right";
6563 case META_FRAME_STATE_SHADED:
6564 return "shaded";
6565 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
6566 return "maximized_and_shaded";
6567 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
6568 return "tiled_left_and_shaded";
6569 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
6570 return "tiled_right_and_shaded";
6571 case META_FRAME_STATE_LAST:
6572 break;
6573 }
6574
6575 return "<unknown>";
6576}
6577
6578MetaFrameResize
6579meta_frame_resize_from_string (const char *str)
6580{
6581 if (strcmp ("none", str) == 0)
6582 return META_FRAME_RESIZE_NONE;
6583 else if (strcmp ("vertical", str) == 0)
6584 return META_FRAME_RESIZE_VERTICAL;
6585 else if (strcmp ("horizontal", str) == 0)
6586 return META_FRAME_RESIZE_HORIZONTAL;
6587 else if (strcmp ("both", str) == 0)
6588 return META_FRAME_RESIZE_BOTH;
6589 else
6590 return META_FRAME_RESIZE_LAST;
6591}
6592
6593const char*
6594meta_frame_resize_to_string (MetaFrameResize resize)
6595{
6596 switch (resize)
6597 {
6598 case META_FRAME_RESIZE_NONE:
6599 return "none";
6600 case META_FRAME_RESIZE_VERTICAL:
6601 return "vertical";
6602 case META_FRAME_RESIZE_HORIZONTAL:
6603 return "horizontal";
6604 case META_FRAME_RESIZE_BOTH:
6605 return "both";
6606 case META_FRAME_RESIZE_LAST:
6607 break;
6608 }
6609
6610 return "<unknown>";
6611}
6612
6613MetaFrameFocus
6614meta_frame_focus_from_string (const char *str)
6615{
6616 if (strcmp ("no", str) == 0)
6617 return META_FRAME_FOCUS_NO;
6618 else if (strcmp ("yes", str) == 0)
6619 return META_FRAME_FOCUS_YES;
6620 else
6621 return META_FRAME_FOCUS_LAST;
6622}
6623
6624const char*
6625meta_frame_focus_to_string (MetaFrameFocus focus)
6626{
6627 switch (focus)
6628 {
6629 case META_FRAME_FOCUS_NO:
6630 return "no";
6631 case META_FRAME_FOCUS_YES:
6632 return "yes";
6633 case META_FRAME_FOCUS_LAST:
6634 break;
6635 }
6636
6637 return "<unknown>";
6638}
6639
6640MetaFrameType
6641meta_frame_type_from_string (const char *str)
6642{
6643 if (strcmp ("normal", str) == 0)
6644 return META_FRAME_TYPE_NORMAL;
6645 else if (strcmp ("dialog", str) == 0)
6646 return META_FRAME_TYPE_DIALOG;
6647 else if (strcmp ("modal_dialog", str) == 0)
6648 return META_FRAME_TYPE_MODAL_DIALOG;
6649 else if (strcmp ("utility", str) == 0)
6650 return META_FRAME_TYPE_UTILITY;
6651 else if (strcmp ("menu", str) == 0)
6652 return META_FRAME_TYPE_MENU;
6653 else if (strcmp ("border", str) == 0)
6654 return META_FRAME_TYPE_BORDER;
6655 else if (strcmp ("attached", str) == 0)
6656 return META_FRAME_TYPE_ATTACHED;
6657#if 0
6658 else if (strcmp ("toolbar", str) == 0)
6659 return META_FRAME_TYPE_TOOLBAR;
6660#endif
6661 else
6662 return META_FRAME_TYPE_LAST;
6663}
6664
6665const char*
6666meta_frame_type_to_string (MetaFrameType type)
6667{
6668 switch (type)
6669 {
6670 case META_FRAME_TYPE_NORMAL:
6671 return "normal";
6672 case META_FRAME_TYPE_DIALOG:
6673 return "dialog";
6674 case META_FRAME_TYPE_MODAL_DIALOG:
6675 return "modal_dialog";
6676 case META_FRAME_TYPE_UTILITY:
6677 return "utility";
6678 case META_FRAME_TYPE_MENU:
6679 return "menu";
6680 case META_FRAME_TYPE_BORDER:
6681 return "border";
6682 case META_FRAME_TYPE_ATTACHED:
6683 return "attached";
6684#if 0
6685 case META_FRAME_TYPE_TOOLBAR:
6686 return "toolbar";
6687#endif
6688 case META_FRAME_TYPE_LAST:
6689 break;
6690 }
6691
6692 return "<unknown>";
6693}
6694
6695MetaGradientType
6696meta_gradient_type_from_string (const char *str)
6697{
6698 if (strcmp ("vertical", str) == 0)
6699 return META_GRADIENT_VERTICAL;
6700 else if (strcmp ("horizontal", str) == 0)
6701 return META_GRADIENT_HORIZONTAL;
6702 else if (strcmp ("diagonal", str) == 0)
6703 return META_GRADIENT_DIAGONAL;
6704 else
6705 return META_GRADIENT_LAST;
6706}
6707
6708const char*
6709meta_gradient_type_to_string (MetaGradientType type)
6710{
6711 switch (type)
6712 {
6713 case META_GRADIENT_VERTICAL:
6714 return "vertical";
6715 case META_GRADIENT_HORIZONTAL:
6716 return "horizontal";
6717 case META_GRADIENT_DIAGONAL:
6718 return "diagonal";
6719 case META_GRADIENT_LAST:
6720 break;
6721 }
6722
6723 return "<unknown>";
6724}
6725
6726GtkStateFlags
6727meta_gtk_state_from_string (const char *str)
6728{
6729 if (g_ascii_strcasecmp ("normal", str) == 0)
6730 return GTK_STATE_FLAG_NORMAL;
6731 else if (g_ascii_strcasecmp ("prelight", str) == 0)
6732 return GTK_STATE_FLAG_PRELIGHT;
6733 else if (g_ascii_strcasecmp ("active", str) == 0)
6734 return GTK_STATE_FLAG_ACTIVE;
6735 else if (g_ascii_strcasecmp ("selected", str) == 0)
6736 return GTK_STATE_FLAG_SELECTED;
6737 else if (g_ascii_strcasecmp ("insensitive", str) == 0)
6738 return GTK_STATE_FLAG_INSENSITIVE;
6739 else if (g_ascii_strcasecmp ("inconsistent", str) == 0)
6740 return GTK_STATE_FLAG_INCONSISTENT;
6741 else if (g_ascii_strcasecmp ("focused", str) == 0)
6742 return GTK_STATE_FLAG_FOCUSED;
6743 else if (g_ascii_strcasecmp ("backdrop", str) == 0)
6744 return GTK_STATE_FLAG_BACKDROP;
6745 else
6746 return -1; /* hack */
6747}
6748
6749GtkShadowType
6750meta_gtk_shadow_from_string (const char *str)
6751{
6752 if (strcmp ("none", str) == 0)
6753 return GTK_SHADOW_NONE;
6754 else if (strcmp ("in", str) == 0)
6755 return GTK_SHADOW_IN;
6756 else if (strcmp ("out", str) == 0)
6757 return GTK_SHADOW_OUT;
6758 else if (strcmp ("etched_in", str) == 0)
6759 return GTK_SHADOW_ETCHED_IN;
6760 else if (strcmp ("etched_out", str) == 0)
6761 return GTK_SHADOW_ETCHED_OUT;
6762 else
6763 return -1;
6764}
6765
6766const char*
6767meta_gtk_shadow_to_string (GtkShadowType shadow)
6768{
6769 switch (shadow)
6770 {
6771 case GTK_SHADOW_NONE:
6772 return "none";
6773 case GTK_SHADOW_IN:
6774 return "in";
6775 case GTK_SHADOW_OUT:
6776 return "out";
6777 case GTK_SHADOW_ETCHED_IN:
6778 return "etched_in";
6779 case GTK_SHADOW_ETCHED_OUT:
6780 return "etched_out";
6781 }
6782
6783 return "<unknown>";
6784}
6785
6786GtkArrowType
6787meta_gtk_arrow_from_string (const char *str)
6788{
6789 if (strcmp ("up", str) == 0)
6790 return GTK_ARROW_UP;
6791 else if (strcmp ("down", str) == 0)
6792 return GTK_ARROW_DOWN;
6793 else if (strcmp ("left", str) == 0)
6794 return GTK_ARROW_LEFT;
6795 else if (strcmp ("right", str) == 0)
6796 return GTK_ARROW_RIGHT;
6797 else if (strcmp ("none", str) == 0)
6798 return GTK_ARROW_NONE;
6799 else
6800 return -1;
6801}
6802
6803const char*
6804meta_gtk_arrow_to_string (GtkArrowType arrow)
6805{
6806 switch (arrow)
6807 {
6808 case GTK_ARROW_UP:
6809 return "up";
6810 case GTK_ARROW_DOWN:
6811 return "down";
6812 case GTK_ARROW_LEFT:
6813 return "left";
6814 case GTK_ARROW_RIGHT:
6815 return "right";
6816 case GTK_ARROW_NONE:
6817 return "none";
6818 }
6819
6820 return "<unknown>";
6821}
6822
6823/**
6824 * Returns a fill_type from a string. The inverse of
6825 * meta_image_fill_type_to_string().
6826 *
6827 * \param str a string representing a fill_type
6828 * \result the fill_type, or -1 if it represents no fill_type.
6829 */
6830MetaImageFillType
6831meta_image_fill_type_from_string (const char *str)
6832{
6833 if (strcmp ("tile", str) == 0)
6834 return META_IMAGE_FILL_TILE;
6835 else if (strcmp ("scale", str) == 0)
6836 return META_IMAGE_FILL_SCALE;
6837 else
6838 return -1;
6839}
6840
6841/**
6842 * Returns a string representation of a fill_type. The inverse of
6843 * meta_image_fill_type_from_string().
6844 *
6845 * \param fill_type the fill type
6846 * \result a string representing that type
6847 */
6848const char*
6849meta_image_fill_type_to_string (MetaImageFillType fill_type)
6850{
6851 switch (fill_type)
6852 {
6853 case META_IMAGE_FILL_TILE:
6854 return "tile";
6855 case META_IMAGE_FILL_SCALE:
6856 return "scale";
6857 }
6858
6859 return "<unknown>";
6860}
6861
6862/**
6863 * Takes a colour "a", scales the lightness and saturation by a certain amount,
6864 * and sets "b" to the resulting colour.
6865 * gtkstyle.c cut-and-pastage.
6866 *
6867 * \param a the starting colour
6868 * \param b [out] the resulting colour
6869 * \param k amount to scale lightness and saturation by
6870 */
6871static void
6872gtk_style_shade (GdkRGBA *a,
6873 GdkRGBA *b,
6874 gdouble k)
6875{
6876 gdouble red;
6877 gdouble green;
6878 gdouble blue;
6879
6880 red = a->red;
6881 green = a->green;
6882 blue = a->blue;
6883
6884 rgb_to_hls (&red, &green, &blue);
6885
6886 green *= k;
6887 if (green > 1.0)
6888 green = 1.0;
6889 else if (green < 0.0)
6890 green = 0.0;
6891
6892 blue *= k;
6893 if (blue > 1.0)
6894 blue = 1.0;
6895 else if (blue < 0.0)
6896 blue = 0.0;
6897
6898 hls_to_rgb (&red, &green, &blue);
6899
6900 b->red = red;
6901 b->green = green;
6902 b->blue = blue;
6903}
6904
6905/**
6906 * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
6907 *
6908 * \param r on input, red; on output, hue
6909 * \param g on input, green; on output, lightness
6910 * \param b on input, blue; on output, saturation
6911 */
6912static void
6913rgb_to_hls (gdouble *r,
6914 gdouble *g,
6915 gdouble *b)
6916{
6917 gdouble min;
6918 gdouble max;
6919 gdouble red;
6920 gdouble green;
6921 gdouble blue;
6922 gdouble h, l, s;
6923 gdouble delta;
6924
6925 red = *r;
6926 green = *g;
6927 blue = *b;
6928
6929 if (red > green)
6930 {
6931 if (red > blue)
6932 max = red;
6933 else
6934 max = blue;
6935
6936 if (green < blue)
6937 min = green;
6938 else
6939 min = blue;
6940 }
6941 else
6942 {
6943 if (green > blue)
6944 max = green;
6945 else
6946 max = blue;
6947
6948 if (red < blue)
6949 min = red;
6950 else
6951 min = blue;
6952 }
6953
6954 l = (max + min) / 2;
6955 s = 0;
6956 h = 0;
6957
6958 if (max != min)
6959 {
6960 if (l <= 0.5)
6961 s = (max - min) / (max + min);
6962 else
6963 s = (max - min) / (2 - max - min);
6964
6965 delta = max -min;
6966 if (red == max)
6967 h = (green - blue) / delta;
6968 else if (green == max)
6969 h = 2 + (blue - red) / delta;
6970 else if (blue == max)
6971 h = 4 + (red - green) / delta;
6972
6973 h *= 60;
6974 if (h < 0.0)
6975 h += 360;
6976 }
6977
6978 *r = h;
6979 *g = l;
6980 *b = s;
6981}
6982
6983/**
6984 * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
6985 *
6986 * \param h on input, hue; on output, red
6987 * \param l on input, lightness; on output, green
6988 * \param s on input, saturation; on output, blue
6989 */
6990static void
6991hls_to_rgb (gdouble *h,
6992 gdouble *l,
6993 gdouble *s)
6994{
6995 gdouble hue;
6996 gdouble lightness;
6997 gdouble saturation;
6998 gdouble m1, m2;
6999 gdouble r, g, b;
7000
7001 lightness = *l;
7002 saturation = *s;
7003
7004 if (lightness <= 0.5)
7005 m2 = lightness * (1 + saturation);
7006 else
7007 m2 = lightness + saturation - lightness * saturation;
7008 m1 = 2 * lightness - m2;
7009
7010 if (saturation == 0)
7011 {
7012 *h = lightness;
7013 *l = lightness;
7014 *s = lightness;
7015 }
7016 else
7017 {
7018 hue = *h + 120;
7019 while (hue > 360)
7020 hue -= 360;
7021 while (hue < 0)
7022 hue += 360;
7023
7024 if (hue < 60)
7025 r = m1 + (m2 - m1) * hue / 60;
7026 else if (hue < 180)
7027 r = m2;
7028 else if (hue < 240)
7029 r = m1 + (m2 - m1) * (240 - hue) / 60;
7030 else
7031 r = m1;
7032
7033 hue = *h;
7034 while (hue > 360)
7035 hue -= 360;
7036 while (hue < 0)
7037 hue += 360;
7038
7039 if (hue < 60)
7040 g = m1 + (m2 - m1) * hue / 60;
7041 else if (hue < 180)
7042 g = m2;
7043 else if (hue < 240)
7044 g = m1 + (m2 - m1) * (240 - hue) / 60;
7045 else
7046 g = m1;
7047
7048 hue = *h - 120;
7049 while (hue > 360)
7050 hue -= 360;
7051 while (hue < 0)
7052 hue += 360;
7053
7054 if (hue < 60)
7055 b = m1 + (m2 - m1) * hue / 60;
7056 else if (hue < 180)
7057 b = m2;
7058 else if (hue < 240)
7059 b = m1 + (m2 - m1) * (240 - hue) / 60;
7060 else
7061 b = m1;
7062
7063 *h = r;
7064 *l = g;
7065 *s = b;
7066 }
7067}
7068
7069#if 0
7070/* These are some functions I'm saving to use in optimizing
7071 * MetaDrawOpList, namely to pre-composite pixbufs on client side
7072 * prior to rendering to the server
7073 */
7074static void
7075draw_bg_solid_composite (const MetaTextureSpec *bg,
7076 const MetaTextureSpec *fg,
7077 double alpha,
7078 GtkWidget *widget,
7079 GdkDrawable *drawable,
7080 const GdkRectangle *clip,
7081 MetaTextureDrawMode mode,
7082 double xalign,
7083 double yalign,
7084 int x,
7085 int y,
7086 int width,
7087 int height)
7088{
7089 GdkColor bg_color;
7090
7091 g_assert (bg->type == META_TEXTURE_SOLID)do { if (bg->type == META_TEXTURE_SOLID) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7091, ((const char*) (__func__)), "bg->type == META_TEXTURE_SOLID"
); } while (0)
;
7092 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7092, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7093 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7093, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7094
7095 meta_color_spec_render (bg->data.solid.color_spec,
7096 widget,
7097 &bg_color);
7098
7099 switch (fg->type)
7100 {
7101 case META_TEXTURE_SOLID:
7102 {
7103 GdkColor fg_color;
7104
7105 meta_color_spec_render (fg->data.solid.color_spec,
7106 widget,
7107 &fg_color);
7108
7109 color_composite (&bg_color, &fg_color,
7110 alpha, &fg_color);
7111
7112 draw_color_rectangle (widget, drawable, &fg_color, clip,
7113 x, y, width, height);
7114 }
7115 break;
7116
7117 case META_TEXTURE_GRADIENT:
7118 /* FIXME I think we could just composite all the colors in
7119 * the gradient prior to generating the gradient?
7120 */
7121 /* FALL THRU */
7122 case META_TEXTURE_IMAGE:
7123 {
7124 GdkPixbuf *pixbuf;
7125 GdkPixbuf *composited;
7126
7127 pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7128 width, height);
7129
7130 if (pixbuf == NULL((void*)0))
7131 return;
7132
7133 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7134 gdk_pixbuf_get_has_alpha (pixbuf), 8,
7135 gdk_pixbuf_get_width (pixbuf),
7136 gdk_pixbuf_get_height (pixbuf));
7137
7138 if (composited == NULL((void*)0))
7139 {
7140 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7141 return;
7142 }
7143
7144 gdk_pixbuf_composite_color (pixbuf,
7145 composited,
7146 0, 0,
7147 gdk_pixbuf_get_width (pixbuf),
7148 gdk_pixbuf_get_height (pixbuf),
7149 0.0, 0.0, /* offsets */
7150 1.0, 1.0, /* scale */
7151 GDK_INTERP_BILINEAR,
7152 255 * alpha,
7153 0, 0, /* check offsets */
7154 0, /* check size */
7155 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
,
7156 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
);
7157
7158 /* Need to draw background since pixbuf is not
7159 * necessarily covering the whole thing
7160 */
7161 draw_color_rectangle (widget, drawable, &bg_color, clip,
7162 x, y, width, height);
7163
7164 render_pixbuf_aligned (drawable, clip, composited,
7165 xalign, yalign,
7166 x, y, width, height);
7167
7168 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7169 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7170 }
7171 break;
7172
7173 case META_TEXTURE_BLANK:
7174 case META_TEXTURE_COMPOSITE:
7175 case META_TEXTURE_SHAPE_LIST:
7176 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7176, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7177 break;
7178 }
7179}
7180
7181static void
7182draw_bg_gradient_composite (const MetaTextureSpec *bg,
7183 const MetaTextureSpec *fg,
7184 double alpha,
7185 GtkWidget *widget,
7186 GdkDrawable *drawable,
7187 const GdkRectangle *clip,
7188 MetaTextureDrawMode mode,
7189 double xalign,
7190 double yalign,
7191 int x,
7192 int y,
7193 int width,
7194 int height)
7195{
7196 g_assert (bg->type == META_TEXTURE_GRADIENT)do { if (bg->type == META_TEXTURE_GRADIENT) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7196, ((const char*) (__func__)), "bg->type == META_TEXTURE_GRADIENT"
); } while (0)
;
7197 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7197, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7198 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7198, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7199
7200 switch (fg->type)
7201 {
7202 case META_TEXTURE_SOLID:
7203 case META_TEXTURE_GRADIENT:
7204 case META_TEXTURE_IMAGE:
7205 {
7206 GdkPixbuf *bg_pixbuf;
7207 GdkPixbuf *fg_pixbuf;
7208 GdkPixbuf *composited;
7209 int fg_width, fg_height;
7210
7211 bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255,
7212 width, height);
7213
7214 if (bg_pixbuf == NULL((void*)0))
7215 return;
7216
7217 fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7218 width, height);
7219
7220 if (fg_pixbuf == NULL((void*)0))
7221 {
7222 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7223 return;
7224 }
7225
7226 /* gradients always fill the entire target area */
7227 g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width)do { if (gdk_pixbuf_get_width (bg_pixbuf) == width) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7227, ((const char*) (__func__)), "gdk_pixbuf_get_width (bg_pixbuf) == width"
); } while (0)
;
7228 g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height)do { if (gdk_pixbuf_get_height (bg_pixbuf) == height) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7228, ((const char*) (__func__)), "gdk_pixbuf_get_height (bg_pixbuf) == height"
); } while (0)
;
7229
7230 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7231 gdk_pixbuf_get_has_alpha (bg_pixbuf), 8,
7232 gdk_pixbuf_get_width (bg_pixbuf),
7233 gdk_pixbuf_get_height (bg_pixbuf));
7234
7235 if (composited == NULL((void*)0))
7236 {
7237 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7238 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7239 return;
7240 }
7241
7242 fg_width = gdk_pixbuf_get_width (fg_pixbuf);
7243 fg_height = gdk_pixbuf_get_height (fg_pixbuf);
7244
7245 /* If we wanted to be all cool we could deal with the
7246 * offsets and try to composite only in the clip rectangle,
7247 * but I just don't care enough to figure it out.
7248 */
7249
7250 gdk_pixbuf_composite (fg_pixbuf,
7251 composited,
7252 x + (width - fg_width) * xalign,
7253 y + (height - fg_height) * yalign,
7254 gdk_pixbuf_get_width (fg_pixbuf),
7255 gdk_pixbuf_get_height (fg_pixbuf),
7256 0.0, 0.0, /* offsets */
7257 1.0, 1.0, /* scale */
7258 GDK_INTERP_BILINEAR,
7259 255 * alpha);
7260
7261 gdk_cairo_set_source_pixbuf (cr, composited, x, y);
7262 cairo_paint (cr);
7263
7264 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7265 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7266 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7267 }
7268 break;
7269
7270 case META_TEXTURE_BLANK:
7271 case META_TEXTURE_SHAPE_LIST:
7272 case META_TEXTURE_COMPOSITE:
7273 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7273, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7274 break;
7275 }
7276}
7277#endif
7278
7279/**
7280 * Returns the earliest version of the theme format which required support
7281 * for a particular button. (For example, "shade" first appeared in v2, and
7282 * "close" in v1.)
7283 *
7284 * \param type the button type
7285 * \return the number of the theme format
7286 */
7287guint
7288meta_theme_earliest_version_with_button (MetaButtonType type)
7289{
7290 switch (type)
7291 {
7292 case META_BUTTON_TYPE_CLOSE:
7293 case META_BUTTON_TYPE_MAXIMIZE:
7294 case META_BUTTON_TYPE_MINIMIZE:
7295 case META_BUTTON_TYPE_MENU:
7296 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
7297 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
7298 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
7299 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
7300 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
7301 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
7302 return 1000;
7303
7304 case META_BUTTON_TYPE_SHADE:
7305 case META_BUTTON_TYPE_ABOVE:
7306 case META_BUTTON_TYPE_STICK:
7307 case META_BUTTON_TYPE_UNSHADE:
7308 case META_BUTTON_TYPE_UNABOVE:
7309 case META_BUTTON_TYPE_UNSTICK:
7310 return 2000;
7311
7312 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
7313 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
7314 return 3003;
7315
7316 case META_BUTTON_TYPE_APPMENU:
7317 return 3005;
7318
7319 default:
7320 meta_warning("Unknown button %d\n", type);
7321 return 1000;
7322 }
7323}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-79e718.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-79e718.html new file mode 100644 index 00000000..4c485c20 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-79e718.html @@ -0,0 +1,8003 @@ + + + +ui/theme.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme.c
Warning:line 6859, column 10
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco Theme Rendering */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24/**
25 * \file theme.c Making Marco look pretty
26 *
27 * The window decorations drawn by Marco are described by files on disk
28 * known internally as "themes" (externally as "window border themes" on
29 * http://art.gnome.org/themes/marco/ or "Marco themes"). This file
30 * contains most of the code necessary to support themes; it does not
31 * contain the XML parser, which is in theme-parser.c.
32 *
33 * \bug This is a big file with lots of different subsystems, which might
34 * be better split out into separate files.
35 */
36
37/**
38 * \defgroup tokenizer The theme expression tokenizer
39 *
40 * Themes can use a simple expression language to represent the values of
41 * things. This is the tokeniser used for that language.
42 *
43 * \bug We could remove almost all this code by using GScanner instead,
44 * but we would also have to find every expression in every existing theme
45 * we could and make sure the parse trees were the same.
46 */
47
48/**
49 * \defgroup parser The theme expression parser
50 *
51 * Themes can use a simple expression language to represent the values of
52 * things. This is the parser used for that language.
53 */
54
55#include <config.h>
56#include <glib/gi18n-lib.h>
57
58#include "prefs.h"
59#include "theme.h"
60#include "theme-parser.h"
61#include "util.h"
62#include "gradient.h"
63#include <gtk/gtk.h>
64#include <string.h>
65#include <stdlib.h>
66#define __USE_XOPEN
67#include <math.h>
68
69#define GDK_COLOR_RGBA(color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
\
70 ((guint32) (0xff | \
71 ((int)((color).red * 255) << 24) | \
72 ((int)((color).green * 255) << 16) | \
73 ((int)((color).blue * 255) << 8)))
74
75#define GDK_COLOR_RGB(color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
\
76 ((guint32) (((int)((color).red * 255) << 16) | \
77 ((int)((color).green * 255) << 8) | \
78 ((int)((color).blue * 255))))
79
80#define DEBUG_FILL_STRUCT(s)memset ((s), 0xef, sizeof (*(s))) memset ((s), 0xef, sizeof (*(s)))
81#define CLAMP_UCHAR(v)((guchar) ((((((int)v)) > ((int)255)) ? ((int)255) : (((((
int)v)) < ((int)0)) ? ((int)0) : (((int)v))))))
((guchar) (CLAMP (((int)v), (int)0, (int)255)(((((int)v)) > ((int)255)) ? ((int)255) : (((((int)v)) <
((int)0)) ? ((int)0) : (((int)v))))
))
82#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
83
84static void gtk_style_shade (GdkRGBA *a,
85 GdkRGBA *b,
86 gdouble k);
87static void rgb_to_hls (gdouble *r,
88 gdouble *g,
89 gdouble *b);
90static void hls_to_rgb (gdouble *h,
91 gdouble *l,
92 gdouble *s);
93
94/**
95 * The current theme. (Themes are singleton.)
96 */
97static MetaTheme *meta_current_theme = NULL((void*)0);
98
99static cairo_surface_t *
100scale_surface (cairo_surface_t *surface,
101 gdouble old_width,
102 gdouble old_height,
103 gdouble new_width,
104 gdouble new_height,
105 gboolean vertical_stripes,
106 gboolean horizontal_stripes)
107{
108 gdouble scale_x;
109 gdouble scale_y;
110 cairo_content_t content;
111 gdouble width;
112 gdouble height;
113 cairo_surface_t *scaled;
114 cairo_t *cr;
115
116 scale_x = new_width / old_width;
117 scale_y = new_height / old_height;
118
119 if (horizontal_stripes && !vertical_stripes)
120 {
121 new_width = old_width;
122 scale_x = 1.0;
123 }
124 else if (vertical_stripes && !horizontal_stripes)
125 {
126 new_height = old_height;
127 scale_y = 1.0;
128 }
129
130 content = CAIRO_CONTENT_COLOR_ALPHA;
131 width = ceil (new_width);
132 height = ceil (new_height);
133
134 scaled = cairo_surface_create_similar (surface, content, (int) width, (int) height);
135 cr = cairo_create (scaled);
136
137 cairo_scale (cr, scale_x, scale_y);
138 cairo_set_source_surface (cr, surface, 0, 0);
139
140 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
141
142 cairo_paint (cr);
143 cairo_destroy (cr);
144
145 return scaled;
146}
147
148static cairo_surface_t *
149get_surface_from_pixbuf (GdkPixbuf *pixbuf,
150 MetaImageFillType fill_type,
151 gdouble width,
152 gdouble height,
153 gboolean vertical_stripes,
154 gboolean horizontal_stripes)
155{
156 gdouble pixbuf_width;
157 gdouble pixbuf_height;
158 cairo_surface_t *surface;
159 cairo_content_t content;
160 cairo_surface_t *copy;
161 cairo_t *cr;
162
163 pixbuf_width = gdk_pixbuf_get_width (pixbuf);
164 pixbuf_height = gdk_pixbuf_get_height (pixbuf);
165 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL((void*)0));
166
167 if (pixbuf_width == width && pixbuf_height == height)
168 {
169 return surface;
170 }
171
172 if (fill_type != META_IMAGE_FILL_TILE)
173 {
174 cairo_surface_t *scaled;
175
176 scaled = scale_surface (surface, pixbuf_width, pixbuf_height,
177 width, height, vertical_stripes,
178 horizontal_stripes);
179
180 cairo_surface_destroy (surface);
181 surface = scaled;
182 }
183
184 content = CAIRO_CONTENT_COLOR_ALPHA;
185 width = ceil (width);
186 height = ceil (height);
187
188 copy = cairo_surface_create_similar (surface, content, (int) width, (int) height);
189 cr = cairo_create (copy);
190
191 cairo_set_source_surface (cr, surface, 0, 0);
192
193 if (fill_type == META_IMAGE_FILL_TILE ||
194 vertical_stripes || horizontal_stripes)
195 {
196 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
197 }
198
199 cairo_paint (cr);
200 cairo_destroy (cr);
201
202 cairo_surface_destroy (surface);
203
204 return copy;
205}
206
207static GdkPixbuf *
208colorize_pixbuf (GdkPixbuf *orig,
209 GdkRGBA *new_color)
210{
211 GdkPixbuf *pixbuf;
212 double intensity;
213 int x, y;
214 const guchar *src;
215 guchar *dest;
216 int orig_rowstride;
217 int dest_rowstride;
218 int width, height;
219 gboolean has_alpha;
220 const guchar *src_pixels;
221 guchar *dest_pixels;
222
223 pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
224 gdk_pixbuf_get_bits_per_sample (orig),
225 gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
226
227 if (pixbuf == NULL((void*)0))
228 return NULL((void*)0);
229
230 orig_rowstride = gdk_pixbuf_get_rowstride (orig);
231 dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
232 width = gdk_pixbuf_get_width (pixbuf);
233 height = gdk_pixbuf_get_height (pixbuf);
234 has_alpha = gdk_pixbuf_get_has_alpha (orig);
235 src_pixels = gdk_pixbuf_get_pixels (orig);
236 dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
237
238 for (y = 0; y < height; y++)
239 {
240 src = src_pixels + y * orig_rowstride;
241 dest = dest_pixels + y * dest_rowstride;
242
243 for (x = 0; x < width; x++)
244 {
245 double dr, dg, db;
246
247 intensity = INTENSITY (src[0], src[1], src[2])((src[0]) * 0.30 + (src[1]) * 0.59 + (src[2]) * 0.11) / 255.0;
248
249 if (intensity <= 0.5)
250 {
251 /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
252 dr = new_color->red * intensity * 2.0;
253 dg = new_color->green * intensity * 2.0;
254 db = new_color->blue * intensity * 2.0;
255 }
256 else
257 {
258 /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
259 dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
260 dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
261 db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
262 }
263
264 dest[0] = CLAMP_UCHAR (255 * dr)((guchar) ((((((int)255 * dr)) > ((int)255)) ? ((int)255) :
(((((int)255 * dr)) < ((int)0)) ? ((int)0) : (((int)255 *
dr))))))
;
265 dest[1] = CLAMP_UCHAR (255 * dg)((guchar) ((((((int)255 * dg)) > ((int)255)) ? ((int)255) :
(((((int)255 * dg)) < ((int)0)) ? ((int)0) : (((int)255 *
dg))))))
;
266 dest[2] = CLAMP_UCHAR (255 * db)((guchar) ((((((int)255 * db)) > ((int)255)) ? ((int)255) :
(((((int)255 * db)) < ((int)0)) ? ((int)0) : (((int)255 *
db))))))
;
267
268 if (has_alpha)
269 {
270 dest[3] = src[3];
271 src += 4;
272 dest += 4;
273 }
274 else
275 {
276 src += 3;
277 dest += 3;
278 }
279 }
280 }
281
282 return pixbuf;
283}
284
285static void
286color_composite (const GdkRGBA *bg,
287 const GdkRGBA *fg,
288 double alpha,
289 GdkRGBA *color)
290{
291 *color = *bg;
292 color->red = color->red + (fg->red - color->red) * alpha;
293 color->green = color->green + (fg->green - color->green) * alpha;
294 color->blue = color->blue + (fg->blue - color->blue) * alpha;
295}
296
297/**
298 * Sets all the fields of a border to dummy values.
299 *
300 * \param border The border whose fields should be reset.
301 */
302static void
303init_border (GtkBorder *border)
304{
305 border->top = -1;
306 border->bottom = -1;
307 border->left = -1;
308 border->right = -1;
309}
310
311/**
312 * Creates a new, empty MetaFrameLayout. The fields will be set to dummy
313 * values.
314 *
315 * \return The newly created MetaFrameLayout.
316 */
317MetaFrameLayout*
318meta_frame_layout_new (void)
319{
320 MetaFrameLayout *layout;
321
322 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
323
324 layout->refcount = 1;
325
326 /* Fill with -1 values to detect invalid themes */
327 layout->left_width = -1;
328 layout->right_width = -1;
329 layout->bottom_height = -1;
330
331 layout->invisible_border.left = 10;
332 layout->invisible_border.right = 10;
333 layout->invisible_border.bottom = 10;
334 layout->invisible_border.top = 10;
335
336 init_border (&layout->title_border);
337
338 layout->title_vertical_pad = -1;
339
340 layout->right_titlebar_edge = -1;
341 layout->left_titlebar_edge = -1;
342
343 layout->button_sizing = META_BUTTON_SIZING_LAST;
344 layout->button_aspect = 1.0;
345 layout->button_width = -1;
346 layout->button_height = -1;
347
348 layout->has_title = TRUE(!(0));
349 layout->title_scale = 1.0;
350
351 init_border (&layout->button_border);
352
353 return layout;
354}
355
356/**
357 *
358 */
359static gboolean
360validate_border (const GtkBorder *border,
361 const char **bad)
362{
363 *bad = NULL((void*)0);
364
365 if (border->top < 0)
366 *bad = _("top")((char *) g_dgettext ("marco", "top"));
367 else if (border->bottom < 0)
368 *bad = _("bottom")((char *) g_dgettext ("marco", "bottom"));
369 else if (border->left < 0)
370 *bad = _("left")((char *) g_dgettext ("marco", "left"));
371 else if (border->right < 0)
372 *bad = _("right")((char *) g_dgettext ("marco", "right"));
373
374 return *bad == NULL((void*)0);
375}
376
377/**
378 * Ensures that the theme supplied a particular dimension. When a
379 * MetaFrameLayout is created, all its integer fields are set to -1
380 * by meta_frame_layout_new(). After an instance of this type
381 * should have been initialised, this function checks that
382 * a given field is not still at -1. It is never called directly, but
383 * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER
384 * macros.
385 *
386 * \param val The value to check
387 * \param name The name to use in the error message
388 * \param[out] error Set to an error if val was not initialised
389 */
390static gboolean
391validate_geometry_value (int val,
392 const char *name,
393 GError **error)
394{
395 if (val < 0)
396 {
397 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
398 META_THEME_ERROR_FRAME_GEOMETRY,
399 _("frame geometry does not specify \"%s\" dimension")((char *) g_dgettext ("marco", "frame geometry does not specify \"%s\" dimension"
))
,
400 name);
401 return FALSE(0);
402 }
403 else
404 return TRUE(!(0));
405}
406
407static gboolean
408validate_geometry_border (const GtkBorder *border,
409 const char *name,
410 GError **error)
411{
412 const char *bad;
413
414 if (!validate_border (border, &bad))
415 {
416 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
417 META_THEME_ERROR_FRAME_GEOMETRY,
418 _("frame geometry does not specify dimension \"%s\" for border \"%s\"")((char *) g_dgettext ("marco", "frame geometry does not specify dimension \"%s\" for border \"%s\""
))
,
419 bad, name);
420 return FALSE(0);
421 }
422 else
423 return TRUE(!(0));
424}
425
426gboolean
427meta_frame_layout_validate (const MetaFrameLayout *layout,
428 GError **error)
429{
430 g_return_val_if_fail (layout != NULL, FALSE)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
((0)); } } while (0)
;
431
432#define CHECK_GEOMETRY_VALUE(vname)if (!validate_geometry_value (layout->vname, "vname", error
)) return (0)
if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE(0)
433
434#define CHECK_GEOMETRY_BORDER(bname)if (!validate_geometry_border (&layout->bname, "bname"
, error)) return (0)
if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE(0)
435
436 CHECK_GEOMETRY_VALUE (left_width)if (!validate_geometry_value (layout->left_width, "left_width"
, error)) return (0)
;
437 CHECK_GEOMETRY_VALUE (right_width)if (!validate_geometry_value (layout->right_width, "right_width"
, error)) return (0)
;
438 CHECK_GEOMETRY_VALUE (bottom_height)if (!validate_geometry_value (layout->bottom_height, "bottom_height"
, error)) return (0)
;
439
440 CHECK_GEOMETRY_BORDER (title_border)if (!validate_geometry_border (&layout->title_border, "title_border"
, error)) return (0)
;
441
442 CHECK_GEOMETRY_VALUE (title_vertical_pad)if (!validate_geometry_value (layout->title_vertical_pad, "title_vertical_pad"
, error)) return (0)
;
443
444 CHECK_GEOMETRY_VALUE (right_titlebar_edge)if (!validate_geometry_value (layout->right_titlebar_edge,
"right_titlebar_edge", error)) return (0)
;
445 CHECK_GEOMETRY_VALUE (left_titlebar_edge)if (!validate_geometry_value (layout->left_titlebar_edge, "left_titlebar_edge"
, error)) return (0)
;
446
447 switch (layout->button_sizing)
448 {
449 case META_BUTTON_SIZING_ASPECT:
450 if (layout->button_aspect < (0.1) ||
451 layout->button_aspect > (15.0))
452 {
453 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
454 META_THEME_ERROR_FRAME_GEOMETRY,
455 _("Button aspect ratio %g is not reasonable")((char *) g_dgettext ("marco", "Button aspect ratio %g is not reasonable"
))
,
456 layout->button_aspect);
457 return FALSE(0);
458 }
459 break;
460 case META_BUTTON_SIZING_FIXED:
461 CHECK_GEOMETRY_VALUE (button_width)if (!validate_geometry_value (layout->button_width, "button_width"
, error)) return (0)
;
462 CHECK_GEOMETRY_VALUE (button_height)if (!validate_geometry_value (layout->button_height, "button_height"
, error)) return (0)
;
463 break;
464 case META_BUTTON_SIZING_LAST:
465 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
466 META_THEME_ERROR_FRAME_GEOMETRY,
467 _("Frame geometry does not specify size of buttons")((char *) g_dgettext ("marco", "Frame geometry does not specify size of buttons"
))
);
468 return FALSE(0);
469 }
470
471 CHECK_GEOMETRY_BORDER (button_border)if (!validate_geometry_border (&layout->button_border,
"button_border", error)) return (0)
;
472
473 return TRUE(!(0));
474}
475
476MetaFrameLayout*
477meta_frame_layout_copy (const MetaFrameLayout *src)
478{
479 MetaFrameLayout *layout;
480
481 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
482
483 *layout = *src;
484
485 layout->refcount = 1;
486
487 return layout;
488}
489
490void
491meta_frame_layout_ref (MetaFrameLayout *layout)
492{
493 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
494
495 layout->refcount += 1;
496}
497
498void
499meta_frame_layout_unref (MetaFrameLayout *layout)
500{
501 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
502 g_return_if_fail (layout->refcount > 0)do { if ((layout->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout->refcount > 0"
); return; } } while (0)
;
503
504 layout->refcount -= 1;
505
506 if (layout->refcount == 0)
507 {
508 DEBUG_FILL_STRUCT (layout)memset ((layout), 0xef, sizeof (*(layout)));
509 g_free (layout);
510 }
511}
512
513void
514meta_frame_layout_get_borders (const MetaFrameLayout *layout,
515 int text_height,
516 MetaFrameFlags flags,
517 MetaFrameBorders *borders)
518{
519 int buttons_height, title_height;
520
521 meta_frame_borders_clear (borders);
522
523 /* For a full-screen window, we don't have any borders, visible or not. */
524 if (flags & META_FRAME_FULLSCREEN)
525 return;
526
527 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
528
529 if (!layout->has_title)
530 text_height = 0;
531
532 buttons_height = layout->button_height +
533 layout->button_border.top + layout->button_border.bottom;
534 title_height = text_height +
535 layout->title_vertical_pad +
536 layout->title_border.top + layout->title_border.bottom;
537
538 borders->visible.top = MAX (buttons_height, title_height)(((buttons_height) > (title_height)) ? (buttons_height) : (
title_height))
;
539 borders->visible.left = layout->left_width;
540 borders->visible.right = layout->right_width;
541 borders->visible.bottom = layout->bottom_height;
542
543 if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
544 {
545 borders->invisible.left = layout->invisible_border.left;
546 borders->invisible.right = layout->invisible_border.right;
547 }
548
549 if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
550 {
551 borders->invisible.bottom = layout->invisible_border.bottom;
552 borders->invisible.top = layout->invisible_border.top;
553 }
554
555 if (flags & META_FRAME_SHADED)
556 borders->visible.bottom = borders->invisible.bottom = 0;
557
558 borders->total.left = borders->invisible.left + borders->visible.left;
559 borders->total.right = borders->invisible.right + borders->visible.right;
560 borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
561 borders->total.top = borders->invisible.top + borders->visible.top;
562}
563
564static MetaButtonType
565map_button_function_to_type (MetaButtonFunction function)
566{
567 switch (function)
568 {
569 case META_BUTTON_FUNCTION_SHADE:
570 return META_BUTTON_TYPE_SHADE;
571 case META_BUTTON_FUNCTION_ABOVE:
572 return META_BUTTON_TYPE_ABOVE;
573 case META_BUTTON_FUNCTION_STICK:
574 return META_BUTTON_TYPE_STICK;
575 case META_BUTTON_FUNCTION_UNSHADE:
576 return META_BUTTON_TYPE_UNSHADE;
577 case META_BUTTON_FUNCTION_UNABOVE:
578 return META_BUTTON_TYPE_UNABOVE;
579 case META_BUTTON_FUNCTION_UNSTICK:
580 return META_BUTTON_TYPE_UNSTICK;
581 case META_BUTTON_FUNCTION_MENU:
582 return META_BUTTON_TYPE_MENU;
583 case META_BUTTON_FUNCTION_APPMENU:
584 return META_BUTTON_TYPE_APPMENU;
585 case META_BUTTON_FUNCTION_MINIMIZE:
586 return META_BUTTON_TYPE_MINIMIZE;
587 case META_BUTTON_FUNCTION_MAXIMIZE:
588 return META_BUTTON_TYPE_MAXIMIZE;
589 case META_BUTTON_FUNCTION_CLOSE:
590 return META_BUTTON_TYPE_CLOSE;
591 case META_BUTTON_FUNCTION_LAST:
592 return META_BUTTON_TYPE_LAST;
593 }
594
595 return META_BUTTON_TYPE_LAST;
596}
597
598static MetaButtonSpace*
599rect_for_function (MetaFrameGeometry *fgeom,
600 MetaFrameFlags flags,
601 MetaButtonFunction function,
602 MetaTheme *theme)
603{
604
605 /* Firstly, check version-specific things. */
606
607 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
608 {
609 switch (function)
610 {
611 case META_BUTTON_FUNCTION_SHADE:
612 if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
613 return &fgeom->shade_rect;
614 else
615 return NULL((void*)0);
616 case META_BUTTON_FUNCTION_ABOVE:
617 if (!(flags & META_FRAME_ABOVE))
618 return &fgeom->above_rect;
619 else
620 return NULL((void*)0);
621 case META_BUTTON_FUNCTION_STICK:
622 if (!(flags & META_FRAME_STUCK))
623 return &fgeom->stick_rect;
624 else
625 return NULL((void*)0);
626 case META_BUTTON_FUNCTION_UNSHADE:
627 if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
628 return &fgeom->unshade_rect;
629 else
630 return NULL((void*)0);
631 case META_BUTTON_FUNCTION_UNABOVE:
632 if (flags & META_FRAME_ABOVE)
633 return &fgeom->unabove_rect;
634 else
635 return NULL((void*)0);
636 case META_BUTTON_FUNCTION_UNSTICK:
637 if (flags & META_FRAME_STUCK)
638 return &fgeom->unstick_rect;
639 default:
640 /* just go on to the next switch block */;
641 }
642 }
643
644 /* now consider the buttons which exist in all versions */
645
646 switch (function)
647 {
648 case META_BUTTON_FUNCTION_MENU:
649 if (flags & META_FRAME_ALLOWS_MENU)
650 return &fgeom->menu_rect;
651 else
652 return NULL((void*)0);
653 case META_BUTTON_FUNCTION_APPMENU:
654 if (flags & META_FRAME_ALLOWS_APPMENU)
655 return &fgeom->appmenu_rect;
656 else
657 return NULL((void*)0);
658 case META_BUTTON_FUNCTION_MINIMIZE:
659 if (flags & META_FRAME_ALLOWS_MINIMIZE)
660 return &fgeom->min_rect;
661 else
662 return NULL((void*)0);
663 case META_BUTTON_FUNCTION_MAXIMIZE:
664 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
665 return &fgeom->max_rect;
666 else
667 return NULL((void*)0);
668 case META_BUTTON_FUNCTION_CLOSE:
669 if (flags & META_FRAME_ALLOWS_DELETE)
670 return &fgeom->close_rect;
671 else
672 return NULL((void*)0);
673 case META_BUTTON_FUNCTION_STICK:
674 case META_BUTTON_FUNCTION_SHADE:
675 case META_BUTTON_FUNCTION_ABOVE:
676 case META_BUTTON_FUNCTION_UNSTICK:
677 case META_BUTTON_FUNCTION_UNSHADE:
678 case META_BUTTON_FUNCTION_UNABOVE:
679 /* we are being asked for a >v1 button which hasn't been handled yet,
680 * so obviously we're not in a theme which supports that version.
681 * therefore, we don't show the button. return NULL and all will
682 * be well.
683 */
684 return NULL((void*)0);
685
686 case META_BUTTON_FUNCTION_LAST:
687 return NULL((void*)0);
688 }
689
690 return NULL((void*)0);
691}
692
693static gboolean
694strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
695 GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
696 int *n_rects,
697 MetaButtonSpace *to_strip)
698{
699 int i;
700
701 i = 0;
702 while (i < *n_rects)
703 {
704 if (func_rects[i] == to_strip)
705 {
706 *n_rects -= 1;
707
708 /* shift the other rects back in the array */
709 while (i < *n_rects)
710 {
711 func_rects[i] = func_rects[i+1];
712 bg_rects[i] = bg_rects[i+1];
713
714 ++i;
715 }
716
717 func_rects[i] = NULL((void*)0);
718 bg_rects[i] = NULL((void*)0);
719
720 return TRUE(!(0));
721 }
722
723 ++i;
724 }
725
726 return FALSE(0); /* did not strip anything */
727}
728
729void
730meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
731 int text_height,
732 MetaFrameFlags flags,
733 int client_width,
734 int client_height,
735 const MetaButtonLayout *button_layout,
736 MetaFrameGeometry *fgeom,
737 MetaTheme *theme)
738{
739 int i, n_left, n_right, n_left_spacers, n_right_spacers;
740 int x;
741 int button_y;
742 int title_right_edge;
743 int width, height;
744 int button_width, button_height;
745 int min_size_for_rounding;
746
747 /* the left/right rects in order; the max # of rects
748 * is the number of button functions
749 */
750 MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
751 MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
752 GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
753 gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
754 GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
755 gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
756
757 MetaFrameBorders borders;
758
759 meta_frame_layout_get_borders (layout, text_height,
760 flags,
761 &borders);
762
763 fgeom->borders = borders;
764
765 width = client_width + borders.total.left + borders.total.right;
766
767 height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
768 borders.total.top + borders.total.bottom;
769
770 fgeom->width = width;
771 fgeom->height = height;
772
773 fgeom->top_titlebar_edge = layout->title_border.top;
774 fgeom->bottom_titlebar_edge = layout->title_border.bottom;
775 fgeom->left_titlebar_edge = layout->left_titlebar_edge;
776 fgeom->right_titlebar_edge = layout->right_titlebar_edge;
777
778 switch (layout->button_sizing)
779 {
780 case META_BUTTON_SIZING_ASPECT:
781 button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
782 button_width = (int) (((double) button_height) / layout->button_aspect);
783 break;
784 case META_BUTTON_SIZING_FIXED:
785 button_width = layout->button_width;
786 button_height = layout->button_height;
787 break;
788 case META_BUTTON_SIZING_LAST:
789 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 789, ((
const char*) (__func__)), ((void*)0)); } while (0)
;
790 default:
791 button_width = -1;
792 button_height = -1;
793 }
794
795 /* FIXME all this code sort of pretends that duplicate buttons
796 * with the same function are allowed, but that breaks the
797 * code in frames.c, so isn't really allowed right now.
798 * Would need left_close_rect, right_close_rect, etc.
799 */
800
801 /* Init all button rects to 0, lame hack */
802 memset (ADDRESS_OF_BUTTON_RECTS (fgeom)(((char*)(fgeom)) + ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
, '\0',
803 LENGTH_OF_BUTTON_RECTS(((glong) __builtin_offsetof(MetaFrameGeometry, right_single_background
)) + sizeof (GdkRectangle) - ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
);
804
805 n_left = 0;
806 n_right = 0;
807 n_left_spacers = 0;
808 n_right_spacers = 0;
809
810 if (!layout->hide_buttons)
811 {
812 /* Try to fill in rects */
813 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
814 {
815 left_func_rects[n_left] = rect_for_function (fgeom, flags,
816 button_layout->left_buttons[i],
817 theme);
818 if (left_func_rects[n_left] != NULL((void*)0))
819 {
820 left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
821 if (button_layout->left_buttons_has_spacer[i])
822 ++n_left_spacers;
823
824 ++n_left;
825 }
826 }
827
828 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
829 {
830 right_func_rects[n_right] = rect_for_function (fgeom, flags,
831 button_layout->right_buttons[i],
832 theme);
833 if (right_func_rects[n_right] != NULL((void*)0))
834 {
835 right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
836 if (button_layout->right_buttons_has_spacer[i])
837 ++n_right_spacers;
838
839 ++n_right;
840 }
841 }
842 }
843
844 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST; i++)
845 {
846 left_bg_rects[i] = NULL((void*)0);
847 right_bg_rects[i] = NULL((void*)0);
848 }
849
850 for (i = 0; i < n_left; i++)
851 {
852 if (n_left == 1)
853 left_bg_rects[i] = &fgeom->left_single_background;
854 else if (i == 0)
855 left_bg_rects[i] = &fgeom->left_left_background;
856 else if (i == (n_left - 1))
857 left_bg_rects[i] = &fgeom->left_right_background;
858 else
859 left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
860 }
861
862 for (i = 0; i < n_right; i++)
863 {
864 if (n_right == 1)
865 right_bg_rects[i] = &fgeom->right_single_background;
866 else if (i == (n_right - 1))
867 right_bg_rects[i] = &fgeom->right_right_background;
868 else if (i == 0)
869 right_bg_rects[i] = &fgeom->right_left_background;
870 else
871 right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
872 }
873
874 /* Be sure buttons fit */
875 while (n_left > 0 || n_right > 0)
876 {
877 int space_used_by_buttons;
878 int space_available;
879
880 space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
881
882 space_used_by_buttons = 0;
883
884 space_used_by_buttons += button_width * n_left;
885 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_left_spacers));
886 space_used_by_buttons += layout->button_border.left * n_left;
887 space_used_by_buttons += layout->button_border.right * n_left;
888
889 space_used_by_buttons += button_width * n_right;
890 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_right_spacers));
891 space_used_by_buttons += layout->button_border.left * n_right;
892 space_used_by_buttons += layout->button_border.right * n_right;
893
894 if (space_used_by_buttons <= space_available)
895 break; /* Everything fits, bail out */
896
897 /* First try to remove separators */
898 if (n_left_spacers > 0)
899 {
900 left_buttons_has_spacer[--n_left_spacers] = FALSE(0);
901 continue;
902 }
903 else if (n_right_spacers > 0)
904 {
905 right_buttons_has_spacer[--n_right_spacers] = FALSE(0);
906 continue;
907 }
908
909 /* Otherwise we need to shave out a button. Shave
910 * above, stick, shade, min, max, close, then menu (menu is most useful);
911 * prefer the default button locations.
912 */
913 if (strip_button (left_func_rects, left_bg_rects,
914 &n_left, &fgeom->above_rect))
915 continue;
916 else if (strip_button (right_func_rects, right_bg_rects,
917 &n_right, &fgeom->above_rect))
918 continue;
919 else if (strip_button (left_func_rects, left_bg_rects,
920 &n_left, &fgeom->stick_rect))
921 continue;
922 else if (strip_button (right_func_rects, right_bg_rects,
923 &n_right, &fgeom->stick_rect))
924 continue;
925 else if (strip_button (left_func_rects, left_bg_rects,
926 &n_left, &fgeom->shade_rect))
927 continue;
928 else if (strip_button (right_func_rects, right_bg_rects,
929 &n_right, &fgeom->shade_rect))
930 continue;
931 else if (strip_button (left_func_rects, left_bg_rects,
932 &n_left, &fgeom->min_rect))
933 continue;
934 else if (strip_button (right_func_rects, right_bg_rects,
935 &n_right, &fgeom->min_rect))
936 continue;
937 else if (strip_button (left_func_rects, left_bg_rects,
938 &n_left, &fgeom->max_rect))
939 continue;
940 else if (strip_button (right_func_rects, right_bg_rects,
941 &n_right, &fgeom->max_rect))
942 continue;
943 else if (strip_button (left_func_rects, left_bg_rects,
944 &n_left, &fgeom->close_rect))
945 continue;
946 else if (strip_button (right_func_rects, right_bg_rects,
947 &n_right, &fgeom->close_rect))
948 continue;
949 else if (strip_button (right_func_rects, right_bg_rects,
950 &n_right, &fgeom->menu_rect))
951 continue;
952 else if (strip_button (left_func_rects, left_bg_rects,
953 &n_left, &fgeom->menu_rect))
954 continue;
955 else if (strip_button (right_func_rects, right_bg_rects,
956 &n_right, &fgeom->appmenu_rect))
957 continue;
958 else if (strip_button (left_func_rects, left_bg_rects,
959 &n_left, &fgeom->appmenu_rect))
960 continue;
961 else
962 {
963 meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
964 n_left, n_right);
965 }
966 }
967
968 /* Save the button layout */
969 fgeom->button_layout = *button_layout;
970 fgeom->n_left_buttons = n_left;
971 fgeom->n_right_buttons = n_right;
972
973 /* center buttons vertically */
974 button_y = (borders.visible.top -
975 (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + borders.invisible.top;
976
977 /* right edge of farthest-right button */
978 x = width - layout->right_titlebar_edge - borders.invisible.right;
979
980 i = n_right - 1;
981 while (i >= 0)
982 {
983 MetaButtonSpace *rect;
984
985 if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
986 break;
987
988 rect = right_func_rects[i];
989 rect->visible.x = x - layout->button_border.right - button_width;
990 if (right_buttons_has_spacer[i])
991 rect->visible.x -= (int) (0.75 * (double) button_width);
992
993 rect->visible.y = button_y;
994 rect->visible.width = button_width;
995 rect->visible.height = button_height;
996
997 if (flags & META_FRAME_MAXIMIZED ||
998 flags & META_FRAME_TILED_LEFT ||
999 flags & META_FRAME_TILED_RIGHT)
1000 {
1001 rect->clickable.x = rect->visible.x;
1002 rect->clickable.y = rect->visible.y;
1003 rect->clickable.width = button_width;
1004 rect->clickable.height = button_height;
1005
1006 if (i == n_right - 1)
1007 rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
1008
1009 }
1010 else
1011 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1012
1013 *(right_bg_rects[i]) = rect->visible;
1014
1015 x = rect->visible.x - layout->button_border.left;
1016
1017 --i;
1018 }
1019
1020 /* save right edge of titlebar for later use */
1021 title_right_edge = x - layout->title_border.right;
1022
1023 /* Now x changes to be position from the left and we go through
1024 * the left-side buttons
1025 */
1026 x = layout->left_titlebar_edge + borders.invisible.left;
1027 for (i = 0; i < n_left; i++)
1028 {
1029 MetaButtonSpace *rect;
1030
1031 rect = left_func_rects[i];
1032
1033 rect->visible.x = x + layout->button_border.left;
1034 rect->visible.y = button_y;
1035 rect->visible.width = button_width;
1036 rect->visible.height = button_height;
1037
1038 if (flags & META_FRAME_MAXIMIZED)
1039 {
1040 rect->clickable.x = rect->visible.x;
1041 rect->clickable.y = rect->visible.y;
1042 rect->clickable.width = button_width;
1043 rect->clickable.height = button_height;
1044 }
1045 else
1046 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1047
1048 x = rect->visible.x + rect->visible.width + layout->button_border.right;
1049 if (left_buttons_has_spacer[i])
1050 x += (int) (0.75 * (double) button_width);
1051
1052 *(left_bg_rects[i]) = rect->visible;
1053 }
1054
1055 /* We always fill as much vertical space as possible with title rect,
1056 * rather than centering it like the buttons
1057 */
1058 fgeom->title_rect.x = x + layout->title_border.left;
1059 fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
1060 fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
1061 fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
1062
1063 /* Nuke title if it won't fit */
1064 if (fgeom->title_rect.width < 0 ||
1065 fgeom->title_rect.height < 0)
1066 {
1067 fgeom->title_rect.width = 0;
1068 fgeom->title_rect.height = 0;
1069 }
1070
1071 if (flags & META_FRAME_SHADED)
1072 min_size_for_rounding = 0;
1073 else
1074 min_size_for_rounding = 5;
1075
1076 fgeom->top_left_corner_rounded_radius = 0;
1077 fgeom->top_right_corner_rounded_radius = 0;
1078 fgeom->bottom_left_corner_rounded_radius = 0;
1079 fgeom->bottom_right_corner_rounded_radius = 0;
1080
1081 if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
1082 fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
1083 if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
1084 fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
1085
1086 if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
1087 fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
1088 if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
1089 fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
1090}
1091
1092MetaGradientSpec*
1093meta_gradient_spec_new (MetaGradientType type)
1094{
1095 MetaGradientSpec *spec;
1096
1097 spec = g_new (MetaGradientSpec, 1)((MetaGradientSpec *) g_malloc_n ((1), sizeof (MetaGradientSpec
)))
;
1098
1099 spec->type = type;
1100 spec->color_specs = NULL((void*)0);
1101
1102 return spec;
1103}
1104
1105static cairo_pattern_t *
1106create_cairo_pattern_from_gradient_spec (const MetaGradientSpec *spec,
1107 const MetaAlphaGradientSpec *alpha_spec,
1108 GtkStyleContext *context)
1109{
1110 gint n_colors;
1111 cairo_pattern_t *pattern;
1112 GSList *tmp;
1113 gint i;
1114
1115 n_colors = g_slist_length (spec->color_specs);
1116 if (n_colors == 0)
1117 return NULL((void*)0);
1118
1119 if (alpha_spec != NULL((void*)0) && alpha_spec->n_alphas != 1)
1120 g_assert (n_colors == alpha_spec->n_alphas)do { if (n_colors == alpha_spec->n_alphas) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1120, ((const char*) (__func__)), "n_colors == alpha_spec->n_alphas"
); } while (0)
;
1121
1122 if (spec->type == META_GRADIENT_HORIZONTAL)
1123 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1124 else if (spec->type == META_GRADIENT_VERTICAL)
1125 pattern = cairo_pattern_create_linear (0, 0, 0, 1);
1126 else if (spec->type == META_GRADIENT_DIAGONAL)
1127 pattern = cairo_pattern_create_linear (0, 0, 1, 1);
1128 else
1129 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1129, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1130
1131 i = 0;
1132 tmp = spec->color_specs;
1133 while (tmp != NULL((void*)0))
1134 {
1135 GdkRGBA color;
1136
1137 meta_color_spec_render (tmp->data, context, &color);
1138
1139 if (alpha_spec != NULL((void*)0))
1140 {
1141 gdouble alpha;
1142
1143 if (alpha_spec->n_alphas == 1)
1144 alpha = alpha_spec->alphas[0] / 255.0;
1145 else
1146 alpha = alpha_spec->alphas[i] / 255.0;
1147
1148 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_colors - 1),
1149 color.red, color.green, color.blue,
1150 alpha);
1151 }
1152 else
1153 cairo_pattern_add_color_stop_rgb (pattern, i / (gfloat) (n_colors - 1),
1154 color.red, color.green, color.blue);
1155
1156 tmp = tmp->next;
1157 ++i;
1158 }
1159
1160 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1161 {
1162 cairo_pattern_destroy (pattern);
1163 return NULL((void*)0);
1164 }
1165
1166 return pattern;
1167}
1168
1169static void
1170free_color_spec (gpointer spec, gpointer user_data)
1171{
1172 meta_color_spec_free (spec);
1173}
1174
1175void
1176meta_gradient_spec_free (MetaGradientSpec *spec)
1177{
1178 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1179
1180 g_slist_foreach (spec->color_specs, free_color_spec, NULL((void*)0));
1181 g_slist_free (spec->color_specs);
1182
1183 DEBUG_FILL_STRUCT (spec)memset ((spec), 0xef, sizeof (*(spec)));
1184 g_free (spec);
1185}
1186
1187void
1188meta_gradient_spec_render (const MetaGradientSpec *spec,
1189 const MetaAlphaGradientSpec *alpha_spec,
1190 cairo_t *cr,
1191 GtkStyleContext *context,
1192 gint x,
1193 gint y,
1194 gint width,
1195 gint height)
1196{
1197 cairo_pattern_t *pattern;
1198
1199 pattern = create_cairo_pattern_from_gradient_spec (spec, alpha_spec, context);
1200 if (pattern == NULL((void*)0))
1201 return;
1202
1203 cairo_save (cr);
1204
1205 cairo_rectangle (cr, x, y, width, height);
1206
1207 cairo_translate (cr, x, y);
1208 cairo_scale (cr, width, height);
1209
1210 cairo_set_source (cr, pattern);
1211 cairo_fill (cr);
1212 cairo_pattern_destroy (pattern);
1213
1214 cairo_restore (cr);
1215}
1216
1217gboolean
1218meta_gradient_spec_validate (MetaGradientSpec *spec,
1219 GError **error)
1220{
1221 g_return_val_if_fail (spec != NULL, FALSE)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
((0)); } } while (0)
;
1222
1223 if (g_slist_length (spec->color_specs) < 2)
1224 {
1225 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1226 META_THEME_ERROR_FAILED,
1227 _("Gradients should have at least two colors")((char *) g_dgettext ("marco", "Gradients should have at least two colors"
))
);
1228 return FALSE(0);
1229 }
1230
1231 return TRUE(!(0));
1232}
1233
1234MetaAlphaGradientSpec*
1235meta_alpha_gradient_spec_new (MetaGradientType type,
1236 int n_alphas)
1237{
1238 MetaAlphaGradientSpec *spec;
1239
1240 g_return_val_if_fail (n_alphas > 0, NULL)do { if ((n_alphas > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_alphas > 0"); return
(((void*)0)); } } while (0)
;
1241
1242 spec = g_new0 (MetaAlphaGradientSpec, 1)((MetaAlphaGradientSpec *) g_malloc0_n ((1), sizeof (MetaAlphaGradientSpec
)))
;
1243
1244 spec->type = type;
1245 spec->alphas = g_new0 (unsigned char, n_alphas)((unsigned char *) g_malloc0_n ((n_alphas), sizeof (unsigned char
)))
;
1246 spec->n_alphas = n_alphas;
1247
1248 return spec;
1249}
1250
1251void
1252meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
1253{
1254 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1255
1256 g_free (spec->alphas);
1257 g_free (spec);
1258}
1259
1260cairo_pattern_t *
1261meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec)
1262{
1263 gint n_alphas;
1264 cairo_pattern_t *pattern;
1265 gint i;
1266
1267 /* Hardcoded in theme-parser.c */
1268 g_assert (spec->type == META_GRADIENT_HORIZONTAL)do { if (spec->type == META_GRADIENT_HORIZONTAL) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1268, ((const char*) (__func__)), "spec->type == META_GRADIENT_HORIZONTAL"
); } while (0)
;
1269
1270 n_alphas = spec->n_alphas;
1271 if (n_alphas == 0)
1272 return NULL((void*)0);
1273
1274 if (n_alphas == 1)
1275 return cairo_pattern_create_rgba (0, 0, 0, spec->alphas[0] / 255.0);
1276
1277 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1278
1279 for (i = 0; i < n_alphas; i++)
1280 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_alphas - 1),
1281 0, 0, 0, spec->alphas[i] / 255.0);
1282
1283 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1284 {
1285 cairo_pattern_destroy (pattern);
1286 return NULL((void*)0);
1287 }
1288
1289 return pattern;
1290}
1291
1292MetaColorSpec*
1293meta_color_spec_new (MetaColorSpecType type)
1294{
1295 MetaColorSpec *spec;
1296 MetaColorSpec dummy;
1297 int size;
1298
1299 size = G_STRUCT_OFFSET (MetaColorSpec, data)((glong) __builtin_offsetof(MetaColorSpec, data));
1300
1301 switch (type)
1302 {
1303 case META_COLOR_SPEC_BASIC:
1304 size += sizeof (dummy.data.basic);
1305 break;
1306
1307 case META_COLOR_SPEC_GTK:
1308 size += sizeof (dummy.data.gtk);
1309 break;
1310
1311 case META_COLOR_SPEC_GTK_CUSTOM:
1312 size += sizeof (dummy.data.gtkcustom);
1313 break;
1314
1315 case META_COLOR_SPEC_BLEND:
1316 size += sizeof (dummy.data.blend);
1317 break;
1318
1319 case META_COLOR_SPEC_SHADE:
1320 size += sizeof (dummy.data.shade);
1321 break;
1322 }
1323
1324 spec = g_malloc0 (size);
1325
1326 spec->type = type;
1327
1328 return spec;
1329}
1330
1331void
1332meta_color_spec_free (MetaColorSpec *spec)
1333{
1334 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1335
1336 switch (spec->type)
1337 {
1338 case META_COLOR_SPEC_BASIC:
1339 DEBUG_FILL_STRUCT (&spec->data.basic)memset ((&spec->data.basic), 0xef, sizeof (*(&spec
->data.basic)))
;
1340 break;
1341
1342 case META_COLOR_SPEC_GTK:
1343 DEBUG_FILL_STRUCT (&spec->data.gtk)memset ((&spec->data.gtk), 0xef, sizeof (*(&spec->
data.gtk)))
;
1344 break;
1345
1346 case META_COLOR_SPEC_GTK_CUSTOM:
1347 if (spec->data.gtkcustom.color_name)
1348 g_free (spec->data.gtkcustom.color_name);
1349 if (spec->data.gtkcustom.fallback)
1350 meta_color_spec_free (spec->data.gtkcustom.fallback);
1351 DEBUG_FILL_STRUCT (&spec->data.gtkcustom)memset ((&spec->data.gtkcustom), 0xef, sizeof (*(&
spec->data.gtkcustom)))
;
1352 break;
1353
1354 case META_COLOR_SPEC_BLEND:
1355 if (spec->data.blend.foreground)
1356 meta_color_spec_free (spec->data.blend.foreground);
1357 if (spec->data.blend.background)
1358 meta_color_spec_free (spec->data.blend.background);
1359 DEBUG_FILL_STRUCT (&spec->data.blend)memset ((&spec->data.blend), 0xef, sizeof (*(&spec
->data.blend)))
;
1360 break;
1361
1362 case META_COLOR_SPEC_SHADE:
1363 if (spec->data.shade.base)
1364 meta_color_spec_free (spec->data.shade.base);
1365 DEBUG_FILL_STRUCT (&spec->data.shade)memset ((&spec->data.shade), 0xef, sizeof (*(&spec
->data.shade)))
;
1366 break;
1367 }
1368
1369 g_free (spec);
1370}
1371
1372MetaColorSpec*
1373meta_color_spec_new_from_string (const char *str,
1374 GError **err)
1375{
1376 MetaColorSpec *spec;
1377
1378 spec = NULL((void*)0);
1379
1380 if (strncmp (str, "gtk:custom", 10) == 0)
1381 {
1382 const char *color_name_start, *fallback_str_start, *end;
1383 char *color_name;
1384 MetaColorSpec *fallback = NULL((void*)0);
1385 static gboolean debug, debug_set = FALSE(0);
1386
1387 if (!debug_set)
1388 {
1389 debug = g_getenv ("MARCO_DISABLE_FALLBACK_COLOR") != NULL((void*)0);
1390 debug_set = TRUE(!(0));
1391 }
1392
1393 if (str[10] != '(')
1394 {
1395 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1396 META_THEME_ERROR_FAILED,
1397 _("GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""
))
,
1398 str);
1399 return NULL((void*)0);
1400 }
1401
1402 color_name_start = str + 11;
1403
1404 fallback_str_start = color_name_start;
1405 while (*fallback_str_start && *fallback_str_start != ',')
1406 {
1407 if (!(g_ascii_isalnum (*fallback_str_start)((g_ascii_table[(guchar) (*fallback_str_start)] & G_ASCII_ALNUM
) != 0)
1408 || *fallback_str_start == '-'
1409 || *fallback_str_start == '_'))
1410 {
1411 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1412 META_THEME_ERROR_FAILED,
1413 _("Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid")((char *) g_dgettext ("marco", "Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid"
))
,
1414 *fallback_str_start);
1415 return NULL((void*)0);
1416 }
1417 fallback_str_start++;
1418 }
1419 fallback_str_start++;
1420
1421 end = strrchr (str, ')');
1422
1423 if (color_name_start == NULL((void*)0) || fallback_str_start == NULL((void*)0) || end == NULL((void*)0))
1424 {
1425 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1426 META_THEME_ERROR_FAILED,
1427 _("Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format"
))
,
1428 str);
1429 return NULL((void*)0);
1430 }
1431
1432 if (!debug)
1433 {
1434 char *fallback_str;
1435 fallback_str = g_strndup (fallback_str_start,
1436 end - fallback_str_start);
1437 fallback = meta_color_spec_new_from_string (fallback_str, err);
1438 g_free (fallback_str);
1439 }
1440 else
1441 {
1442 fallback = meta_color_spec_new_from_string ("pink", err);
1443 }
1444
1445 if (fallback == NULL((void*)0))
1446 return NULL((void*)0);
1447
1448 color_name = g_strndup (color_name_start, fallback_str_start - color_name_start - 1);
1449
1450 spec = meta_color_spec_new (META_COLOR_SPEC_GTK_CUSTOM);
1451 spec->data.gtkcustom.color_name = color_name;
1452 spec->data.gtkcustom.fallback = fallback;
1453 }
1454 else if (strncmp (str, "gtk:", 4) == 0)
1455 {
1456 /* GTK color */
1457 const char *bracket;
1458 const char *end_bracket;
1459 char *tmp;
1460 GtkStateFlags state;
1461 MetaGtkColorComponent component;
1462
1463 bracket = str;
1464 while (*bracket && *bracket != '[')
1465 ++bracket;
1466
1467 if (*bracket == '\0')
1468 {
1469 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1470 META_THEME_ERROR_FAILED,
1471 _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1472 str);
1473 return NULL((void*)0);
1474 }
1475
1476 end_bracket = bracket;
1477 ++end_bracket;
1478 while (*end_bracket && *end_bracket != ']')
1479 ++end_bracket;
1480
1481 if (*end_bracket == '\0')
1482 {
1483 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1484 META_THEME_ERROR_FAILED,
1485 _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1486 str);
1487 return NULL((void*)0);
1488 }
1489
1490 tmp = g_strndup (bracket + 1, end_bracket - bracket - 1);
1491 state = meta_gtk_state_from_string (tmp);
1492 if (((int) state) == -1)
1493 {
1494 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1495 META_THEME_ERROR_FAILED,
1496 _("Did not understand state \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand state \"%s\" in color specification"
))
,
1497 tmp);
1498 g_free (tmp);
1499 return NULL((void*)0);
1500 }
1501 g_free (tmp);
1502
1503 tmp = g_strndup (str + 4, bracket - str - 4);
1504 component = meta_color_component_from_string (tmp);
1505 if (component == META_GTK_COLOR_LAST)
1506 {
1507 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1508 META_THEME_ERROR_FAILED,
1509 _("Did not understand color component \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand color component \"%s\" in color specification"
))
,
1510 tmp);
1511 g_free (tmp);
1512 return NULL((void*)0);
1513 }
1514 g_free (tmp);
1515
1516 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1517 spec->data.gtk.state = state;
1518 spec->data.gtk.component = component;
1519 g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST)do { if (spec->data.gtk.component < META_GTK_COLOR_LAST
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 1519
, ((const char*) (__func__)), "spec->data.gtk.component < META_GTK_COLOR_LAST"
); } while (0)
;
1520 }
1521 else if (strncmp (str, "blend/", 6) == 0)
1522 {
1523 /* blend */
1524 char **split;
1525 double alpha;
1526 char *end;
1527 MetaColorSpec *fg;
1528 MetaColorSpec *bg;
1529
1530 split = g_strsplit (str, "/", 4);
1531
1532 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1533 split[2] == NULL((void*)0) || split[3] == NULL((void*)0))
1534 {
1535 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1536 META_THEME_ERROR_FAILED,
1537 _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"
))
,
1538 str);
1539 g_strfreev (split);
1540 return NULL((void*)0);
1541 }
1542
1543 alpha = g_ascii_strtod (split[3], &end);
1544 if (end == split[3])
1545 {
1546 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1547 META_THEME_ERROR_FAILED,
1548 _("Could not parse alpha value \"%s\" in blended color")((char *) g_dgettext ("marco", "Could not parse alpha value \"%s\" in blended color"
))
,
1549 split[3]);
1550 g_strfreev (split);
1551 return NULL((void*)0);
1552 }
1553
1554 if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6))
1555 {
1556 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1557 META_THEME_ERROR_FAILED,
1558 _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0")((char *) g_dgettext ("marco", "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
))
,
1559 split[3]);
1560 g_strfreev (split);
1561 return NULL((void*)0);
1562 }
1563
1564 fg = NULL((void*)0);
1565 bg = NULL((void*)0);
1566
1567 bg = meta_color_spec_new_from_string (split[1], err);
1568 if (bg == NULL((void*)0))
1569 {
1570 g_strfreev (split);
1571 return NULL((void*)0);
1572 }
1573
1574 fg = meta_color_spec_new_from_string (split[2], err);
1575 if (fg == NULL((void*)0))
1576 {
1577 meta_color_spec_free (bg);
1578 g_strfreev (split);
1579 return NULL((void*)0);
1580 }
1581
1582 g_strfreev (split);
1583
1584 spec = meta_color_spec_new (META_COLOR_SPEC_BLEND);
1585 spec->data.blend.alpha = alpha;
1586 spec->data.blend.background = bg;
1587 spec->data.blend.foreground = fg;
1588 }
1589 else if (strncmp (str, "shade/", 6) == 0)
1590 {
1591 /* shade */
1592 char **split;
1593 double factor;
1594 char *end;
1595 MetaColorSpec *base;
1596
1597 split = g_strsplit (str, "/", 3);
1598
1599 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1600 split[2] == NULL((void*)0))
1601 {
1602 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1603 META_THEME_ERROR_FAILED,
1604 _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
))
,
1605 str);
1606 g_strfreev (split);
1607 return NULL((void*)0);
1608 }
1609
1610 factor = g_ascii_strtod (split[2], &end);
1611 if (end == split[2])
1612 {
1613 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1614 META_THEME_ERROR_FAILED,
1615 _("Could not parse shade factor \"%s\" in shaded color")((char *) g_dgettext ("marco", "Could not parse shade factor \"%s\" in shaded color"
))
,
1616 split[2]);
1617 g_strfreev (split);
1618 return NULL((void*)0);
1619 }
1620
1621 if (factor < (0.0 - 1e6))
1622 {
1623 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1624 META_THEME_ERROR_FAILED,
1625 _("Shade factor \"%s\" in shaded color is negative")((char *) g_dgettext ("marco", "Shade factor \"%s\" in shaded color is negative"
))
,
1626 split[2]);
1627 g_strfreev (split);
1628 return NULL((void*)0);
1629 }
1630
1631 base = NULL((void*)0);
1632
1633 base = meta_color_spec_new_from_string (split[1], err);
1634 if (base == NULL((void*)0))
1635 {
1636 g_strfreev (split);
1637 return NULL((void*)0);
1638 }
1639
1640 g_strfreev (split);
1641
1642 spec = meta_color_spec_new (META_COLOR_SPEC_SHADE);
1643 spec->data.shade.factor = factor;
1644 spec->data.shade.base = base;
1645 }
1646 else
1647 {
1648 spec = meta_color_spec_new (META_COLOR_SPEC_BASIC);
1649
1650 if (!gdk_rgba_parse (&spec->data.basic.color, str))
1651 {
1652 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1653 META_THEME_ERROR_FAILED,
1654 _("Could not parse color \"%s\"")((char *) g_dgettext ("marco", "Could not parse color \"%s\""
))
,
1655 str);
1656 meta_color_spec_free (spec);
1657 return NULL((void*)0);
1658 }
1659 }
1660
1661 g_assert (spec)do { if (spec) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 1661, ((const char*) (__func__)), "spec"); } while (0)
;
1662
1663 return spec;
1664}
1665
1666MetaColorSpec*
1667meta_color_spec_new_gtk (MetaGtkColorComponent component,
1668 GtkStateFlags state)
1669{
1670 MetaColorSpec *spec;
1671
1672 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1673
1674 spec->data.gtk.component = component;
1675 spec->data.gtk.state = state;
1676
1677 return spec;
1678}
1679
1680static void
1681get_background_color_real (GtkStyleContext *context,
1682 GtkStateFlags state,
1683 GdkRGBA *color)
1684{
1685 GdkRGBA *c;
1686
1687 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "color != NULL"); return
; } } while (0)
;
1688 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context)); GType __t = ((gtk_style_context_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "GTK_IS_STYLE_CONTEXT (context)"); return; } }
while (0)
;
1689
1690 gtk_style_context_get (context,
1691 state,
1692 "background-color", &c,
1693 NULL((void*)0));
1694
1695 *color = *c;
1696 gdk_rgba_free (c);
1697}
1698
1699static void
1700get_background_color (GtkStyleContext *context,
1701 GtkStateFlags state,
1702 GdkRGBA *color)
1703{
1704 GdkRGBA empty = { 0.0, 0.0, 0.0, 0.0 };
1705 GdkRGBA rgba;
1706
1707 get_background_color_real (context, state, &rgba);
1708
1709 if (gdk_rgba_equal (&rgba, &empty))
1710 {
1711 GtkWidget *toplevel;
1712 GtkStyleContext *tmp;
1713
1714 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1715 tmp = gtk_widget_get_style_context (toplevel);
1716
1717 get_background_color_real (tmp, state, &rgba);
1718
1719 gtk_widget_destroy (toplevel);
1720 }
1721
1722 *color = rgba;
1723}
1724
1725/* Based on set_color() in gtkstyle.c */
1726#define LIGHTNESS_MULT1.3 1.3
1727#define DARKNESS_MULT0.7 0.7
1728void
1729meta_gtk_style_get_light_color (GtkStyleContext *style,
1730 GtkStateFlags state,
1731 GdkRGBA *color)
1732{
1733 get_background_color (style, state, color);
1734 gtk_style_shade (color, color, LIGHTNESS_MULT1.3);
1735}
1736
1737void
1738meta_gtk_style_get_dark_color (GtkStyleContext *style,
1739 GtkStateFlags state,
1740 GdkRGBA *color)
1741{
1742 get_background_color (style, state, color);
1743 gtk_style_shade (color, color, DARKNESS_MULT0.7);
1744}
1745
1746static void
1747meta_set_color_from_style (GdkRGBA *color,
1748 GtkStyleContext *context,
1749 GtkStateFlags state,
1750 MetaGtkColorComponent component)
1751{
1752 GdkRGBA other;
1753
1754 /* Add background class to context to get the correct colors from the GTK+
1755 theme instead of white text over black background. */
1756 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND"background");
1757
1758 switch (component)
1759 {
1760 case META_GTK_COLOR_BG:
1761 case META_GTK_COLOR_BASE:
1762 get_background_color (context, state, color);
1763 break;
1764 case META_GTK_COLOR_FG:
1765 case META_GTK_COLOR_TEXT:
1766 gtk_style_context_get_color (context, state, color);
1767 break;
1768 case META_GTK_COLOR_TEXT_AA:
1769 gtk_style_context_get_color (context, state, color);
1770 meta_set_color_from_style (&other, context, state, META_GTK_COLOR_BASE);
1771
1772 color->red = (color->red + other.red) / 2;
1773 color->green = (color->green + other.green) / 2;
1774 color->blue = (color->blue + other.blue) / 2;
1775 break;
1776 case META_GTK_COLOR_MID:
1777 meta_gtk_style_get_light_color (context, state, color);
1778 meta_gtk_style_get_dark_color (context, state, &other);
1779
1780 color->red = (color->red + other.red) / 2;
1781 color->green = (color->green + other.green) / 2;
1782 color->blue = (color->blue + other.blue) / 2;
1783 break;
1784 case META_GTK_COLOR_LIGHT:
1785 meta_gtk_style_get_light_color (context, state, color);
1786 break;
1787 case META_GTK_COLOR_DARK:
1788 meta_gtk_style_get_dark_color (context, state, color);
1789 break;
1790 case META_GTK_COLOR_LAST:
1791 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1791, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1792 break;
1793 }
1794}
1795
1796static void
1797meta_set_custom_color_from_style (GdkRGBA *color,
1798 GtkStyleContext *context,
1799 char *color_name,
1800 MetaColorSpec *fallback)
1801{
1802 if (!gtk_style_context_lookup_color (context, color_name, color))
1803 meta_color_spec_render (fallback, context, color);
1804}
1805
1806void
1807meta_color_spec_render (MetaColorSpec *spec,
1808 GtkStyleContext *style,
1809 GdkRGBA *color)
1810{
1811 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1812
1813 g_return_if_fail (GTK_IS_STYLE_CONTEXT (style))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((style)); GType __t = ((gtk_style_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GTK_IS_STYLE_CONTEXT (style)"); return; } } while (0)
;
1814
1815 switch (spec->type)
1816 {
1817 case META_COLOR_SPEC_BASIC:
1818 *color = spec->data.basic.color;
1819 break;
1820
1821 case META_COLOR_SPEC_GTK:
1822 meta_set_color_from_style (color,
1823 style,
1824 spec->data.gtk.state,
1825 spec->data.gtk.component);
1826 break;
1827
1828 case META_COLOR_SPEC_GTK_CUSTOM:
1829 meta_set_custom_color_from_style (color,
1830 style,
1831 spec->data.gtkcustom.color_name,
1832 spec->data.gtkcustom.fallback);
1833 break;
1834
1835 case META_COLOR_SPEC_BLEND:
1836 {
1837 GdkRGBA bg, fg;
1838
1839 meta_color_spec_render (spec->data.blend.background, style, &bg);
1840 meta_color_spec_render (spec->data.blend.foreground, style, &fg);
1841
1842 color_composite (&bg, &fg, spec->data.blend.alpha,
1843 &spec->data.blend.color);
1844
1845 *color = spec->data.blend.color;
1846 }
1847 break;
1848
1849 case META_COLOR_SPEC_SHADE:
1850 {
1851 meta_color_spec_render (spec->data.shade.base, style,
1852 &spec->data.shade.color);
1853
1854 gtk_style_shade (&spec->data.shade.color,
1855 &spec->data.shade.color, spec->data.shade.factor);
1856
1857 *color = spec->data.shade.color;
1858 }
1859 break;
1860 }
1861}
1862
1863/**
1864 * Represents an operation as a string.
1865 *
1866 * \param type an operation, such as addition
1867 * \return a string, such as "+"
1868 */
1869static const char*
1870op_name (PosOperatorType type)
1871{
1872 switch (type)
1873 {
1874 case POS_OP_ADD:
1875 return "+";
1876 case POS_OP_SUBTRACT:
1877 return "-";
1878 case POS_OP_MULTIPLY:
1879 return "*";
1880 case POS_OP_DIVIDE:
1881 return "/";
1882 case POS_OP_MOD:
1883 return "%";
1884 case POS_OP_MAX:
1885 return "`max`";
1886 case POS_OP_MIN:
1887 return "`min`";
1888 case POS_OP_NONE:
1889 break;
1890 }
1891
1892 return "<unknown>";
1893}
1894
1895/**
1896 * Parses a string and returns an operation.
1897 *
1898 * \param p a pointer into a string representing an operation; part of an
1899 * expression somewhere, so not null-terminated
1900 * \param len set to the length of the string found. Set to 0 if none is.
1901 * \return the operation found. If none was, returns POS_OP_NONE.
1902 */
1903static PosOperatorType
1904op_from_string (const char *p,
1905 int *len)
1906{
1907 *len = 0;
1908
1909 switch (*p)
1910 {
1911 case '+':
1912 *len = 1;
1913 return POS_OP_ADD;
1914 case '-':
1915 *len = 1;
1916 return POS_OP_SUBTRACT;
1917 case '*':
1918 *len = 1;
1919 return POS_OP_MULTIPLY;
1920 case '/':
1921 *len = 1;
1922 return POS_OP_DIVIDE;
1923 case '%':
1924 *len = 1;
1925 return POS_OP_MOD;
1926
1927 case '`':
1928 if (strncmp (p, "`max`", 5) == 0)
1929 {
1930 *len = 5;
1931 return POS_OP_MAX;
1932 }
1933 else if (strncmp (p, "`min`", 5) == 0)
1934 {
1935 *len = 5;
1936 return POS_OP_MIN;
1937 }
1938 }
1939
1940 return POS_OP_NONE;
1941}
1942
1943/**
1944 * Frees an array of tokens. All the tokens and their associated memory
1945 * will be freed.
1946 *
1947 * \param tokens an array of tokens to be freed
1948 * \param n_tokens how many tokens are in the array.
1949 */
1950static void
1951free_tokens (PosToken *tokens,
1952 int n_tokens)
1953{
1954 int i;
1955
1956 /* n_tokens can be 0 since tokens may have been allocated more than
1957 * it was initialized
1958 */
1959
1960 for (i = 0; i < n_tokens; i++)
1961 if (tokens[i].type == POS_TOKEN_VARIABLE)
1962 g_free (tokens[i].d.v.name);
1963
1964 g_free (tokens);
1965}
1966
1967/**
1968 * Tokenises a number in an expression.
1969 *
1970 * \param p a pointer into a string representing an operation; part of an
1971 * expression somewhere, so not null-terminated
1972 * \param end_return set to a pointer to the end of the number found; but
1973 * not updated if no number was found at all
1974 * \param next set to either an integer or a float token
1975 * \param[out] err set to the problem if there was a problem
1976 * \return TRUE if a valid number was found, FALSE otherwise (and "err" will
1977 * have been set)
1978 *
1979 * \bug The "while (*start)..." part: what's wrong with strchr-ish things?
1980 * \bug The name is wrong: it doesn't parse anything.
1981 * \ingroup tokenizer
1982 */
1983static gboolean
1984parse_number (const char *p,
1985 const char **end_return,
1986 PosToken *next,
1987 GError **err)
1988{
1989 const char *start = p;
1990 char *end;
1991 gboolean is_float;
1992 char *num_str;
1993
1994 while (*p && (*p == '.' || g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0)))
1995 ++p;
1996
1997 if (p == start)
1998 {
1999 char buf[7] = { '\0' };
2000 buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0';
2001 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2002 META_THEME_ERROR_BAD_CHARACTER,
2003 _("Coordinate expression contains character '%s' which is not allowed")((char *) g_dgettext ("marco", "Coordinate expression contains character '%s' which is not allowed"
))
,
2004 buf);
2005 return FALSE(0);
2006 }
2007
2008 *end_return = p;
2009
2010 /* we need this to exclude floats like "1e6" */
2011 num_str = g_strndup (start, p - start);
2012 start = num_str;
2013 is_float = FALSE(0);
2014 while (*start)
2015 {
2016 if (*start == '.')
2017 is_float = TRUE(!(0));
2018 ++start;
2019 }
2020
2021 if (is_float)
2022 {
2023 next->type = POS_TOKEN_DOUBLE;
2024 next->d.d.val = g_ascii_strtod (num_str, &end);
2025
2026 if (end == num_str)
2027 {
2028 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2029 META_THEME_ERROR_FAILED,
2030 _("Coordinate expression contains floating point number '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains floating point number '%s' which could not be parsed"
))
,
2031 num_str);
2032 g_free (num_str);
2033 return FALSE(0);
2034 }
2035 }
2036 else
2037 {
2038 next->type = POS_TOKEN_INT;
2039 next->d.i.val = strtol (num_str, &end, 10);
2040 if (end == num_str)
2041 {
2042 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2043 META_THEME_ERROR_FAILED,
2044 _("Coordinate expression contains integer '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains integer '%s' which could not be parsed"
))
,
2045 num_str);
2046 g_free (num_str);
2047 return FALSE(0);
2048 }
2049 }
2050
2051 g_free (num_str);
2052
2053 g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE)do { if (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 2053
, ((const char*) (__func__)), "next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE"
); } while (0)
;
2054
2055 return TRUE(!(0));
2056}
2057
2058/**
2059 * Whether a variable can validly appear as part of the name of a variable.
2060 */
2061#define IS_VARIABLE_CHAR(c)(((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) ||
(c) == '_')
(g_ascii_isalpha ((c))((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) || (c) == '_')
2062
2063#if 0
2064static void
2065debug_print_tokens (PosToken *tokens,
2066 int n_tokens)
2067{
2068 int i;
2069
2070 for (i = 0; i < n_tokens; i++)
2071 {
2072 PosToken *t = &tokens[i];
2073
2074 g_print (" ");
2075
2076 switch (t->type)
2077 {
2078 case POS_TOKEN_INT:
2079 g_print ("\"%d\"", t->d.i.val);
2080 break;
2081 case POS_TOKEN_DOUBLE:
2082 g_print ("\"%g\"", t->d.d.val);
2083 break;
2084 case POS_TOKEN_OPEN_PAREN:
2085 g_print ("\"(\"");
2086 break;
2087 case POS_TOKEN_CLOSE_PAREN:
2088 g_print ("\")\"");
2089 break;
2090 case POS_TOKEN_VARIABLE:
2091 g_print ("\"%s\"", t->d.v.name);
2092 break;
2093 case POS_TOKEN_OPERATOR:
2094 g_print ("\"%s\"", op_name (t->d.o.op));
2095 break;
2096 }
2097 }
2098
2099 g_print ("\n");
2100}
2101#endif
2102
2103/**
2104 * Tokenises an expression.
2105 *
2106 * \param expr The expression
2107 * \param[out] tokens_p The resulting tokens
2108 * \param[out] n_tokens_p The number of resulting tokens
2109 * \param[out] err set to the problem if there was a problem
2110 *
2111 * \return True if the expression was successfully tokenised; false otherwise.
2112 *
2113 * \ingroup tokenizer
2114 */
2115static gboolean
2116pos_tokenize (const char *expr,
2117 PosToken **tokens_p,
2118 int *n_tokens_p,
2119 GError **err)
2120{
2121 PosToken *tokens;
2122 int n_tokens;
2123 int allocated;
2124 const char *p;
2125
2126 *tokens_p = NULL((void*)0);
2127 *n_tokens_p = 0;
2128
2129 allocated = 3;
2130 n_tokens = 0;
2131 tokens = g_new (PosToken, allocated)((PosToken *) g_malloc_n ((allocated), sizeof (PosToken)));
2132
2133 p = expr;
2134 while (*p)
2135 {
2136 PosToken *next;
2137 int len;
2138
2139 if (n_tokens == allocated)
2140 {
2141 allocated *= 2;
2142 tokens = g_renew (PosToken, tokens, allocated)((PosToken *) g_realloc_n (tokens, (allocated), sizeof (PosToken
)))
;
2143 }
2144
2145 next = &tokens[n_tokens];
2146
2147 switch (*p)
2148 {
2149 case '*':
2150 case '/':
2151 case '+':
2152 case '-': /* negative numbers aren't allowed so this is easy */
2153 case '%':
2154 case '`':
2155 next->type = POS_TOKEN_OPERATOR;
2156 next->d.o.op = op_from_string (p, &len);
2157 if (next->d.o.op != POS_OP_NONE)
2158 {
2159 ++n_tokens;
2160 p = p + (len - 1); /* -1 since we ++p later */
2161 }
2162 else
2163 {
2164 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2165 META_THEME_ERROR_FAILED,
2166 _("Coordinate expression contained unknown operator at the start of this text: \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression contained unknown operator at the start of this text: \"%s\""
))
,
2167 p);
2168
2169 goto error;
2170 }
2171 break;
2172
2173 case '(':
2174 next->type = POS_TOKEN_OPEN_PAREN;
2175 ++n_tokens;
2176 break;
2177
2178 case ')':
2179 next->type = POS_TOKEN_CLOSE_PAREN;
2180 ++n_tokens;
2181 break;
2182
2183 case ' ':
2184 case '\t':
2185 case '\n':
2186 break;
2187
2188 default:
2189 if (IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2190 {
2191 /* Assume variable */
2192 const char *start = p;
2193 while (*p && IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2194 ++p;
2195 g_assert (p != start)do { if (p != start) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2195, ((const char*) (__func__)), "p != start"
); } while (0)
;
2196 next->type = POS_TOKEN_VARIABLE;
2197 next->d.v.name = g_strndup (start, p - start);
2198 ++n_tokens;
2199 --p; /* since we ++p again at the end of while loop */
2200 }
2201 else
2202 {
2203 /* Assume number */
2204 const char *end;
2205
2206 if (!parse_number (p, &end, next, err))
2207 goto error;
2208
2209 ++n_tokens;
2210 p = end - 1; /* -1 since we ++p again at the end of while loop */
2211 }
2212
2213 break;
2214 }
2215
2216 ++p;
2217 }
2218
2219 if (n_tokens == 0)
2220 {
2221 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2222 META_THEME_ERROR_FAILED,
2223 _("Coordinate expression was empty or not understood")((char *) g_dgettext ("marco", "Coordinate expression was empty or not understood"
))
);
2224
2225 goto error;
2226 }
2227
2228 *tokens_p = tokens;
2229 *n_tokens_p = n_tokens;
2230
2231 return TRUE(!(0));
2232
2233 error:
2234 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2234, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2235
2236 free_tokens (tokens, n_tokens);
2237 return FALSE(0);
2238}
2239
2240/**
2241 * The type of a PosExpr: either integer, double, or an operation.
2242 * \ingroup parser
2243 */
2244typedef enum
2245{
2246 POS_EXPR_INT,
2247 POS_EXPR_DOUBLE,
2248 POS_EXPR_OPERATOR
2249} PosExprType;
2250
2251/**
2252 * Type and value of an expression in a parsed sequence. We don't
2253 * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR,
2254 * the arguments of the operator will be in the array positions
2255 * immediately preceding and following this operator; they cannot
2256 * themselves be operators.
2257 *
2258 * \bug operator is char; it should really be of PosOperatorType.
2259 * \ingroup parser
2260 */
2261typedef struct
2262{
2263 PosExprType type;
2264 union
2265 {
2266 double double_val;
2267 int int_val;
2268 char operator;
2269 } d;
2270} PosExpr;
2271
2272#if 0
2273static void
2274debug_print_exprs (PosExpr *exprs,
2275 int n_exprs)
2276{
2277 int i;
2278
2279 for (i = 0; i < n_exprs; i++)
2280 {
2281 switch (exprs[i].type)
2282 {
2283 case POS_EXPR_INT:
2284 g_print (" %d", exprs[i].d.int_val);
2285 break;
2286 case POS_EXPR_DOUBLE:
2287 g_print (" %g", exprs[i].d.double_val);
2288 break;
2289 case POS_EXPR_OPERATOR:
2290 g_print (" %s", op_name (exprs[i].d.operator));
2291 break;
2292 }
2293 }
2294 g_print ("\n");
2295}
2296#endif
2297
2298static gboolean
2299do_operation (PosExpr *a,
2300 PosExpr *b,
2301 PosOperatorType op,
2302 GError **err)
2303{
2304 /* Promote types to double if required */
2305 if (a->type == POS_EXPR_DOUBLE ||
2306 b->type == POS_EXPR_DOUBLE)
2307 {
2308 if (a->type != POS_EXPR_DOUBLE)
2309 {
2310 a->type = POS_EXPR_DOUBLE;
2311 a->d.double_val = a->d.int_val;
2312 }
2313 if (b->type != POS_EXPR_DOUBLE)
2314 {
2315 b->type = POS_EXPR_DOUBLE;
2316 b->d.double_val = b->d.int_val;
2317 }
2318 }
2319
2320 g_assert (a->type == b->type)do { if (a->type == b->type) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2320, ((const char*) (__func__)), "a->type == b->type"
); } while (0)
;
2321
2322 if (a->type == POS_EXPR_INT)
2323 {
2324 switch (op)
2325 {
2326 case POS_OP_MULTIPLY:
2327 a->d.int_val = a->d.int_val * b->d.int_val;
2328 break;
2329 case POS_OP_DIVIDE:
2330 if (b->d.int_val == 0)
2331 {
2332 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2333 META_THEME_ERROR_DIVIDE_BY_ZERO,
2334 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2335 return FALSE(0);
2336 }
2337 a->d.int_val = a->d.int_val / b->d.int_val;
2338 break;
2339 case POS_OP_MOD:
2340 if (b->d.int_val == 0)
2341 {
2342 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2343 META_THEME_ERROR_DIVIDE_BY_ZERO,
2344 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2345 return FALSE(0);
2346 }
2347 a->d.int_val = a->d.int_val % b->d.int_val;
2348 break;
2349 case POS_OP_ADD:
2350 a->d.int_val = a->d.int_val + b->d.int_val;
2351 break;
2352 case POS_OP_SUBTRACT:
2353 a->d.int_val = a->d.int_val - b->d.int_val;
2354 break;
2355 case POS_OP_MAX:
2356 a->d.int_val = MAX (a->d.int_val, b->d.int_val)(((a->d.int_val) > (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2357 break;
2358 case POS_OP_MIN:
2359 a->d.int_val = MIN (a->d.int_val, b->d.int_val)(((a->d.int_val) < (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2360 break;
2361 case POS_OP_NONE:
2362 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2362, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2363 break;
2364 }
2365 }
2366 else if (a->type == POS_EXPR_DOUBLE)
2367 {
2368 switch (op)
2369 {
2370 case POS_OP_MULTIPLY:
2371 a->d.double_val = a->d.double_val * b->d.double_val;
2372 break;
2373 case POS_OP_DIVIDE:
2374 if (b->d.double_val == 0.0)
2375 {
2376 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2377 META_THEME_ERROR_DIVIDE_BY_ZERO,
2378 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2379 return FALSE(0);
2380 }
2381 a->d.double_val = a->d.double_val / b->d.double_val;
2382 break;
2383 case POS_OP_MOD:
2384 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2385 META_THEME_ERROR_MOD_ON_FLOAT,
2386 _("Coordinate expression tries to use mod operator on a floating-point number")((char *) g_dgettext ("marco", "Coordinate expression tries to use mod operator on a floating-point number"
))
);
2387 return FALSE(0);
2388 case POS_OP_ADD:
2389 a->d.double_val = a->d.double_val + b->d.double_val;
2390 break;
2391 case POS_OP_SUBTRACT:
2392 a->d.double_val = a->d.double_val - b->d.double_val;
2393 break;
2394 case POS_OP_MAX:
2395 a->d.double_val = MAX (a->d.double_val, b->d.double_val)(((a->d.double_val) > (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2396 break;
2397 case POS_OP_MIN:
2398 a->d.double_val = MIN (a->d.double_val, b->d.double_val)(((a->d.double_val) < (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2399 break;
2400 case POS_OP_NONE:
2401 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2401, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2402 break;
2403 }
2404 }
2405 else
2406 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2406, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2407
2408 return TRUE(!(0));
2409}
2410
2411static gboolean
2412do_operations (PosExpr *exprs,
2413 int *n_exprs,
2414 int precedence,
2415 GError **err)
2416{
2417 int i;
2418
2419#if 0
2420 g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs);
2421 debug_print_exprs (exprs, *n_exprs);
2422#endif
2423
2424 i = 1;
2425 while (i < *n_exprs)
2426 {
2427 gboolean compress;
2428
2429 /* exprs[i-1] first operand
2430 * exprs[i] operator
2431 * exprs[i+1] second operand
2432 *
2433 * we replace first operand with result of mul/div/mod,
2434 * or skip over operator and second operand if we have
2435 * an add/subtract
2436 */
2437
2438 if (exprs[i-1].type == POS_EXPR_OPERATOR)
2439 {
2440 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2441 META_THEME_ERROR_FAILED,
2442 _("Coordinate expression has an operator \"%s\" where an operand was expected")((char *) g_dgettext ("marco", "Coordinate expression has an operator \"%s\" where an operand was expected"
))
,
2443 op_name (exprs[i-1].d.operator));
2444 return FALSE(0);
2445 }
2446
2447 if (exprs[i].type != POS_EXPR_OPERATOR)
2448 {
2449 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2450 META_THEME_ERROR_FAILED,
2451 _("Coordinate expression had an operand where an operator was expected")((char *) g_dgettext ("marco", "Coordinate expression had an operand where an operator was expected"
))
);
2452 return FALSE(0);
2453 }
2454
2455 if (i == (*n_exprs - 1))
2456 {
2457 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2458 META_THEME_ERROR_FAILED,
2459 _("Coordinate expression ended with an operator instead of an operand")((char *) g_dgettext ("marco", "Coordinate expression ended with an operator instead of an operand"
))
);
2460 return FALSE(0);
2461 }
2462
2463 g_assert ((i+1) < *n_exprs)do { if ((i+1) < *n_exprs) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2463, ((const char*) (__func__)), "(i+1) < *n_exprs"
); } while (0)
;
2464
2465 if (exprs[i+1].type == POS_EXPR_OPERATOR)
2466 {
2467 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2468 META_THEME_ERROR_FAILED,
2469 _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between")((char *) g_dgettext ("marco", "Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"
))
,
2470 exprs[i+1].d.operator,
2471 exprs[i].d.operator);
2472 return FALSE(0);
2473 }
2474
2475 compress = FALSE(0);
2476
2477 switch (precedence)
2478 {
2479 case 2:
2480 switch (exprs[i].d.operator)
2481 {
2482 case POS_OP_DIVIDE:
2483 case POS_OP_MOD:
2484 case POS_OP_MULTIPLY:
2485 compress = TRUE(!(0));
2486 if (!do_operation (&exprs[i-1], &exprs[i+1],
2487 exprs[i].d.operator,
2488 err))
2489 return FALSE(0);
2490 break;
2491 }
2492 break;
2493 case 1:
2494 switch (exprs[i].d.operator)
2495 {
2496 case POS_OP_ADD:
2497 case POS_OP_SUBTRACT:
2498 compress = TRUE(!(0));
2499 if (!do_operation (&exprs[i-1], &exprs[i+1],
2500 exprs[i].d.operator,
2501 err))
2502 return FALSE(0);
2503 break;
2504 }
2505 break;
2506 /* I have no rationale at all for making these low-precedence */
2507 case 0:
2508 switch (exprs[i].d.operator)
2509 {
2510 case POS_OP_MAX:
2511 case POS_OP_MIN:
2512 compress = TRUE(!(0));
2513 if (!do_operation (&exprs[i-1], &exprs[i+1],
2514 exprs[i].d.operator,
2515 err))
2516 return FALSE(0);
2517 break;
2518 }
2519 break;
2520 }
2521
2522 if (compress)
2523 {
2524 /* exprs[i-1] first operand (now result)
2525 * exprs[i] operator
2526 * exprs[i+1] second operand
2527 * exprs[i+2] new operator
2528 *
2529 * we move new operator just after first operand
2530 */
2531 if ((i+2) < *n_exprs)
2532 {
2533 memmove (&exprs[i], &exprs[i+2],
2534 sizeof (PosExpr) * (*n_exprs - i - 2));
2535 }
2536
2537 *n_exprs -= 2;
2538 }
2539 else
2540 {
2541 /* Skip operator and next operand */
2542 i += 2;
2543 }
2544 }
2545
2546 return TRUE(!(0));
2547}
2548
2549/**
2550 * There is a predefined set of variables which can appear in an expression.
2551 * Here we take a token representing a variable, and return the current value
2552 * of that variable in a particular environment.
2553 * (The value is always an integer.)
2554 *
2555 * There are supposedly some circumstances in which this function can be
2556 * called from outside Marco, in which case env->theme will be NULL, and
2557 * therefore we can't use it to find out quark values, so we do the comparison
2558 * using strcmp, which is slower.
2559 *
2560 * \param t The token representing a variable
2561 * \param[out] result The value of that variable; not set if the token did
2562 * not represent a known variable
2563 * \param env The environment within which t should be evaluated
2564 * \param[out] err set to the problem if there was a problem
2565 *
2566 * \return true if we found the variable asked for, false if we didn't
2567 *
2568 * \bug shouldn't t be const?
2569 * \bug we should perhaps consider some sort of lookup arrangement into an
2570 * array; also, the duplication of code is unlovely; perhaps using glib
2571 * string hashes instead of quarks would fix both problems?
2572 * \ingroup parser
2573 */
2574static gboolean
2575pos_eval_get_variable (PosToken *t,
2576 int *result,
2577 const MetaPositionExprEnv *env,
2578 GError **err)
2579{
2580 if (env->theme)
2581 {
2582 if (t->d.v.name_quark == env->theme->quark_width)
2583 *result = env->rect.width;
2584 else if (t->d.v.name_quark == env->theme->quark_height)
2585 *result = env->rect.height;
2586 else if (env->object_width >= 0 &&
2587 t->d.v.name_quark == env->theme->quark_object_width)
2588 *result = env->object_width;
2589 else if (env->object_height >= 0 &&
2590 t->d.v.name_quark == env->theme->quark_object_height)
2591 *result = env->object_height;
2592 else if (t->d.v.name_quark == env->theme->quark_left_width)
2593 *result = env->left_width;
2594 else if (t->d.v.name_quark == env->theme->quark_right_width)
2595 *result = env->right_width;
2596 else if (t->d.v.name_quark == env->theme->quark_top_height)
2597 *result = env->top_height;
2598 else if (t->d.v.name_quark == env->theme->quark_bottom_height)
2599 *result = env->bottom_height;
2600 else if (t->d.v.name_quark == env->theme->quark_mini_icon_width)
2601 *result = env->mini_icon_width;
2602 else if (t->d.v.name_quark == env->theme->quark_mini_icon_height)
2603 *result = env->mini_icon_height;
2604 else if (t->d.v.name_quark == env->theme->quark_icon_width)
2605 *result = env->icon_width;
2606 else if (t->d.v.name_quark == env->theme->quark_icon_height)
2607 *result = env->icon_height;
2608 else if (t->d.v.name_quark == env->theme->quark_title_width)
2609 *result = env->title_width;
2610 else if (t->d.v.name_quark == env->theme->quark_title_height)
2611 *result = env->title_height;
2612 else if (t->d.v.name_quark == env->theme->quark_frame_x_center)
2613 *result = env->frame_x_center;
2614 else if (t->d.v.name_quark == env->theme->quark_frame_y_center)
2615 *result = env->frame_y_center;
2616 else
2617 {
2618 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2619 META_THEME_ERROR_UNKNOWN_VARIABLE,
2620 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2621 t->d.v.name);
2622 return FALSE(0);
2623 }
2624 }
2625 else
2626 {
2627 if (strcmp (t->d.v.name, "width") == 0)
2628 *result = env->rect.width;
2629 else if (strcmp (t->d.v.name, "height") == 0)
2630 *result = env->rect.height;
2631 else if (env->object_width >= 0 &&
2632 strcmp (t->d.v.name, "object_width") == 0)
2633 *result = env->object_width;
2634 else if (env->object_height >= 0 &&
2635 strcmp (t->d.v.name, "object_height") == 0)
2636 *result = env->object_height;
2637 else if (strcmp (t->d.v.name, "left_width") == 0)
2638 *result = env->left_width;
2639 else if (strcmp (t->d.v.name, "right_width") == 0)
2640 *result = env->right_width;
2641 else if (strcmp (t->d.v.name, "top_height") == 0)
2642 *result = env->top_height;
2643 else if (strcmp (t->d.v.name, "bottom_height") == 0)
2644 *result = env->bottom_height;
2645 else if (strcmp (t->d.v.name, "mini_icon_width") == 0)
2646 *result = env->mini_icon_width;
2647 else if (strcmp (t->d.v.name, "mini_icon_height") == 0)
2648 *result = env->mini_icon_height;
2649 else if (strcmp (t->d.v.name, "icon_width") == 0)
2650 *result = env->icon_width;
2651 else if (strcmp (t->d.v.name, "icon_height") == 0)
2652 *result = env->icon_height;
2653 else if (strcmp (t->d.v.name, "title_width") == 0)
2654 *result = env->title_width;
2655 else if (strcmp (t->d.v.name, "title_height") == 0)
2656 *result = env->title_height;
2657 else if (strcmp (t->d.v.name, "frame_x_center") == 0)
2658 *result = env->frame_x_center;
2659 else if (strcmp (t->d.v.name, "frame_y_center") == 0)
2660 *result = env->frame_y_center;
2661 else
2662 {
2663 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2664 META_THEME_ERROR_UNKNOWN_VARIABLE,
2665 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2666 t->d.v.name);
2667 return FALSE(0);
2668 }
2669 }
2670
2671 return TRUE(!(0));
2672}
2673
2674/**
2675 * Evaluates a sequence of tokens within a particular environment context,
2676 * and returns the current value. May recur if parantheses are found.
2677 *
2678 * \param tokens A list of tokens to evaluate.
2679 * \param n_tokens How many tokens are in the list.
2680 * \param env The environment context in which to evaluate the expression.
2681 * \param[out] result The current value of the expression
2682 *
2683 * \bug Yes, we really do reparse the expression every time it's evaluated.
2684 * We should keep the parse tree around all the time and just
2685 * run the new values through it.
2686 * \ingroup parser
2687 */
2688static gboolean
2689pos_eval_helper (PosToken *tokens,
2690 int n_tokens,
2691 const MetaPositionExprEnv *env,
2692 PosExpr *result,
2693 GError **err)
2694{
2695 /* Lazy-ass hardcoded limit on number of terms in expression */
2696#define MAX_EXPRS32 32
2697 int paren_level;
2698 int first_paren;
2699 int i;
2700 PosExpr exprs[MAX_EXPRS32];
2701 int n_exprs;
2702 int precedence;
2703
2704 /* Our first goal is to get a list of PosExpr, essentially
2705 * substituting variables and handling parentheses.
2706 */
2707
2708 first_paren = 0;
2709 paren_level = 0;
2710 n_exprs = 0;
2711 for (i = 0; i < n_tokens; i++)
2712 {
2713 PosToken *t = &tokens[i];
2714
2715 if (n_exprs >= MAX_EXPRS32)
2716 {
2717 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2718 META_THEME_ERROR_FAILED,
2719 _("Coordinate expression parser overflowed its buffer.")((char *) g_dgettext ("marco", "Coordinate expression parser overflowed its buffer."
))
);
2720 return FALSE(0);
2721 }
2722
2723 if (paren_level == 0)
2724 {
2725 switch (t->type)
2726 {
2727 case POS_TOKEN_INT:
2728 exprs[n_exprs].type = POS_EXPR_INT;
2729 exprs[n_exprs].d.int_val = t->d.i.val;
2730 ++n_exprs;
2731 break;
2732
2733 case POS_TOKEN_DOUBLE:
2734 exprs[n_exprs].type = POS_EXPR_DOUBLE;
2735 exprs[n_exprs].d.double_val = t->d.d.val;
2736 ++n_exprs;
2737 break;
2738
2739 case POS_TOKEN_OPEN_PAREN:
2740 ++paren_level;
2741 if (paren_level == 1)
2742 first_paren = i;
2743 break;
2744
2745 case POS_TOKEN_CLOSE_PAREN:
2746 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2747 META_THEME_ERROR_BAD_PARENS,
2748 _("Coordinate expression had a close parenthesis with no open parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had a close parenthesis with no open parenthesis"
))
);
2749 return FALSE(0);
2750
2751 case POS_TOKEN_VARIABLE:
2752 exprs[n_exprs].type = POS_EXPR_INT;
2753
2754 /* FIXME we should just dump all this crap
2755 * in a hash, maybe keep width/height out
2756 * for optimization purposes
2757 */
2758 if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err))
2759 return FALSE(0);
2760
2761 ++n_exprs;
2762 break;
2763
2764 case POS_TOKEN_OPERATOR:
2765 exprs[n_exprs].type = POS_EXPR_OPERATOR;
2766 exprs[n_exprs].d.operator = t->d.o.op;
2767 ++n_exprs;
2768 break;
2769 }
2770 }
2771 else
2772 {
2773 g_assert (paren_level > 0)do { if (paren_level > 0) ; else g_assertion_message_expr (
"marco", "ui/theme.c", 2773, ((const char*) (__func__)), "paren_level > 0"
); } while (0)
;
2774
2775 switch (t->type)
2776 {
2777 case POS_TOKEN_INT:
2778 case POS_TOKEN_DOUBLE:
2779 case POS_TOKEN_VARIABLE:
2780 case POS_TOKEN_OPERATOR:
2781 break;
2782
2783 case POS_TOKEN_OPEN_PAREN:
2784 ++paren_level;
2785 break;
2786
2787 case POS_TOKEN_CLOSE_PAREN:
2788 if (paren_level == 1)
2789 {
2790 /* We closed a toplevel paren group, so recurse */
2791 if (!pos_eval_helper (&tokens[first_paren+1],
2792 i - first_paren - 1,
2793 env,
2794 &exprs[n_exprs],
2795 err))
2796 return FALSE(0);
2797
2798 ++n_exprs;
2799 }
2800
2801 --paren_level;
2802 break;
2803
2804 }
2805 }
2806 }
2807
2808 if (paren_level > 0)
2809 {
2810 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2811 META_THEME_ERROR_BAD_PARENS,
2812 _("Coordinate expression had an open parenthesis with no close parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had an open parenthesis with no close parenthesis"
))
);
2813 return FALSE(0);
2814 }
2815
2816 /* Now we have no parens and no vars; so we just do all the multiplies
2817 * and divides, then all the add and subtract.
2818 */
2819 if (n_exprs == 0)
2820 {
2821 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2822 META_THEME_ERROR_FAILED,
2823 _("Coordinate expression doesn't seem to have any operators or operands")((char *) g_dgettext ("marco", "Coordinate expression doesn't seem to have any operators or operands"
))
);
2824 return FALSE(0);
2825 }
2826
2827 /* precedence 1 ops */
2828 precedence = 2;
2829 while (precedence >= 0)
2830 {
2831 if (!do_operations (exprs, &n_exprs, precedence, err))
2832 return FALSE(0);
2833 --precedence;
2834 }
2835
2836 g_assert (n_exprs == 1)do { if (n_exprs == 1) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2836, ((const char*) (__func__)), "n_exprs == 1"
); } while (0)
;
2837
2838 *result = *exprs;
2839
2840 return TRUE(!(0));
2841}
2842
2843/*
2844 * expr = int | double | expr * expr | expr / expr |
2845 * expr + expr | expr - expr | (expr)
2846 *
2847 * so very not worth fooling with bison, yet so very painful by hand.
2848 */
2849/**
2850 * Evaluates an expression.
2851 *
2852 * \param spec The expression to evaluate.
2853 * \param env The environment context to evaluate the expression in.
2854 * \param[out] val_p The integer value of the expression; if the expression
2855 * is of type float, this will be rounded. If we return
2856 * FALSE because the expression is invalid, this will be
2857 * zero.
2858 * \param[out] err The error, if anything went wrong.
2859 *
2860 * \return True if we evaluated the expression successfully; false otherwise.
2861 *
2862 * \bug Shouldn't spec be const?
2863 * \ingroup parser
2864 */
2865static gboolean
2866pos_eval (MetaDrawSpec *spec,
2867 const MetaPositionExprEnv *env,
2868 int *val_p,
2869 GError **err)
2870{
2871 PosExpr expr;
2872
2873 *val_p = 0;
2874
2875 if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err))
2876 {
2877 switch (expr.type)
2878 {
2879 case POS_EXPR_INT:
2880 *val_p = expr.d.int_val;
2881 break;
2882 case POS_EXPR_DOUBLE:
2883 *val_p = (int) expr.d.double_val;
2884 break;
2885 case POS_EXPR_OPERATOR:
2886 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2886, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2887 break;
2888 }
2889 return TRUE(!(0));
2890 }
2891 else
2892 {
2893 return FALSE(0);
2894 }
2895}
2896
2897/* We always return both X and Y, but only one will be meaningful in
2898 * most contexts.
2899 */
2900
2901gboolean
2902meta_parse_position_expression (MetaDrawSpec *spec,
2903 const MetaPositionExprEnv *env,
2904 int *x_return,
2905 int *y_return,
2906 GError **err)
2907{
2908 /* All positions are in a coordinate system with x, y at the origin.
2909 * The expression can have -, +, *, / as operators, floating point
2910 * or integer constants, and the variables "width" and "height" and
2911 * optionally "object_width" and object_height". Negative numbers
2912 * aren't allowed.
2913 */
2914 int val;
2915
2916 if (spec->constant)
2917 val = spec->value;
2918 else
2919 {
2920 if (!pos_eval (spec, env, &spec->value, err))
2921 {
2922 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2922, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2923 return FALSE(0);
2924 }
2925
2926 val = spec->value;
2927 }
2928
2929 if (x_return)
2930 *x_return = env->rect.x + val;
2931 if (y_return)
2932 *y_return = env->rect.y + val;
2933
2934 return TRUE(!(0));
2935}
2936
2937gboolean
2938meta_parse_size_expression (MetaDrawSpec *spec,
2939 const MetaPositionExprEnv *env,
2940 int *val_return,
2941 GError **err)
2942{
2943 int val;
2944
2945 if (spec->constant)
2946 val = spec->value;
2947 else
2948 {
2949 if (!pos_eval (spec, env, &spec->value, err))
2950 {
2951 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2951, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2952 return FALSE(0);
2953 }
2954
2955 val = spec->value;
2956 }
2957
2958 if (val_return)
2959 *val_return = MAX (val, 1)(((val) > (1)) ? (val) : (1)); /* require that sizes be at least 1x1 */
2960
2961 return TRUE(!(0));
2962}
2963
2964/* To do this we tokenize, replace variable tokens
2965 * that are constants, then reassemble. The purpose
2966 * here is to optimize expressions so we don't do hash
2967 * lookups to eval them. Obviously it's a tradeoff that
2968 * slows down theme load times.
2969 */
2970gboolean
2971meta_theme_replace_constants (MetaTheme *theme,
2972 PosToken *tokens,
2973 int n_tokens,
2974 GError **err)
2975{
2976 int i;
2977 double dval;
2978 int ival;
2979 gboolean is_constant = TRUE(!(0));
2980
2981 /* Loop through tokenized string looking for variables to replace */
2982 for (i = 0; i < n_tokens; i++)
2983 {
2984 PosToken *t = &tokens[i];
2985
2986 if (t->type == POS_TOKEN_VARIABLE)
2987 {
2988 if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival))
2989 {
2990 g_free (t->d.v.name);
2991 t->type = POS_TOKEN_INT;
2992 t->d.i.val = ival;
2993 }
2994 else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval))
2995 {
2996 g_free (t->d.v.name);
2997 t->type = POS_TOKEN_DOUBLE;
2998 t->d.d.val = dval;
2999 }
3000 else
3001 {
3002 /* If we've found a variable that cannot be replaced then the
3003 expression is not a constant expression and we want to
3004 replace it with a GQuark */
3005
3006 t->d.v.name_quark = g_quark_from_string (t->d.v.name);
3007 is_constant = FALSE(0);
3008 }
3009 }
3010 }
3011
3012 return is_constant;
3013}
3014
3015static int
3016parse_x_position_unchecked (MetaDrawSpec *spec,
3017 const MetaPositionExprEnv *env)
3018{
3019 int retval;
3020 GError *error;
3021
3022 retval = 0;
3023 error = NULL((void*)0);
3024 if (!meta_parse_position_expression (spec, env, &retval, NULL((void*)0), &error))
3025 {
3026 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3027 error->message);
3028
3029 g_error_free (error);
3030 }
3031
3032 return retval;
3033}
3034
3035static int
3036parse_y_position_unchecked (MetaDrawSpec *spec,
3037 const MetaPositionExprEnv *env)
3038{
3039 int retval;
3040 GError *error;
3041
3042 retval = 0;
3043 error = NULL((void*)0);
3044 if (!meta_parse_position_expression (spec, env, NULL((void*)0), &retval, &error))
3045 {
3046 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3047 error->message);
3048
3049 g_error_free (error);
3050 }
3051
3052 return retval;
3053}
3054
3055static int
3056parse_size_unchecked (MetaDrawSpec *spec,
3057 MetaPositionExprEnv *env)
3058{
3059 int retval;
3060 GError *error;
3061
3062 retval = 0;
3063 error = NULL((void*)0);
3064 if (!meta_parse_size_expression (spec, env, &retval, &error))
3065 {
3066 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3067 error->message);
3068
3069 g_error_free (error);
3070 }
3071
3072 return retval;
3073}
3074
3075void
3076meta_draw_spec_free (MetaDrawSpec *spec)
3077{
3078 if (!spec) return;
3079 free_tokens (spec->tokens, spec->n_tokens);
3080 g_slice_free (MetaDrawSpec, spec)do { if (1) g_slice_free1 (sizeof (MetaDrawSpec), (spec)); else
(void) ((MetaDrawSpec*) 0 == (spec)); } while (0)
;
3081}
3082
3083MetaDrawSpec *
3084meta_draw_spec_new (MetaTheme *theme,
3085 const char *expr,
3086 GError **error)
3087{
3088 MetaDrawSpec *spec;
3089
3090 spec = g_slice_new0 (MetaDrawSpec)((MetaDrawSpec*) g_slice_alloc0 (sizeof (MetaDrawSpec)));
3091
3092 pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL((void*)0));
3093
3094 spec->constant = meta_theme_replace_constants (theme, spec->tokens,
3095 spec->n_tokens, NULL((void*)0));
3096 if (spec->constant)
3097 {
3098 if (!pos_eval (spec, NULL((void*)0), &spec->value, error))
3099 {
3100 meta_draw_spec_free (spec);
3101 return NULL((void*)0);
3102 }
3103 }
3104
3105 return spec;
3106}
3107
3108MetaDrawOp*
3109meta_draw_op_new (MetaDrawType type)
3110{
3111 MetaDrawOp *op;
3112 MetaDrawOp dummy;
3113 int size;
3114
3115 size = G_STRUCT_OFFSET (MetaDrawOp, data)((glong) __builtin_offsetof(MetaDrawOp, data));
3116
3117 switch (type)
3118 {
3119 case META_DRAW_LINE:
3120 size += sizeof (dummy.data.line);
3121 break;
3122
3123 case META_DRAW_RECTANGLE:
3124 size += sizeof (dummy.data.rectangle);
3125 break;
3126
3127 case META_DRAW_ARC:
3128 size += sizeof (dummy.data.arc);
3129 break;
3130
3131 case META_DRAW_CLIP:
3132 size += sizeof (dummy.data.clip);
3133 break;
3134
3135 case META_DRAW_TINT:
3136 size += sizeof (dummy.data.tint);
3137 break;
3138
3139 case META_DRAW_GRADIENT:
3140 size += sizeof (dummy.data.gradient);
3141 break;
3142
3143 case META_DRAW_IMAGE:
3144 size += sizeof (dummy.data.image);
3145 break;
3146
3147 case META_DRAW_GTK_ARROW:
3148 size += sizeof (dummy.data.gtk_arrow);
3149 break;
3150
3151 case META_DRAW_GTK_BOX:
3152 size += sizeof (dummy.data.gtk_box);
3153 break;
3154
3155 case META_DRAW_GTK_VLINE:
3156 size += sizeof (dummy.data.gtk_vline);
3157 break;
3158
3159 case META_DRAW_ICON:
3160 size += sizeof (dummy.data.icon);
3161 break;
3162
3163 case META_DRAW_TITLE:
3164 size += sizeof (dummy.data.title);
3165 break;
3166 case META_DRAW_OP_LIST:
3167 size += sizeof (dummy.data.op_list);
3168 break;
3169 case META_DRAW_TILE:
3170 size += sizeof (dummy.data.tile);
3171 break;
3172 }
3173
3174 op = g_malloc0 (size);
3175
3176 op->type = type;
3177
3178 return op;
3179}
3180
3181void
3182meta_draw_op_free (MetaDrawOp *op)
3183{
3184 g_return_if_fail (op != NULL)do { if ((op != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op != NULL"); return;
} } while (0)
;
3185
3186 switch (op->type)
3187 {
3188 case META_DRAW_LINE:
3189 if (op->data.line.color_spec)
3190 meta_color_spec_free (op->data.line.color_spec);
3191
3192 meta_draw_spec_free (op->data.line.x1);
3193 meta_draw_spec_free (op->data.line.y1);
3194 meta_draw_spec_free (op->data.line.x2);
3195 meta_draw_spec_free (op->data.line.y2);
3196 break;
3197
3198 case META_DRAW_RECTANGLE:
3199 if (op->data.rectangle.color_spec)
3200 g_free (op->data.rectangle.color_spec);
3201
3202 meta_draw_spec_free (op->data.rectangle.x);
3203 meta_draw_spec_free (op->data.rectangle.y);
3204 meta_draw_spec_free (op->data.rectangle.width);
3205 meta_draw_spec_free (op->data.rectangle.height);
3206 break;
3207
3208 case META_DRAW_ARC:
3209 if (op->data.arc.color_spec)
3210 g_free (op->data.arc.color_spec);
3211
3212 meta_draw_spec_free (op->data.arc.x);
3213 meta_draw_spec_free (op->data.arc.y);
3214 meta_draw_spec_free (op->data.arc.width);
3215 meta_draw_spec_free (op->data.arc.height);
3216 break;
3217
3218 case META_DRAW_CLIP:
3219 meta_draw_spec_free (op->data.clip.x);
3220 meta_draw_spec_free (op->data.clip.y);
3221 meta_draw_spec_free (op->data.clip.width);
3222 meta_draw_spec_free (op->data.clip.height);
3223 break;
3224
3225 case META_DRAW_TINT:
3226 if (op->data.tint.color_spec)
3227 meta_color_spec_free (op->data.tint.color_spec);
3228
3229 if (op->data.tint.alpha_spec)
3230 meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
3231
3232 meta_draw_spec_free (op->data.tint.x);
3233 meta_draw_spec_free (op->data.tint.y);
3234 meta_draw_spec_free (op->data.tint.width);
3235 meta_draw_spec_free (op->data.tint.height);
3236 break;
3237
3238 case META_DRAW_GRADIENT:
3239 if (op->data.gradient.gradient_spec)
3240 meta_gradient_spec_free (op->data.gradient.gradient_spec);
3241
3242 if (op->data.gradient.alpha_spec)
3243 meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
3244
3245 meta_draw_spec_free (op->data.gradient.x);
3246 meta_draw_spec_free (op->data.gradient.y);
3247 meta_draw_spec_free (op->data.gradient.width);
3248 meta_draw_spec_free (op->data.gradient.height);
3249 break;
3250
3251 case META_DRAW_IMAGE:
3252 if (op->data.image.alpha_spec)
3253 meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
3254
3255 if (op->data.image.pixbuf)
3256 g_object_unref (G_OBJECT (op->data.image.pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.pixbuf)), (((GType) ((20) << (2)
)))))))
);
3257
3258 if (op->data.image.colorize_spec)
3259 meta_color_spec_free (op->data.image.colorize_spec);
3260
3261 if (op->data.image.colorize_cache_pixbuf)
3262 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3263
3264 meta_draw_spec_free (op->data.image.x);
3265 meta_draw_spec_free (op->data.image.y);
3266 meta_draw_spec_free (op->data.image.width);
3267 meta_draw_spec_free (op->data.image.height);
3268 break;
3269
3270 case META_DRAW_GTK_ARROW:
3271 meta_draw_spec_free (op->data.gtk_arrow.x);
3272 meta_draw_spec_free (op->data.gtk_arrow.y);
3273 meta_draw_spec_free (op->data.gtk_arrow.width);
3274 meta_draw_spec_free (op->data.gtk_arrow.height);
3275 break;
3276
3277 case META_DRAW_GTK_BOX:
3278 meta_draw_spec_free (op->data.gtk_box.x);
3279 meta_draw_spec_free (op->data.gtk_box.y);
3280 meta_draw_spec_free (op->data.gtk_box.width);
3281 meta_draw_spec_free (op->data.gtk_box.height);
3282 break;
3283
3284 case META_DRAW_GTK_VLINE:
3285 meta_draw_spec_free (op->data.gtk_vline.x);
3286 meta_draw_spec_free (op->data.gtk_vline.y1);
3287 meta_draw_spec_free (op->data.gtk_vline.y2);
3288 break;
3289
3290 case META_DRAW_ICON:
3291 if (op->data.icon.alpha_spec)
3292 meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
3293
3294 meta_draw_spec_free (op->data.icon.x);
3295 meta_draw_spec_free (op->data.icon.y);
3296 meta_draw_spec_free (op->data.icon.width);
3297 meta_draw_spec_free (op->data.icon.height);
3298 break;
3299
3300 case META_DRAW_TITLE:
3301 if (op->data.title.color_spec)
3302 meta_color_spec_free (op->data.title.color_spec);
3303
3304 meta_draw_spec_free (op->data.title.x);
3305 meta_draw_spec_free (op->data.title.y);
3306 if (op->data.title.ellipsize_width)
3307 meta_draw_spec_free (op->data.title.ellipsize_width);
3308 break;
3309
3310 case META_DRAW_OP_LIST:
3311 if (op->data.op_list.op_list)
3312 meta_draw_op_list_unref (op->data.op_list.op_list);
3313
3314 meta_draw_spec_free (op->data.op_list.x);
3315 meta_draw_spec_free (op->data.op_list.y);
3316 meta_draw_spec_free (op->data.op_list.width);
3317 meta_draw_spec_free (op->data.op_list.height);
3318 break;
3319
3320 case META_DRAW_TILE:
3321 if (op->data.tile.op_list)
3322 meta_draw_op_list_unref (op->data.tile.op_list);
3323
3324 meta_draw_spec_free (op->data.tile.x);
3325 meta_draw_spec_free (op->data.tile.y);
3326 meta_draw_spec_free (op->data.tile.width);
3327 meta_draw_spec_free (op->data.tile.height);
3328 meta_draw_spec_free (op->data.tile.tile_xoffset);
3329 meta_draw_spec_free (op->data.tile.tile_yoffset);
3330 meta_draw_spec_free (op->data.tile.tile_width);
3331 meta_draw_spec_free (op->data.tile.tile_height);
3332 break;
3333 }
3334
3335 g_free (op);
3336}
3337
3338static GdkPixbuf*
3339apply_alpha (GdkPixbuf *pixbuf,
3340 MetaAlphaGradientSpec *spec,
3341 gboolean force_copy)
3342{
3343 GdkPixbuf *new_pixbuf;
3344 gboolean needs_alpha;
3345
3346 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return (((void*)0)); } } while
(0)
;
3347
3348 needs_alpha = spec && (spec->n_alphas > 1 ||
3349 spec->alphas[0] != 0xff);
3350
3351 if (!needs_alpha)
3352 return pixbuf;
3353
3354 if (!gdk_pixbuf_get_has_alpha (pixbuf))
3355 {
3356 new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE(0), 0, 0, 0);
3357 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3358 pixbuf = new_pixbuf;
3359 }
3360 else if (force_copy)
3361 {
3362 new_pixbuf = gdk_pixbuf_copy (pixbuf);
3363 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3364 pixbuf = new_pixbuf;
3365 }
3366
3367 g_assert (gdk_pixbuf_get_has_alpha (pixbuf))do { if (gdk_pixbuf_get_has_alpha (pixbuf)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 3367, ((const char*) (__func__)), "gdk_pixbuf_get_has_alpha (pixbuf)"
); } while (0)
;
3368
3369 meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
3370
3371 return pixbuf;
3372}
3373
3374static GdkPixbuf*
3375pixbuf_tile (GdkPixbuf *tile,
3376 int width,
3377 int height)
3378{
3379 GdkPixbuf *pixbuf;
3380 int tile_width;
3381 int tile_height;
3382 int i, j;
3383
3384 tile_width = gdk_pixbuf_get_width (tile);
3385 tile_height = gdk_pixbuf_get_height (tile);
3386
3387 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3388 gdk_pixbuf_get_has_alpha (tile),
3389 8, width, height);
3390
3391 i = 0;
3392 while (i < width)
3393 {
3394 j = 0;
3395 while (j < height)
3396 {
3397 int w, h;
3398
3399 w = MIN (tile_width, width - i)(((tile_width) < (width - i)) ? (tile_width) : (width - i)
)
;
3400 h = MIN (tile_height, height - j)(((tile_height) < (height - j)) ? (tile_height) : (height -
j))
;
3401
3402 gdk_pixbuf_copy_area (tile,
3403 0, 0,
3404 w, h,
3405 pixbuf,
3406 i, j);
3407
3408 j += tile_height;
3409 }
3410
3411 i += tile_width;
3412 }
3413
3414 return pixbuf;
3415}
3416
3417static GdkPixbuf *
3418replicate_rows (GdkPixbuf *src,
3419 int src_x,
3420 int src_y,
3421 int width,
3422 int height)
3423{
3424 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3425 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3426 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3427 * n_channels);
3428 unsigned char *dest_pixels;
3429 GdkPixbuf *result;
3430 unsigned int dest_rowstride;
3431 int i;
3432
3433 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3434 width, height);
3435 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3436 dest_pixels = gdk_pixbuf_get_pixels (result);
3437
3438 for (i = 0; i < height; i++)
3439 memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
3440
3441 return result;
3442}
3443
3444static GdkPixbuf *
3445replicate_cols (GdkPixbuf *src,
3446 int src_x,
3447 int src_y,
3448 int width,
3449 int height)
3450{
3451 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3452 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3453 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3454 * n_channels);
3455 unsigned char *dest_pixels;
3456 GdkPixbuf *result;
3457 unsigned int dest_rowstride;
3458 int i, j;
3459
3460 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3461 width, height);
3462 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3463 dest_pixels = gdk_pixbuf_get_pixels (result);
3464
3465 for (i = 0; i < height; i++)
3466 {
3467 unsigned char *p = dest_pixels + dest_rowstride * i;
3468 unsigned char *q = pixels + src_rowstride * i;
3469
3470 unsigned char r = *(q++);
3471 unsigned char g = *(q++);
3472 unsigned char b = *(q++);
3473
3474 if (n_channels == 4)
3475 {
3476 unsigned char a;
3477
3478 a = *(q++);
3479
3480 for (j = 0; j < width; j++)
3481 {
3482 *(p++) = r;
3483 *(p++) = g;
3484 *(p++) = b;
3485 *(p++) = a;
3486 }
3487 }
3488 else
3489 {
3490 for (j = 0; j < width; j++)
3491 {
3492 *(p++) = r;
3493 *(p++) = g;
3494 *(p++) = b;
3495 }
3496 }
3497 }
3498
3499 return result;
3500}
3501
3502static GdkPixbuf*
3503scale_and_alpha_pixbuf (GdkPixbuf *src,
3504 MetaAlphaGradientSpec *alpha_spec,
3505 MetaImageFillType fill_type,
3506 int width,
3507 int height,
3508 gboolean vertical_stripes,
3509 gboolean horizontal_stripes)
3510{
3511 GdkPixbuf *pixbuf;
3512 GdkPixbuf *temp_pixbuf;
3513
3514 pixbuf = NULL((void*)0);
3515
3516 pixbuf = src;
3517
3518 if (gdk_pixbuf_get_width (pixbuf) == width &&
3519 gdk_pixbuf_get_height (pixbuf) == height)
3520 {
3521 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
3522 }
3523 else
3524 {
3525 if (fill_type == META_IMAGE_FILL_TILE)
3526 {
3527 pixbuf = pixbuf_tile (pixbuf, width, height);
3528 }
3529 else
3530 {
3531 int src_h, src_w, dest_h, dest_w;
3532 src_h = gdk_pixbuf_get_height (src);
3533 src_w = gdk_pixbuf_get_width (src);
3534
3535 /* prefer to replicate_cols if possible, as that
3536 * is faster (no memory reads)
3537 */
3538 if (horizontal_stripes)
3539 {
3540 dest_w = gdk_pixbuf_get_width (src);
3541 dest_h = height;
3542 }
3543 else if (vertical_stripes)
3544 {
3545 dest_w = width;
3546 dest_h = gdk_pixbuf_get_height (src);
3547 }
3548
3549 else
3550 {
3551 dest_w = width;
3552 dest_h = height;
3553 }
3554
3555 if (dest_w == src_w && dest_h == src_h)
3556 {
3557 temp_pixbuf = src;
3558 g_object_ref (G_OBJECT (temp_pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2)))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2))))))))))
;
3559 }
3560 else
3561 {
3562 temp_pixbuf = gdk_pixbuf_scale_simple (src,
3563 dest_w, dest_h,
3564 GDK_INTERP_BILINEAR);
3565 }
3566
3567 /* prefer to replicate_cols if possible, as that
3568 * is faster (no memory reads)
3569 */
3570 if (horizontal_stripes)
3571 {
3572 pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
3573 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3574 }
3575 else if (vertical_stripes)
3576 {
3577 pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
3578 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3579 }
3580 else
3581 {
3582 pixbuf = temp_pixbuf;
3583 }
3584 }
3585 }
3586
3587 if (pixbuf)
3588 pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
3589
3590 return pixbuf;
3591}
3592
3593static GdkPixbuf*
3594draw_op_as_pixbuf (const MetaDrawOp *op,
3595 GtkStyleContext *style,
3596 const MetaDrawInfo *info,
3597 int width,
3598 int height)
3599{
3600 /* Try to get the op as a pixbuf, assuming w/h in the op
3601 * matches the width/height passed in. return NULL
3602 * if the op can't be converted to an equivalent pixbuf.
3603 */
3604 GdkPixbuf *pixbuf;
3605
3606 pixbuf = NULL((void*)0);
3607
3608 switch (op->type)
3609 {
3610 case META_DRAW_LINE:
3611 break;
3612
3613 case META_DRAW_RECTANGLE:
3614 if (op->data.rectangle.filled)
3615 {
3616 GdkRGBA color;
3617
3618 meta_color_spec_render (op->data.rectangle.color_spec,
3619 style,
3620 &color);
3621
3622 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3623 FALSE(0),
3624 8, width, height);
3625
3626 gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
);
3627 }
3628 break;
3629
3630 case META_DRAW_ARC:
3631 break;
3632
3633 case META_DRAW_CLIP:
3634 break;
3635
3636 case META_DRAW_TINT:
3637 {
3638 GdkRGBA color;
3639 guint32 rgba;
3640 gboolean has_alpha;
3641
3642 meta_color_spec_render (op->data.rectangle.color_spec,
3643 style,
3644 &color);
3645
3646 has_alpha =
3647 op->data.tint.alpha_spec &&
3648 (op->data.tint.alpha_spec->n_alphas > 1 ||
3649 op->data.tint.alpha_spec->alphas[0] != 0xff);
3650
3651 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3652 has_alpha,
3653 8, width, height);
3654
3655 if (!has_alpha)
3656 {
3657 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3658
3659 gdk_pixbuf_fill (pixbuf, rgba);
3660 }
3661 else if (op->data.tint.alpha_spec->n_alphas == 1)
3662 {
3663 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3664 rgba &= ~0xff;
3665 rgba |= op->data.tint.alpha_spec->alphas[0];
3666
3667 gdk_pixbuf_fill (pixbuf, rgba);
3668 }
3669 else
3670 {
3671 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3672
3673 gdk_pixbuf_fill (pixbuf, rgba);
3674
3675 meta_gradient_add_alpha (pixbuf,
3676 op->data.tint.alpha_spec->alphas,
3677 op->data.tint.alpha_spec->n_alphas,
3678 op->data.tint.alpha_spec->type);
3679 }
3680 }
3681 break;
3682
3683 case META_DRAW_IMAGE:
3684 {
3685 if (op->data.image.colorize_spec)
3686 {
3687 GdkRGBA color;
3688
3689 meta_color_spec_render (op->data.image.colorize_spec,
3690 style, &color);
3691
3692 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3693 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3694 {
3695 if (op->data.image.colorize_cache_pixbuf)
3696 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3697
3698 /* const cast here */
3699 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3700 colorize_pixbuf (op->data.image.pixbuf,
3701 &color);
3702 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3703 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3704 }
3705
3706 if (op->data.image.colorize_cache_pixbuf)
3707 {
3708 pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
3709 op->data.image.alpha_spec,
3710 op->data.image.fill_type,
3711 width, height,
3712 op->data.image.vertical_stripes,
3713 op->data.image.horizontal_stripes);
3714 }
3715 }
3716 else
3717 {
3718 pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
3719 op->data.image.alpha_spec,
3720 op->data.image.fill_type,
3721 width, height,
3722 op->data.image.vertical_stripes,
3723 op->data.image.horizontal_stripes);
3724 }
3725 break;
3726 }
3727
3728 case META_DRAW_GRADIENT:
3729 case META_DRAW_GTK_ARROW:
3730 case META_DRAW_GTK_BOX:
3731 case META_DRAW_GTK_VLINE:
3732 break;
3733
3734 case META_DRAW_ICON:
3735 if (info->mini_icon &&
3736 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3737 height <= gdk_pixbuf_get_height (info->mini_icon))
3738 pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
3739 op->data.icon.alpha_spec,
3740 op->data.icon.fill_type,
3741 width, height,
3742 FALSE(0), FALSE(0));
3743 else if (info->icon)
3744 pixbuf = scale_and_alpha_pixbuf (info->icon,
3745 op->data.icon.alpha_spec,
3746 op->data.icon.fill_type,
3747 width, height,
3748 FALSE(0), FALSE(0));
3749 break;
3750
3751 case META_DRAW_TITLE:
3752 break;
3753
3754 case META_DRAW_OP_LIST:
3755 break;
3756
3757 case META_DRAW_TILE:
3758 break;
3759 }
3760
3761 return pixbuf;
3762}
3763
3764static cairo_surface_t *
3765draw_op_as_surface (const MetaDrawOp *op,
3766 GtkStyleContext *style,
3767 const MetaDrawInfo *info,
3768 gdouble width,
3769 gdouble height)
3770{
3771 cairo_surface_t *surface;
3772
3773 surface = NULL((void*)0);
3774
3775 switch (op->type)
3776 {
3777 case META_DRAW_IMAGE:
3778 {
3779 if (op->data.image.colorize_spec)
3780 {
3781 GdkRGBA color;
3782
3783 meta_color_spec_render (op->data.image.colorize_spec,
3784 style, &color);
3785
3786 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3787 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3788 {
3789 if (op->data.image.colorize_cache_pixbuf)
3790 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3791
3792 /* const cast here */
3793 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3794 colorize_pixbuf (op->data.image.pixbuf,
3795 &color);
3796 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3797 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3798 }
3799
3800 if (op->data.image.colorize_cache_pixbuf)
3801 {
3802 surface = get_surface_from_pixbuf (op->data.image.colorize_cache_pixbuf,
3803 op->data.image.fill_type,
3804 width, height,
3805 op->data.image.vertical_stripes,
3806 op->data.image.horizontal_stripes);
3807 }
3808 }
3809 else
3810 {
3811 surface = get_surface_from_pixbuf (op->data.image.pixbuf,
3812 op->data.image.fill_type,
3813 width, height,
3814 op->data.image.vertical_stripes,
3815 op->data.image.horizontal_stripes);
3816 }
3817 break;
3818 }
3819
3820 case META_DRAW_ICON:
3821 if (info->mini_icon &&
3822 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3823 height <= gdk_pixbuf_get_height (info->mini_icon))
3824 surface = get_surface_from_pixbuf (info->mini_icon, op->data.icon.fill_type,
3825 width, height, FALSE(0), FALSE(0));
3826 else if (info->icon)
3827 surface = get_surface_from_pixbuf (info->icon, op->data.icon.fill_type,
3828 width, height, FALSE(0), FALSE(0));
3829 break;
3830
3831 case META_DRAW_TINT:
3832 case META_DRAW_LINE:
3833 case META_DRAW_RECTANGLE:
3834 case META_DRAW_ARC:
3835 case META_DRAW_CLIP:
3836 case META_DRAW_GRADIENT:
3837 case META_DRAW_GTK_ARROW:
3838 case META_DRAW_GTK_BOX:
3839 case META_DRAW_GTK_VLINE:
3840 case META_DRAW_TITLE:
3841 case META_DRAW_OP_LIST:
3842 case META_DRAW_TILE:
3843 break;
3844
3845 default:
3846 break;
3847 }
3848
3849 return surface;
3850}
3851
3852static void
3853fill_env (MetaPositionExprEnv *env,
3854 const MetaDrawInfo *info,
3855 MetaRectangle logical_region)
3856{
3857 /* FIXME this stuff could be raised into draw_op_list_draw() probably
3858 */
3859 env->rect = logical_region;
3860 env->object_width = -1;
3861 env->object_height = -1;
3862 if (info->fgeom)
3863 {
3864 env->left_width = info->fgeom->borders.visible.left;
3865 env->right_width = info->fgeom->borders.visible.right;
3866 env->top_height = info->fgeom->borders.visible.top;
3867 env->bottom_height = info->fgeom->borders.visible.bottom;
3868 env->frame_x_center = info->fgeom->width / 2 - logical_region.x;
3869 env->frame_y_center = info->fgeom->height / 2 - logical_region.y;
3870 }
3871 else
3872 {
3873 env->left_width = 0;
3874 env->right_width = 0;
3875 env->top_height = 0;
3876 env->bottom_height = 0;
3877 env->frame_x_center = 0;
3878 env->frame_y_center = 0;
3879 }
3880
3881 env->mini_icon_width = info->mini_icon ? gdk_pixbuf_get_width (info->mini_icon) : 0;
3882 env->mini_icon_height = info->mini_icon ? gdk_pixbuf_get_height (info->mini_icon) : 0;
3883 env->icon_width = info->icon ? gdk_pixbuf_get_width (info->icon) : 0;
3884 env->icon_height = info->icon ? gdk_pixbuf_get_height (info->icon) : 0;
3885
3886 env->title_width = info->title_layout_width;
3887 env->title_height = info->title_layout_height;
3888 env->theme = meta_current_theme;
3889}
3890
3891/* This code was originally rendering anti-aliased using X primitives, and
3892 * now has been switched to draw anti-aliased using cairo. In general, the
3893 * closest correspondence between X rendering and cairo rendering is given
3894 * by offsetting the geometry by 0.5 pixels in both directions before rendering
3895 * with cairo. This is because X samples at the upper left corner of the
3896 * pixel while cairo averages over the entire pixel. However, in the cases
3897 * where the X rendering was an exact rectangle with no "jaggies"
3898 * we need to be a bit careful about applying the offset. We want to produce
3899 * the exact same pixel-aligned rectangle, rather than a rectangle with
3900 * fuzz around the edges.
3901 */
3902static void
3903meta_draw_op_draw_with_env (const MetaDrawOp *op,
3904 GtkStyleContext *style_gtk,
3905 cairo_t *cr,
3906 const MetaDrawInfo *info,
3907 MetaRectangle rect,
3908 MetaPositionExprEnv *env)
3909{
3910 GdkRGBA color;
3911
3912 cairo_save (cr);
3913 gtk_style_context_save (style_gtk);
3914
3915 cairo_set_line_width (cr, 1.0);
3916
3917 switch (op->type)
3918 {
3919 case META_DRAW_LINE:
3920 {
3921 int x1, x2, y1, y2;
3922
3923 meta_color_spec_render (op->data.line.color_spec, style_gtk, &color);
3924 gdk_cairo_set_source_rgba (cr, &color);
3925
3926 if (op->data.line.width > 0)
3927 cairo_set_line_width (cr, op->data.line.width);
3928
3929 if (op->data.line.dash_on_length > 0 &&
3930 op->data.line.dash_off_length > 0)
3931 {
3932 double dash_list[2];
3933 dash_list[0] = op->data.line.dash_on_length;
3934 dash_list[1] = op->data.line.dash_off_length;
3935 cairo_set_dash (cr, dash_list, 2, 0);
3936 }
3937
3938 x1 = parse_x_position_unchecked (op->data.line.x1, env);
3939 y1 = parse_y_position_unchecked (op->data.line.y1, env);
3940
3941 if (!op->data.line.x2 &&
3942 !op->data.line.y2 &&
3943 op->data.line.width==0)
3944 {
3945 cairo_rectangle (cr, x1, y1, 1, 1);
3946 cairo_fill (cr);
3947 }
3948 else
3949 {
3950 if (op->data.line.x2)
3951 x2 = parse_x_position_unchecked (op->data.line.x2, env);
3952 else
3953 x2 = x1;
3954
3955 if (op->data.line.y2)
3956 y2 = parse_y_position_unchecked (op->data.line.y2, env);
3957 else
3958 y2 = y1;
3959
3960 /* This is one of the cases where we are matching the exact
3961 * pixel aligned rectangle produced by X; for zero-width lines
3962 * the generic algorithm produces the right result so we don't
3963 * need to handle them here.
3964 */
3965 if ((y1 == y2 || x1 == x2) && op->data.line.width != 0)
3966 {
3967 double offset = op->data.line.width % 2 ? .5 : 0;
3968
3969 if (y1 == y2)
3970 {
3971 cairo_move_to (cr, x1, y1 + offset);
3972 cairo_line_to (cr, x2, y2 + offset);
3973 }
3974 else
3975 {
3976 cairo_move_to (cr, x1 + offset, y1);
3977 cairo_line_to (cr, x2 + offset, y2);
3978 }
3979 }
3980 else
3981 {
3982 /* zero-width lines include both end-points in X, unlike wide lines */
3983 if (op->data.line.width == 0)
3984 cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
3985
3986 cairo_move_to (cr, x1 + .5, y1 + .5);
3987 cairo_line_to (cr, x2 + .5, y2 + .5);
3988 }
3989 cairo_stroke (cr);
3990 }
3991 }
3992 break;
3993
3994 case META_DRAW_RECTANGLE:
3995 {
3996 int rx, ry, rwidth, rheight;
3997
3998 meta_color_spec_render (op->data.rectangle.color_spec, style_gtk, &color);
3999 gdk_cairo_set_source_rgba (cr, &color);
4000
4001 rx = parse_x_position_unchecked (op->data.rectangle.x, env);
4002 ry = parse_y_position_unchecked (op->data.rectangle.y, env);
4003 rwidth = parse_size_unchecked (op->data.rectangle.width, env);
4004 rheight = parse_size_unchecked (op->data.rectangle.height, env);
4005
4006 /* Filled and stroked rectangles are the other cases
4007 * we pixel-align to X rasterization
4008 */
4009 if (op->data.rectangle.filled)
4010 {
4011 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4012 cairo_fill (cr);
4013 }
4014 else
4015 {
4016 cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight);
4017 cairo_stroke (cr);
4018 }
4019 }
4020 break;
4021
4022 case META_DRAW_ARC:
4023 {
4024 int rx, ry, rwidth, rheight;
4025 double start_angle, end_angle;
4026 double center_x, center_y;
4027
4028 meta_color_spec_render (op->data.arc.color_spec, style_gtk, &color);
4029 gdk_cairo_set_source_rgba (cr, &color);
4030
4031 rx = parse_x_position_unchecked (op->data.arc.x, env);
4032 ry = parse_y_position_unchecked (op->data.arc.y, env);
4033 rwidth = parse_size_unchecked (op->data.arc.width, env);
4034 rheight = parse_size_unchecked (op->data.arc.height, env);
4035
4036 start_angle = op->data.arc.start_angle * (M_PI3.14159265358979323846 / 180.)
4037 - (.5 * M_PI3.14159265358979323846); /* start at 12 instead of 3 oclock */
4038 end_angle = start_angle + op->data.arc.extent_angle * (M_PI3.14159265358979323846 / 180.);
4039 center_x = rx + (double)rwidth / 2. + .5;
4040 center_y = ry + (double)rheight / 2. + .5;
4041
4042 cairo_save (cr);
4043
4044 cairo_translate (cr, center_x, center_y);
4045 cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.);
4046
4047 if (op->data.arc.extent_angle >= 0)
4048 cairo_arc (cr, 0, 0, 1, start_angle, end_angle);
4049 else
4050 cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle);
4051
4052 cairo_restore (cr);
4053
4054 if (op->data.arc.filled)
4055 {
4056 cairo_line_to (cr, center_x, center_y);
4057 cairo_fill (cr);
4058 }
4059 else
4060 cairo_stroke (cr);
4061 }
4062 break;
4063
4064 case META_DRAW_CLIP:
4065 break;
4066
4067 case META_DRAW_TINT:
4068 {
4069 int rx, ry, rwidth, rheight;
4070 gboolean needs_alpha;
4071
4072 needs_alpha = op->data.tint.alpha_spec &&
4073 (op->data.tint.alpha_spec->n_alphas > 1 ||
4074 op->data.tint.alpha_spec->alphas[0] != 0xff);
4075
4076 rx = parse_x_position_unchecked (op->data.tint.x, env);
4077 ry = parse_y_position_unchecked (op->data.tint.y, env);
4078 rwidth = parse_size_unchecked (op->data.tint.width, env);
4079 rheight = parse_size_unchecked (op->data.tint.height, env);
4080
4081 if (!needs_alpha)
4082 {
4083 meta_color_spec_render (op->data.tint.color_spec, style_gtk, &color);
4084 gdk_cairo_set_source_rgba (cr, &color);
4085
4086 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4087 cairo_fill (cr);
4088 }
4089 else
4090 {
4091 GdkPixbuf *pixbuf;
4092
4093 pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
4094 rwidth, rheight);
4095
4096 if (pixbuf)
4097 {
4098 gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
4099 cairo_paint (cr);
4100
4101 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
4102 }
4103 }
4104 }
4105 break;
4106
4107 case META_DRAW_GRADIENT:
4108 {
4109 int rx, ry, rwidth, rheight;
4110
4111 rx = parse_x_position_unchecked (op->data.gradient.x, env);
4112 ry = parse_y_position_unchecked (op->data.gradient.y, env);
4113 rwidth = parse_size_unchecked (op->data.gradient.width, env);
4114 rheight = parse_size_unchecked (op->data.gradient.height, env);
4115
4116 meta_gradient_spec_render (op->data.gradient.gradient_spec,
4117 op->data.gradient.alpha_spec,
4118 cr, style_gtk, rx, ry, rwidth, rheight);
4119 }
4120 break;
4121
4122 case META_DRAW_IMAGE:
4123 {
4124 gint scale;
4125 gdouble rx, ry, rwidth, rheight;
4126 cairo_surface_t *surface;
4127
4128 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4129 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4130
4131 if (op->data.image.pixbuf)
4132 {
4133 env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf) / scale;
4134 env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf) / scale;
4135 }
4136
4137 rwidth = parse_size_unchecked (op->data.image.width, env) * scale;
4138 rheight = parse_size_unchecked (op->data.image.height, env) * scale;
4139
4140 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4141
4142 if (surface)
4143 {
4144 rx = parse_x_position_unchecked (op->data.image.x, env) * scale;
4145 ry = parse_y_position_unchecked (op->data.image.y, env) * scale;
4146
4147 cairo_set_source_surface (cr, surface, rx, ry);
4148
4149 if (op->data.image.alpha_spec)
4150 {
4151 cairo_pattern_t *pattern;
4152
4153 cairo_translate (cr, rx, ry);
4154 cairo_scale (cr, rwidth, rheight);
4155
4156 pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec);
4157 cairo_mask (cr, pattern);
4158
4159 cairo_pattern_destroy (pattern);
4160 }
4161 else
4162 {
4163 cairo_paint (cr);
4164 }
4165
4166 cairo_surface_destroy (surface);
4167 }
4168 }
4169 break;
4170
4171 case META_DRAW_GTK_ARROW:
4172 {
4173 int rx, ry, rwidth, rheight;
4174
4175 rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
4176 ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
4177 rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
4178 rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
4179
4180 double size = MAX(rwidth, rheight)(((rwidth) > (rheight)) ? (rwidth) : (rheight)), angle = 0;
4181
4182 switch (op->data.gtk_arrow.arrow)
4183 {
4184 case GTK_ARROW_UP:
4185 angle = 0;
4186 break;
4187 case GTK_ARROW_RIGHT:
4188 angle = M_PI3.14159265358979323846 / 2;
4189 break;
4190 case GTK_ARROW_DOWN:
4191 angle = M_PI3.14159265358979323846;
4192 break;
4193 case GTK_ARROW_LEFT:
4194 angle = 3 * M_PI3.14159265358979323846 / 2;
4195 break;
4196 case GTK_ARROW_NONE:
4197 return;
4198 }
4199
4200 gtk_style_context_set_state (style_gtk, op->data.gtk_arrow.state);
4201 gtk_render_arrow (style_gtk, cr, angle, rx, ry, size);
4202 }
4203 break;
4204
4205 case META_DRAW_GTK_BOX:
4206 {
4207 int rx, ry, rwidth, rheight;
4208
4209 rx = parse_x_position_unchecked (op->data.gtk_box.x, env);
4210 ry = parse_y_position_unchecked (op->data.gtk_box.y, env);
4211 rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
4212 rheight = parse_size_unchecked (op->data.gtk_box.height, env);
4213
4214 gtk_style_context_set_state (style_gtk, op->data.gtk_box.state);
4215 gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight);
4216 gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight);
4217 }
4218 break;
4219
4220 case META_DRAW_GTK_VLINE:
4221 {
4222 int rx, ry1, ry2;
4223
4224 rx = parse_x_position_unchecked (op->data.gtk_vline.x, env);
4225 ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
4226 ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
4227
4228 gtk_style_context_set_state (style_gtk, op->data.gtk_vline.state);
4229 gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2);
4230 }
4231 break;
4232
4233 case META_DRAW_ICON:
4234 {
4235 gint scale;
4236 gdouble rx, ry, rwidth, rheight;
4237 cairo_surface_t *surface;
4238
4239 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4240 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4241
4242 rwidth = parse_size_unchecked (op->data.icon.width, env) * scale;
4243 rheight = parse_size_unchecked (op->data.icon.height, env) * scale;
4244
4245 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4246
4247 if (surface)
4248 {
4249 rx = parse_x_position_unchecked (op->data.icon.x, env) * scale;
4250 ry = parse_y_position_unchecked (op->data.icon.y, env) * scale;
4251
4252 cairo_set_source_surface (cr, surface, rx, ry);
4253
4254 if (op->data.icon.alpha_spec)
4255 {
4256 cairo_pattern_t *pattern;
4257
4258 cairo_translate (cr, rx, ry);
4259 cairo_scale (cr, rwidth, rheight);
4260
4261 pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec);
4262 cairo_mask (cr, pattern);
4263
4264 cairo_pattern_destroy (pattern);
4265 }
4266 else
4267 {
4268 cairo_paint (cr);
4269 }
4270
4271 cairo_surface_destroy (surface);
4272 }
4273 }
4274 break;
4275
4276 case META_DRAW_TITLE:
4277 if (info->title_layout)
4278 {
4279 int rx, ry;
4280 PangoRectangle ink_rect, logical_rect;
4281
4282 meta_color_spec_render (op->data.title.color_spec, style_gtk, &color);
4283 gdk_cairo_set_source_rgba (cr, &color);
4284
4285 rx = parse_x_position_unchecked (op->data.title.x, env);
4286 ry = parse_y_position_unchecked (op->data.title.y, env);
4287
4288 if (op->data.title.ellipsize_width)
4289 {
4290 int ellipsize_width;
4291 int right_bearing;
4292
4293 ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env);
4294 /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */
4295 ellipsize_width -= env->rect.x;
4296
4297 pango_layout_set_width (info->title_layout, -1);
4298 pango_layout_get_pixel_extents (info->title_layout,
4299 &ink_rect, &logical_rect);
4300
4301 /* Pango's idea of ellipsization is with respect to the logical rect.
4302 * correct for this, by reducing the ellipsization width by the overflow
4303 * of the un-ellipsized text on the right... it's always the visual
4304 * right we want regardless of bidi, since since the X we pass in to
4305 * cairo_move_to() is always the left edge of the line.
4306 */
4307 right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width);
4308 right_bearing = MAX (right_bearing, 0)(((right_bearing) > (0)) ? (right_bearing) : (0));
4309
4310 ellipsize_width -= right_bearing;
4311 ellipsize_width = MAX (ellipsize_width, 0)(((ellipsize_width) > (0)) ? (ellipsize_width) : (0));
4312
4313 /* Only ellipsizing when necessary is a performance optimization -
4314 * pango_layout_set_width() will force a relayout if it isn't the
4315 * same as the current width of -1.
4316 */
4317 if (ellipsize_width < logical_rect.width)
4318 pango_layout_set_width (info->title_layout, PANGO_SCALE1024 * ellipsize_width);
4319 }
4320 else if (rx - env->rect.x + env->title_width >= env->rect.width)
4321 {
4322 const double alpha_margin = 30.0;
4323 int text_space = env->rect.x + env->rect.width -
4324 (rx - env->rect.x) - env->right_width;
4325
4326 double startalpha = 1.0 - (alpha_margin/((double)text_space));
4327
4328 cairo_pattern_t *linpat;
4329 linpat = cairo_pattern_create_linear (rx, ry, text_space,
4330 env->title_height);
4331 cairo_pattern_add_color_stop_rgba (linpat, 0, color.red,
4332 color.green,
4333 color.blue,
4334 color.alpha);
4335 cairo_pattern_add_color_stop_rgba (linpat, startalpha,
4336 color.red,
4337 color.green,
4338 color.blue,
4339 color.alpha);
4340 cairo_pattern_add_color_stop_rgba (linpat, 1, color.red,
4341 color.green,
4342 color.blue, 0);
4343 cairo_set_source(cr, linpat);
4344 cairo_pattern_destroy(linpat);
4345 }
4346
4347 cairo_move_to (cr, rx, ry);
4348 pango_cairo_show_layout (cr, info->title_layout);
4349
4350 /* Remove any ellipsization we might have set; will short-circuit
4351 * if the width is already -1 */
4352 pango_layout_set_width (info->title_layout, -1);
4353 }
4354 break;
4355
4356 case META_DRAW_OP_LIST:
4357 {
4358 MetaRectangle d_rect;
4359
4360 d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env);
4361 d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env);
4362 d_rect.width = parse_size_unchecked (op->data.op_list.width, env);
4363 d_rect.height = parse_size_unchecked (op->data.op_list.height, env);
4364
4365 meta_draw_op_list_draw_with_style (op->data.op_list.op_list,
4366 style_gtk,
4367 cr,
4368 info, d_rect);
4369 }
4370 break;
4371
4372 case META_DRAW_TILE:
4373 {
4374 int rx, ry, rwidth, rheight;
4375 int tile_xoffset, tile_yoffset;
4376 MetaRectangle tile;
4377
4378 rx = parse_x_position_unchecked (op->data.tile.x, env);
4379 ry = parse_y_position_unchecked (op->data.tile.y, env);
4380 rwidth = parse_size_unchecked (op->data.tile.width, env);
4381 rheight = parse_size_unchecked (op->data.tile.height, env);
4382
4383 cairo_save (cr);
4384
4385 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4386 cairo_clip (cr);
4387
4388 tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env);
4389 tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env);
4390 /* tile offset should not include x/y */
4391 tile_xoffset -= rect.x;
4392 tile_yoffset -= rect.y;
4393
4394 tile.width = parse_size_unchecked (op->data.tile.tile_width, env);
4395 tile.height = parse_size_unchecked (op->data.tile.tile_height, env);
4396
4397 tile.x = rx - tile_xoffset;
4398
4399 while (tile.x < (rx + rwidth))
4400 {
4401 tile.y = ry - tile_yoffset;
4402 while (tile.y < (ry + rheight))
4403 {
4404 meta_draw_op_list_draw_with_style (op->data.tile.op_list,
4405 style_gtk, cr, info,
4406 tile);
4407
4408 tile.y += tile.height;
4409 }
4410
4411 tile.x += tile.width;
4412 }
4413 cairo_restore (cr);
4414 }
4415 break;
4416 }
4417
4418 cairo_restore (cr);
4419 gtk_style_context_restore (style_gtk);
4420}
4421
4422void
4423meta_draw_op_draw_with_style (const MetaDrawOp *op,
4424 GtkStyleContext *style_gtk,
4425 cairo_t *cr,
4426 const MetaDrawInfo *info,
4427 MetaRectangle logical_region)
4428{
4429 MetaPositionExprEnv env;
4430
4431 fill_env (&env, info, logical_region);
4432
4433 meta_draw_op_draw_with_env (op,
4434 style_gtk,
4435 cr,
4436 info, logical_region,
4437 &env);
4438
4439}
4440
4441void
4442meta_draw_op_draw (const MetaDrawOp *op,
4443 GtkWidget *widget,
4444 cairo_t *cr,
4445 const MetaDrawInfo *info,
4446 MetaRectangle logical_region)
4447{
4448 meta_draw_op_draw_with_style (op,
4449 gtk_widget_get_style_context (widget),
4450 cr,
4451 info, logical_region);
4452}
4453
4454MetaDrawOpList*
4455meta_draw_op_list_new (int n_preallocs)
4456{
4457 MetaDrawOpList *op_list;
4458
4459 g_return_val_if_fail (n_preallocs >= 0, NULL)do { if ((n_preallocs >= 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_preallocs >= 0")
; return (((void*)0)); } } while (0)
;
4460
4461 op_list = g_new (MetaDrawOpList, 1)((MetaDrawOpList *) g_malloc_n ((1), sizeof (MetaDrawOpList))
)
;
4462
4463 op_list->refcount = 1;
4464 op_list->n_allocated = n_preallocs;
4465 op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated)((MetaDrawOp* *) g_malloc_n ((op_list->n_allocated), sizeof
(MetaDrawOp*)))
;
4466 op_list->n_ops = 0;
4467
4468 return op_list;
4469}
4470
4471void
4472meta_draw_op_list_ref (MetaDrawOpList *op_list)
4473{
4474 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4475
4476 op_list->refcount += 1;
4477}
4478
4479void
4480meta_draw_op_list_unref (MetaDrawOpList *op_list)
4481{
4482 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4483 g_return_if_fail (op_list->refcount > 0)do { if ((op_list->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list->refcount > 0"
); return; } } while (0)
;
4484
4485 op_list->refcount -= 1;
4486
4487 if (op_list->refcount == 0)
4488 {
4489 int i;
4490
4491 for (i = 0; i < op_list->n_ops; i++)
4492 meta_draw_op_free (op_list->ops[i]);
4493
4494 g_free (op_list->ops);
4495
4496 DEBUG_FILL_STRUCT (op_list)memset ((op_list), 0xef, sizeof (*(op_list)));
4497 g_free (op_list);
4498 }
4499}
4500
4501void
4502meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
4503 GtkStyleContext *style_gtk,
4504 cairo_t *cr,
4505 const MetaDrawInfo *info,
4506 MetaRectangle rect)
4507{
4508 /* BOOKMARK */
4509
4510 int i;
4511 MetaPositionExprEnv env;
4512
4513 if (op_list->n_ops == 0)
4514 return;
4515
4516 fill_env (&env, info, rect);
4517
4518 /* FIXME this can be optimized, potentially a lot, by
4519 * compressing multiple ops when possible. For example,
4520 * anything convertible to a pixbuf can be composited
4521 * client-side, and putting a color tint over a pixbuf
4522 * can be done without creating the solid-color pixbuf.
4523 *
4524 * To implement this my plan is to have the idea of a
4525 * compiled draw op (with the string expressions already
4526 * evaluated), we make an array of those, and then fold
4527 * adjacent items when possible.
4528 */
4529
4530 cairo_save (cr);
4531
4532 for (i = 0; i < op_list->n_ops; i++)
4533 {
4534 MetaDrawOp *op = op_list->ops[i];
4535
4536 if (op->type == META_DRAW_CLIP)
4537 {
4538 cairo_restore (cr);
4539
4540 cairo_rectangle (cr,
4541 parse_x_position_unchecked (op->data.clip.x, &env),
4542 parse_y_position_unchecked (op->data.clip.y, &env),
4543 parse_size_unchecked (op->data.clip.width, &env),
4544 parse_size_unchecked (op->data.clip.height, &env));
4545 cairo_clip (cr);
4546
4547 cairo_save (cr);
4548 }
4549 else if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
4550 {
4551 meta_draw_op_draw_with_env (op, style_gtk, cr, info, rect, &env);
4552 }
4553 }
4554
4555 cairo_restore (cr);
4556}
4557
4558void
4559meta_draw_op_list_draw (const MetaDrawOpList *op_list,
4560 GtkWidget *widget,
4561 cairo_t *cr,
4562 const MetaDrawInfo *info,
4563 MetaRectangle rect)
4564
4565{
4566 meta_draw_op_list_draw_with_style (op_list,
4567 gtk_widget_get_style_context (widget),
4568 cr,
4569 info, rect);
4570}
4571
4572void
4573meta_draw_op_list_append (MetaDrawOpList *op_list,
4574 MetaDrawOp *op)
4575{
4576 if (op_list->n_ops == op_list->n_allocated)
4577 {
4578 op_list->n_allocated *= 2;
4579 op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated)((MetaDrawOp* *) g_realloc_n (op_list->ops, (op_list->n_allocated
), sizeof (MetaDrawOp*)))
;
4580 }
4581
4582 op_list->ops[op_list->n_ops] = op;
4583 op_list->n_ops += 1;
4584}
4585
4586gboolean
4587meta_draw_op_list_validate (MetaDrawOpList *op_list,
4588 GError **error)
4589{
4590 g_return_val_if_fail (op_list != NULL, FALSE)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
((0)); } } while (0)
;
4591
4592 /* empty lists are OK, nothing else to check really */
4593
4594 return TRUE(!(0));
4595}
4596
4597/* This is not done in validate, since we wouldn't know the name
4598 * of the list to report the error. It might be nice to
4599 * store names inside the list sometime.
4600 */
4601gboolean
4602meta_draw_op_list_contains (MetaDrawOpList *op_list,
4603 MetaDrawOpList *child)
4604{
4605 int i;
4606
4607 /* mmm, huge tree recursion */
4608
4609 for (i = 0; i < op_list->n_ops; i++)
4610 {
4611 if (op_list->ops[i]->type == META_DRAW_OP_LIST)
4612 {
4613 if (op_list->ops[i]->data.op_list.op_list == child)
4614 return TRUE(!(0));
4615
4616 if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list,
4617 child))
4618 return TRUE(!(0));
4619 }
4620 else if (op_list->ops[i]->type == META_DRAW_TILE)
4621 {
4622 if (op_list->ops[i]->data.tile.op_list == child)
4623 return TRUE(!(0));
4624
4625 if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list,
4626 child))
4627 return TRUE(!(0));
4628 }
4629 }
4630
4631 return FALSE(0);
4632}
4633
4634/**
4635 * Constructor for a MetaFrameStyle.
4636 *
4637 * \param parent The parent style. Data not filled in here will be
4638 * looked for in the parent style, and in its parent
4639 * style, and so on.
4640 *
4641 * \return The newly-constructed style.
4642 */
4643MetaFrameStyle*
4644meta_frame_style_new (MetaFrameStyle *parent)
4645{
4646 MetaFrameStyle *style;
4647
4648 style = g_new0 (MetaFrameStyle, 1)((MetaFrameStyle *) g_malloc0_n ((1), sizeof (MetaFrameStyle)
))
;
4649
4650 style->refcount = 1;
4651
4652 /* Default alpha is fully opaque */
4653 style->window_background_alpha = 255;
4654
4655 style->parent = parent;
4656 if (parent)
4657 meta_frame_style_ref (parent);
4658
4659 return style;
4660}
4661
4662/**
4663 * Increases the reference count of a frame style.
4664 * If the style is NULL, this is a no-op.
4665 *
4666 * \param style The style.
4667 */
4668void
4669meta_frame_style_ref (MetaFrameStyle *style)
4670{
4671 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4672
4673 style->refcount += 1;
4674}
4675
4676static void
4677free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
4678{
4679 int i, j;
4680
4681 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4682 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4683 if (op_lists[i][j])
4684 meta_draw_op_list_unref (op_lists[i][j]);
4685}
4686
4687void
4688meta_frame_style_unref (MetaFrameStyle *style)
4689{
4690 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4691 g_return_if_fail (style->refcount > 0)do { if ((style->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->refcount > 0"
); return; } } while (0)
;
4692
4693 style->refcount -= 1;
4694
4695 if (style->refcount == 0)
4696 {
4697 int i;
4698
4699 free_button_ops (style->buttons);
4700
4701 for (i = 0; i < META_FRAME_PIECE_LAST; i++)
4702 if (style->pieces[i])
4703 meta_draw_op_list_unref (style->pieces[i]);
4704
4705 if (style->layout)
4706 meta_frame_layout_unref (style->layout);
4707
4708 if (style->window_background_color)
4709 meta_color_spec_free (style->window_background_color);
4710
4711 /* we hold a reference to any parent style */
4712 if (style->parent)
4713 meta_frame_style_unref (style->parent);
4714
4715 DEBUG_FILL_STRUCT (style)memset ((style), 0xef, sizeof (*(style)));
4716 g_free (style);
4717 }
4718}
4719
4720static MetaButtonState
4721map_button_state (MetaButtonType button_type,
4722 const MetaFrameGeometry *fgeom,
4723 int middle_bg_offset,
4724 MetaButtonState button_states[META_BUTTON_TYPE_LAST])
4725{
4726 MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
4727
4728 switch (button_type)
4729 {
4730 /* First handle functions, which map directly */
4731 case META_BUTTON_TYPE_SHADE:
4732 case META_BUTTON_TYPE_ABOVE:
4733 case META_BUTTON_TYPE_STICK:
4734 case META_BUTTON_TYPE_UNSHADE:
4735 case META_BUTTON_TYPE_UNABOVE:
4736 case META_BUTTON_TYPE_UNSTICK:
4737 case META_BUTTON_TYPE_MENU:
4738 case META_BUTTON_TYPE_APPMENU:
4739 case META_BUTTON_TYPE_MINIMIZE:
4740 case META_BUTTON_TYPE_MAXIMIZE:
4741 case META_BUTTON_TYPE_CLOSE:
4742 return button_states[button_type];
4743
4744 /* Map position buttons to the corresponding function */
4745 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4746 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4747 if (fgeom->n_right_buttons > 0)
4748 function = fgeom->button_layout.right_buttons[0];
4749 break;
4750 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4751 if (fgeom->n_right_buttons > 0)
4752 function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
4753 break;
4754 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4755 if (middle_bg_offset + 1 < fgeom->n_right_buttons)
4756 function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
4757 break;
4758 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4759 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4760 if (fgeom->n_left_buttons > 0)
4761 function = fgeom->button_layout.left_buttons[0];
4762 break;
4763 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4764 if (fgeom->n_left_buttons > 0)
4765 function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
4766 break;
4767 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4768 if (middle_bg_offset + 1 < fgeom->n_left_buttons)
4769 function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
4770 break;
4771 case META_BUTTON_TYPE_LAST:
4772 break;
4773 }
4774
4775 if (function != META_BUTTON_FUNCTION_LAST)
4776 return button_states[map_button_function_to_type (function)];
4777
4778 return META_BUTTON_STATE_LAST;
4779}
4780
4781static MetaDrawOpList*
4782get_button (MetaFrameStyle *style,
4783 MetaButtonType type,
4784 MetaButtonState state)
4785{
4786 MetaDrawOpList *op_list;
4787 MetaFrameStyle *parent;
4788
4789 parent = style;
4790 op_list = NULL((void*)0);
4791 while (parent && op_list == NULL((void*)0))
4792 {
4793 op_list = parent->buttons[type][state];
4794 parent = parent->parent;
4795 }
4796
4797 /* We fall back to the side buttons if we don't have
4798 * single button backgrounds, and to middle button
4799 * backgrounds if we don't have the ones on the sides
4800 */
4801
4802 if (op_list == NULL((void*)0) &&
4803 type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND)
4804 return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state);
4805
4806 if (op_list == NULL((void*)0) &&
4807 type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND)
4808 return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state);
4809
4810 if (op_list == NULL((void*)0) &&
4811 (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
4812 type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
4813 return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
4814 state);
4815
4816 if (op_list == NULL((void*)0) &&
4817 (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND ||
4818 type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND))
4819 return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
4820 state);
4821
4822 /* We fall back to normal if no prelight */
4823 if (op_list == NULL((void*)0) &&
4824 state == META_BUTTON_STATE_PRELIGHT)
4825 return get_button (style, type, META_BUTTON_STATE_NORMAL);
4826
4827 return op_list;
4828}
4829
4830gboolean
4831meta_frame_style_validate (MetaFrameStyle *style,
4832 guint current_theme_version,
4833 GError **error)
4834{
4835 int i, j;
4836
4837 g_return_val_if_fail (style != NULL, FALSE)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
((0)); } } while (0)
;
4838 g_return_val_if_fail (style->layout != NULL, FALSE)do { if ((style->layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->layout != NULL"
); return ((0)); } } while (0)
;
4839
4840 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4841 {
4842 /* for now the "positional" buttons are optional */
4843 if (i >= META_BUTTON_TYPE_CLOSE)
4844 {
4845 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4846 {
4847 if (get_button (style, i, j) == NULL((void*)0) &&
4848 meta_theme_earliest_version_with_button (i) <= current_theme_version
4849 )
4850 {
4851 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
4852 META_THEME_ERROR_FAILED,
4853 _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style")((char *) g_dgettext ("marco", "<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"
))
,
4854 meta_button_type_to_string (i),
4855 meta_button_state_to_string (j));
4856 return FALSE(0);
4857 }
4858 }
4859 }
4860 }
4861
4862 return TRUE(!(0));
4863}
4864
4865static void
4866get_button_rect (MetaButtonType type,
4867 const MetaFrameGeometry *fgeom,
4868 int middle_background_offset,
4869 GdkRectangle *rect)
4870{
4871 switch (type)
4872 {
4873 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4874 *rect = fgeom->left_left_background;
4875 break;
4876
4877 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4878 *rect = fgeom->left_middle_backgrounds[middle_background_offset];
4879 break;
4880
4881 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4882 *rect = fgeom->left_right_background;
4883 break;
4884
4885 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4886 *rect = fgeom->left_single_background;
4887 break;
4888
4889 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4890 *rect = fgeom->right_left_background;
4891 break;
4892
4893 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4894 *rect = fgeom->right_middle_backgrounds[middle_background_offset];
4895 break;
4896
4897 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4898 *rect = fgeom->right_right_background;
4899 break;
4900
4901 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4902 *rect = fgeom->right_single_background;
4903 break;
4904
4905 case META_BUTTON_TYPE_CLOSE:
4906 *rect = fgeom->close_rect.visible;
4907 break;
4908
4909 case META_BUTTON_TYPE_SHADE:
4910 *rect = fgeom->shade_rect.visible;
4911 break;
4912
4913 case META_BUTTON_TYPE_UNSHADE:
4914 *rect = fgeom->unshade_rect.visible;
4915 break;
4916
4917 case META_BUTTON_TYPE_ABOVE:
4918 *rect = fgeom->above_rect.visible;
4919 break;
4920
4921 case META_BUTTON_TYPE_UNABOVE:
4922 *rect = fgeom->unabove_rect.visible;
4923 break;
4924
4925 case META_BUTTON_TYPE_STICK:
4926 *rect = fgeom->stick_rect.visible;
4927 break;
4928
4929 case META_BUTTON_TYPE_UNSTICK:
4930 *rect = fgeom->unstick_rect.visible;
4931 break;
4932
4933 case META_BUTTON_TYPE_MAXIMIZE:
4934 *rect = fgeom->max_rect.visible;
4935 break;
4936
4937 case META_BUTTON_TYPE_MINIMIZE:
4938 *rect = fgeom->min_rect.visible;
4939 break;
4940
4941 case META_BUTTON_TYPE_MENU:
4942 *rect = fgeom->menu_rect.visible;
4943 break;
4944
4945 case META_BUTTON_TYPE_APPMENU:
4946 *rect = fgeom->appmenu_rect.visible;
4947 break;
4948
4949 case META_BUTTON_TYPE_LAST:
4950 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 4950, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
4951 break;
4952 }
4953}
4954
4955void
4956meta_frame_style_draw_with_style (MetaFrameStyle *style,
4957 GtkStyleContext *style_gtk,
4958 cairo_t *cr,
4959 const MetaFrameGeometry *fgeom,
4960 int client_width,
4961 int client_height,
4962 PangoLayout *title_layout,
4963 int text_height,
4964 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
4965 GdkPixbuf *mini_icon,
4966 GdkPixbuf *icon)
4967{
4968 /* BOOKMARK */
4969 int i, j;
4970 GdkRectangle visible_rect;
4971 GdkRectangle titlebar_rect;
4972 GdkRectangle left_titlebar_edge;
4973 GdkRectangle right_titlebar_edge;
4974 GdkRectangle bottom_titlebar_edge;
4975 GdkRectangle top_titlebar_edge;
4976 GdkRectangle left_edge, right_edge, bottom_edge;
4977 PangoRectangle extents;
4978 MetaDrawInfo draw_info;
4979 const MetaFrameBorders *borders;
4980
4981 borders = &fgeom->borders;
4982
4983 visible_rect.x = borders->invisible.left;
4984 visible_rect.y = borders->invisible.top;
4985 visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
4986 visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
4987
4988 titlebar_rect.x = visible_rect.x;
4989 titlebar_rect.y = visible_rect.y;
4990 titlebar_rect.width = visible_rect.width;
4991 titlebar_rect.height = borders->visible.top;
4992
4993 left_titlebar_edge.x = titlebar_rect.x;
4994 left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
4995 left_titlebar_edge.width = fgeom->left_titlebar_edge;
4996 left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
4997
4998 right_titlebar_edge.y = left_titlebar_edge.y;
4999 right_titlebar_edge.height = left_titlebar_edge.height;
5000 right_titlebar_edge.width = fgeom->right_titlebar_edge;
5001 right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
5002
5003 top_titlebar_edge.x = titlebar_rect.x;
5004 top_titlebar_edge.y = titlebar_rect.y;
5005 top_titlebar_edge.width = titlebar_rect.width;
5006 top_titlebar_edge.height = fgeom->top_titlebar_edge;
5007
5008 bottom_titlebar_edge.x = titlebar_rect.x;
5009 bottom_titlebar_edge.width = titlebar_rect.width;
5010 bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
5011 bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
5012
5013 left_edge.x = visible_rect.x;
5014 left_edge.y = visible_rect.y + borders->visible.top;
5015 left_edge.width = borders->visible.left;
5016 left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5017
5018 right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
5019 right_edge.y = visible_rect.y + borders->visible.top;
5020 right_edge.width = borders->visible.right;
5021 right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5022
5023 bottom_edge.x = visible_rect.x;
5024 bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
5025 bottom_edge.width = visible_rect.width;
5026 bottom_edge.height = borders->visible.bottom;
5027
5028 if (title_layout)
5029 pango_layout_get_pixel_extents (title_layout,
5030 NULL((void*)0), &extents);
5031
5032 draw_info.mini_icon = mini_icon;
5033 draw_info.icon = icon;
5034 draw_info.title_layout = title_layout;
5035 draw_info.title_layout_width = title_layout ? extents.width : 0;
5036 draw_info.title_layout_height = title_layout ? extents.height : 0;
5037 draw_info.fgeom = fgeom;
5038
5039 /* The enum is in the order the pieces should be rendered. */
5040 i = 0;
5041 while (i < META_FRAME_PIECE_LAST)
5042 {
5043 GdkRectangle rect;
5044
5045 switch ((MetaFramePiece) i)
5046 {
5047 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
5048 rect = visible_rect;
5049 break;
5050
5051 case META_FRAME_PIECE_TITLEBAR:
5052 rect = titlebar_rect;
5053 break;
5054
5055 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
5056 rect = left_titlebar_edge;
5057 break;
5058
5059 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
5060 rect = right_titlebar_edge;
5061 break;
5062
5063 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
5064 rect = top_titlebar_edge;
5065 break;
5066
5067 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
5068 rect = bottom_titlebar_edge;
5069 break;
5070
5071 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
5072 rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
5073 rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
5074 rect.width = titlebar_rect.width - left_titlebar_edge.width -
5075 right_titlebar_edge.width;
5076 rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
5077 break;
5078
5079 case META_FRAME_PIECE_TITLE:
5080 rect = fgeom->title_rect;
5081 break;
5082
5083 case META_FRAME_PIECE_LEFT_EDGE:
5084 rect = left_edge;
5085 break;
5086
5087 case META_FRAME_PIECE_RIGHT_EDGE:
5088 rect = right_edge;
5089 break;
5090
5091 case META_FRAME_PIECE_BOTTOM_EDGE:
5092 rect = bottom_edge;
5093 break;
5094
5095 case META_FRAME_PIECE_OVERLAY:
5096 rect = visible_rect;
5097 break;
5098
5099 case META_FRAME_PIECE_LAST:
5100 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5100, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5101 break;
5102 }
5103
5104 cairo_save (cr);
5105
5106 gdk_cairo_rectangle (cr, &rect);
5107 cairo_clip (cr);
5108
5109 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5110 {
5111 MetaDrawOpList *op_list;
5112 MetaFrameStyle *parent;
5113
5114 parent = style;
5115 op_list = NULL((void*)0);
5116 while (parent && op_list == NULL((void*)0))
5117 {
5118 op_list = parent->pieces[i];
5119 parent = parent->parent;
5120 }
5121
5122 if (op_list)
5123 {
5124 MetaRectangle m_rect;
5125 m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
5126 meta_draw_op_list_draw_with_style (op_list,
5127 style_gtk,
5128 cr,
5129 &draw_info,
5130 m_rect);
5131 }
5132 }
5133
5134 cairo_restore (cr);
5135
5136 /* Draw buttons just before overlay */
5137 if ((i + 1) == META_FRAME_PIECE_OVERLAY)
5138 {
5139 MetaDrawOpList *op_list;
5140 int middle_bg_offset;
5141
5142 middle_bg_offset = 0;
5143 j = 0;
5144 while (j < META_BUTTON_TYPE_LAST)
5145 {
5146 MetaButtonState button_state;
5147
5148 get_button_rect (j, fgeom, middle_bg_offset, &rect);
5149
5150 button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
5151 op_list = get_button (style, j, button_state);
5152
5153 if (op_list)
5154 {
5155 cairo_save (cr);
5156 gdk_cairo_rectangle (cr, &rect);
5157 cairo_clip (cr);
5158
5159 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5160 {
5161 MetaRectangle m_rect;
5162
5163 m_rect = meta_rect (rect.x, rect.y,
5164 rect.width, rect.height);
5165
5166 meta_draw_op_list_draw_with_style (op_list,
5167 style_gtk,
5168 cr,
5169 &draw_info,
5170 m_rect);
5171 }
5172
5173 cairo_restore (cr);
5174 }
5175
5176 /* MIDDLE_BACKGROUND type may get drawn more than once */
5177 if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
5178 j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
5179 middle_bg_offset < MAX_MIDDLE_BACKGROUNDS(META_BUTTON_FUNCTION_LAST - 2))
5180 {
5181 ++middle_bg_offset;
5182 }
5183 else
5184 {
5185 middle_bg_offset = 0;
5186 ++j;
5187 }
5188 }
5189 }
5190
5191 ++i;
5192 }
5193}
5194
5195void
5196meta_frame_style_draw (MetaFrameStyle *style,
5197 GtkWidget *widget,
5198 cairo_t *cr,
5199 const MetaFrameGeometry *fgeom,
5200 int client_width,
5201 int client_height,
5202 PangoLayout *title_layout,
5203 int text_height,
5204 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5205 GdkPixbuf *mini_icon,
5206 GdkPixbuf *icon)
5207{
5208 meta_frame_style_draw_with_style (style,
5209 gtk_widget_get_style_context (widget),
5210 cr,
5211 fgeom, client_width, client_height,
5212 title_layout, text_height,
5213 button_states, mini_icon, icon);
5214}
5215
5216MetaFrameStyleSet*
5217meta_frame_style_set_new (MetaFrameStyleSet *parent)
5218{
5219 MetaFrameStyleSet *style_set;
5220
5221 style_set = g_new0 (MetaFrameStyleSet, 1)((MetaFrameStyleSet *) g_malloc0_n ((1), sizeof (MetaFrameStyleSet
)))
;
5222
5223 style_set->parent = parent;
5224 if (parent)
5225 meta_frame_style_set_ref (parent);
5226
5227 style_set->refcount = 1;
5228
5229 return style_set;
5230}
5231
5232static void
5233free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST])
5234{
5235 int i;
5236
5237 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5238 if (focus_styles[i])
5239 meta_frame_style_unref (focus_styles[i]);
5240}
5241
5242void
5243meta_frame_style_set_ref (MetaFrameStyleSet *style_set)
5244{
5245 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5246
5247 style_set->refcount += 1;
5248}
5249
5250void
5251meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
5252{
5253 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5254 g_return_if_fail (style_set->refcount > 0)do { if ((style_set->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set->refcount > 0"
); return; } } while (0)
;
5255
5256 style_set->refcount -= 1;
5257
5258 if (style_set->refcount == 0)
5259 {
5260 int i;
5261
5262 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5263 {
5264 free_focus_styles (style_set->normal_styles[i]);
5265 free_focus_styles (style_set->shaded_styles[i]);
5266 }
5267
5268 free_focus_styles (style_set->maximized_styles);
5269 free_focus_styles (style_set->tiled_left_styles);
5270 free_focus_styles (style_set->tiled_right_styles);
5271 free_focus_styles (style_set->maximized_and_shaded_styles);
5272 free_focus_styles (style_set->tiled_left_and_shaded_styles);
5273 free_focus_styles (style_set->tiled_right_and_shaded_styles);
5274
5275 if (style_set->parent)
5276 meta_frame_style_set_unref (style_set->parent);
5277
5278 DEBUG_FILL_STRUCT (style_set)memset ((style_set), 0xef, sizeof (*(style_set)));
5279 g_free (style_set);
5280 }
5281}
5282
5283static MetaFrameStyle*
5284get_style (MetaFrameStyleSet *style_set,
5285 MetaFrameState state,
5286 MetaFrameResize resize,
5287 MetaFrameFocus focus)
5288{
5289 MetaFrameStyle *style;
5290
5291 style = NULL((void*)0);
5292
5293 switch (state)
5294 {
5295 case META_FRAME_STATE_NORMAL:
5296 case META_FRAME_STATE_SHADED:
5297 {
5298 if (state == META_FRAME_STATE_SHADED)
5299 style = style_set->shaded_styles[resize][focus];
5300 else
5301 style = style_set->normal_styles[resize][focus];
5302
5303 /* Try parent if we failed here */
5304 if (style == NULL((void*)0) && style_set->parent)
5305 style = get_style (style_set->parent, state, resize, focus);
5306
5307 /* Allow people to omit the vert/horz/none resize modes */
5308 if (style == NULL((void*)0) &&
5309 resize != META_FRAME_RESIZE_BOTH)
5310 style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
5311 }
5312 break;
5313 default:
5314 {
5315 MetaFrameStyle **styles;
5316
5317 styles = NULL((void*)0);
5318
5319 switch (state)
5320 {
5321 case META_FRAME_STATE_MAXIMIZED:
5322 styles = style_set->maximized_styles;
5323 break;
5324 case META_FRAME_STATE_TILED_LEFT:
5325 styles = style_set->tiled_left_styles;
5326 break;
5327 case META_FRAME_STATE_TILED_RIGHT:
5328 styles = style_set->tiled_right_styles;
5329 break;
5330 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
5331 styles = style_set->maximized_and_shaded_styles;
5332 break;
5333 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
5334 styles = style_set->tiled_left_and_shaded_styles;
5335 break;
5336 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
5337 styles = style_set->tiled_right_and_shaded_styles;
5338 break;
5339 case META_FRAME_STATE_NORMAL:
5340 case META_FRAME_STATE_SHADED:
5341 case META_FRAME_STATE_LAST:
5342 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5342, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5343 break;
5344 }
5345
5346 style = styles[focus];
5347
5348 /* Tiled states are optional, try falling back to non-tiled states */
5349 if (style == NULL((void*)0))
5350 {
5351 if (state == META_FRAME_STATE_TILED_LEFT ||
5352 state == META_FRAME_STATE_TILED_RIGHT)
5353 style = get_style (style_set, META_FRAME_STATE_NORMAL,
5354 resize, focus);
5355 else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED ||
5356 state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED)
5357 style = get_style (style_set, META_FRAME_STATE_SHADED,
5358 resize, focus);
5359 }
5360
5361 /* Try parent if we failed here */
5362 if (style == NULL((void*)0) && style_set->parent)
5363 style = get_style (style_set->parent, state, resize, focus);
5364 }
5365 }
5366
5367 return style;
5368}
5369
5370static gboolean
5371check_state (MetaFrameStyleSet *style_set,
5372 MetaFrameState state,
5373 GError **error)
5374{
5375 int i;
5376
5377 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5378 {
5379 if (get_style (style_set, state,
5380 META_FRAME_RESIZE_NONE, i) == NULL((void*)0))
5381 {
5382 /* Translators: This error occurs when a <frame> tag is missing
5383 * in theme XML. The "<frame ...>" is intended as a noun phrase,
5384 * and the "missing" qualifies it. You should translate "whatever".
5385 */
5386 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5387 META_THEME_ERROR_FAILED,
5388 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5389 meta_frame_state_to_string (state),
5390 meta_frame_resize_to_string (META_FRAME_RESIZE_NONE),
5391 meta_frame_focus_to_string (i));
5392 return FALSE(0);
5393 }
5394 }
5395
5396 return TRUE(!(0));
5397}
5398
5399gboolean
5400meta_frame_style_set_validate (MetaFrameStyleSet *style_set,
5401 GError **error)
5402{
5403 int i, j;
5404
5405 g_return_val_if_fail (style_set != NULL, FALSE)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
((0)); } } while (0)
;
5406
5407 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5408 for (j = 0; j < META_FRAME_FOCUS_LAST; j++)
5409 if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL((void*)0))
5410 {
5411 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5412 META_THEME_ERROR_FAILED,
5413 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5414 meta_frame_state_to_string (META_FRAME_STATE_NORMAL),
5415 meta_frame_resize_to_string (i),
5416 meta_frame_focus_to_string (j));
5417 return FALSE(0);
5418 }
5419
5420 if (!check_state (style_set, META_FRAME_STATE_SHADED, error))
5421 return FALSE(0);
5422
5423 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error))
5424 return FALSE(0);
5425
5426 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error))
5427 return FALSE(0);
5428
5429 return TRUE(!(0));
5430}
5431
5432MetaTheme*
5433meta_theme_get_current (void)
5434{
5435 return meta_current_theme;
5436}
5437
5438void
5439meta_theme_set_current (const char *name,
5440 gboolean force_reload)
5441{
5442 MetaTheme *new_theme;
5443 GError *err;
5444
5445 meta_topicmeta_topic_real (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name);
5446
5447 if (!force_reload &&
5448 meta_current_theme &&
5449 strcmp (name, meta_current_theme->name) == 0)
5450 return;
5451
5452 err = NULL((void*)0);
5453 new_theme = meta_theme_load (name, &err);
5454
5455 if (new_theme == NULL((void*)0))
5456 {
5457 meta_warning (_("Failed to load theme \"%s\": %s\n")((char *) g_dgettext ("marco", "Failed to load theme \"%s\": %s\n"
))
,
5458 name, err->message);
5459 g_error_free (err);
5460 }
5461 else
5462 {
5463 if (meta_current_theme)
5464 meta_theme_free (meta_current_theme);
5465
5466 meta_current_theme = new_theme;
5467
5468 meta_topicmeta_topic_real (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name);
5469 }
5470}
5471
5472MetaTheme*
5473meta_theme_new (void)
5474{
5475 MetaTheme *theme;
5476
5477 theme = g_new0 (MetaTheme, 1)((MetaTheme *) g_malloc0_n ((1), sizeof (MetaTheme)));
5478
5479 theme->images_by_filename =
5480 g_hash_table_new_full (g_str_hash,
5481 g_str_equal,
5482 g_free,
5483 g_object_unref);
5484
5485 theme->layouts_by_name =
5486 g_hash_table_new_full (g_str_hash,
5487 g_str_equal,
5488 g_free,
5489 (GDestroyNotify) meta_frame_layout_unref);
5490
5491 theme->draw_op_lists_by_name =
5492 g_hash_table_new_full (g_str_hash,
5493 g_str_equal,
5494 g_free,
5495 (GDestroyNotify) meta_draw_op_list_unref);
5496
5497 theme->styles_by_name =
5498 g_hash_table_new_full (g_str_hash,
5499 g_str_equal,
5500 g_free,
5501 (GDestroyNotify) meta_frame_style_unref);
5502
5503 theme->style_sets_by_name =
5504 g_hash_table_new_full (g_str_hash,
5505 g_str_equal,
5506 g_free,
5507 (GDestroyNotify) meta_frame_style_set_unref);
5508
5509 /* Create our variable quarks so we can look up variables without
5510 having to strcmp for the names */
5511 theme->quark_width = g_quark_from_static_string ("width");
5512 theme->quark_height = g_quark_from_static_string ("height");
5513 theme->quark_object_width = g_quark_from_static_string ("object_width");
5514 theme->quark_object_height = g_quark_from_static_string ("object_height");
5515 theme->quark_left_width = g_quark_from_static_string ("left_width");
5516 theme->quark_right_width = g_quark_from_static_string ("right_width");
5517 theme->quark_top_height = g_quark_from_static_string ("top_height");
5518 theme->quark_bottom_height = g_quark_from_static_string ("bottom_height");
5519 theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width");
5520 theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height");
5521 theme->quark_icon_width = g_quark_from_static_string ("icon_width");
5522 theme->quark_icon_height = g_quark_from_static_string ("icon_height");
5523 theme->quark_title_width = g_quark_from_static_string ("title_width");
5524 theme->quark_title_height = g_quark_from_static_string ("title_height");
5525 theme->quark_frame_x_center = g_quark_from_static_string ("frame_x_center");
5526 theme->quark_frame_y_center = g_quark_from_static_string ("frame_y_center");
5527 return theme;
5528}
5529
5530void
5531meta_theme_free (MetaTheme *theme)
5532{
5533 int i;
5534
5535 g_return_if_fail (theme != NULL)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
; } } while (0)
;
5536
5537 g_free (theme->name);
5538 g_free (theme->dirname);
5539 g_free (theme->filename);
5540 g_free (theme->readable_name);
5541 g_free (theme->date);
5542 g_free (theme->description);
5543 g_free (theme->author);
5544 g_free (theme->copyright);
5545
5546 /* be more careful when destroying the theme hash tables,
5547 since they are only constructed as needed, and may be NULL. */
5548 if (theme->integer_constants)
5549 g_hash_table_destroy (theme->integer_constants);
5550 if (theme->images_by_filename)
5551 g_hash_table_destroy (theme->images_by_filename);
5552 if (theme->layouts_by_name)
5553 g_hash_table_destroy (theme->layouts_by_name);
5554 if (theme->draw_op_lists_by_name)
5555 g_hash_table_destroy (theme->draw_op_lists_by_name);
5556 if (theme->styles_by_name)
5557 g_hash_table_destroy (theme->styles_by_name);
5558 if (theme->style_sets_by_name)
5559 g_hash_table_destroy (theme->style_sets_by_name);
5560
5561 for (i = 0; i < META_FRAME_TYPE_LAST; i++)
5562 if (theme->style_sets_by_type[i])
5563 meta_frame_style_set_unref (theme->style_sets_by_type[i]);
5564
5565 DEBUG_FILL_STRUCT (theme)memset ((theme), 0xef, sizeof (*(theme)));
5566 g_free (theme);
5567}
5568
5569gboolean
5570meta_theme_validate (MetaTheme *theme,
5571 GError **error)
5572{
5573 int i;
5574
5575 g_return_val_if_fail (theme != NULL, FALSE)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
((0)); } } while (0)
;
5576
5577 /* FIXME what else should be checked? */
5578
5579 g_assert (theme->name)do { if (theme->name) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 5579, ((const char*) (__func__)), "theme->name"
); } while (0)
;
5580
5581 if (theme->readable_name == NULL((void*)0))
5582 {
5583 /* Translators: This error means that a necessary XML tag (whose name
5584 * is given in angle brackets) was not found in a given theme (whose
5585 * name is given second, in quotation marks).
5586 */
5587 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5588 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "name", theme->name);
5589 return FALSE(0);
5590 }
5591
5592 if (theme->author == NULL((void*)0))
5593 {
5594 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5595 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "author", theme->name);
5596 return FALSE(0);
5597 }
5598
5599 if (theme->date == NULL((void*)0))
5600 {
5601 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5602 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "date", theme->name);
5603 return FALSE(0);
5604 }
5605
5606 if (theme->description == NULL((void*)0))
5607 {
5608 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5609 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "description", theme->name);
5610 return FALSE(0);
5611 }
5612
5613 if (theme->copyright == NULL((void*)0))
5614 {
5615 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5616 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "copyright", theme->name);
5617 return FALSE(0);
5618 }
5619
5620 for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
5621 if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL((void*)0))
5622 {
5623 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5624 _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element")((char *) g_dgettext ("marco", "No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"
))
,
5625 meta_frame_type_to_string (i),
5626 theme->name,
5627 meta_frame_type_to_string (i));
5628
5629 return FALSE(0);
5630 }
5631
5632 return TRUE(!(0));
5633}
5634
5635GdkPixbuf*
5636meta_theme_load_image (MetaTheme *theme,
5637 const char *filename,
5638 guint size_of_theme_icons,
5639 GError **error)
5640{
5641 GdkPixbuf *pixbuf;
5642 int scale;
5643
5644 pixbuf = g_hash_table_lookup (theme->images_by_filename,
5645 filename);
5646
5647 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
5648
5649 if (pixbuf == NULL((void*)0))
5650 {
5651
5652 if (g_str_has_prefix (filename, "theme:")(__builtin_constant_p ("theme:")? __extension__ ({ const char
* const __str = (filename); const char * const __prefix = ("theme:"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (filename, "theme:") )
&&
5653 META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES)(theme->format_version >= 2))
5654 {
5655 pixbuf = gtk_icon_theme_load_icon_for_scale (
5656 gtk_icon_theme_get_default (),
5657 filename+6,
5658 size_of_theme_icons,
5659 scale,
5660 0,
5661 error);
5662 if (pixbuf == NULL((void*)0)) return NULL((void*)0);
5663 }
5664 else
5665 {
5666 char *full_path;
5667 full_path = g_build_filename (theme->dirname, filename, NULL((void*)0));
5668
5669 gint width, height;
5670
5671 if (gdk_pixbuf_get_file_info (full_path, &width, &height) == NULL((void*)0))
5672 {
5673 g_free (full_path);
5674 return NULL((void*)0);
5675 }
5676
5677 width *= scale;
5678 height *= scale;
5679
5680 pixbuf = gdk_pixbuf_new_from_file_at_size (full_path, width, height, error);
5681
5682 if (pixbuf == NULL((void*)0))
5683 {
5684 g_free (full_path);
5685 return NULL((void*)0);
5686 }
5687
5688 g_free (full_path);
5689 }
5690 g_hash_table_replace (theme->images_by_filename,
5691 g_strdup (filename)g_strdup_inline (filename),
5692 pixbuf);
5693 }
5694
5695 g_assert (pixbuf)do { if (pixbuf) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 5695, ((const char*) (__func__)), "pixbuf"); } while (0)
;
5696
5697 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
5698
5699 return pixbuf;
5700}
5701
5702static MetaFrameStyle*
5703theme_get_style (MetaTheme *theme,
5704 MetaFrameType type,
5705 MetaFrameFlags flags)
5706{
5707 MetaFrameState state;
5708 MetaFrameResize resize;
5709 MetaFrameFocus focus;
5710 MetaFrameStyle *style;
5711 MetaFrameStyleSet *style_set;
5712
5713 style_set = theme->style_sets_by_type[type];
5714
5715 if (style_set == NULL((void*)0) && type == META_FRAME_TYPE_ATTACHED)
5716 style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER];
5717
5718 /* Right now the parser forces a style set for all other types,
5719 * but this fallback code is here in case I take that out.
5720 */
5721 if (style_set == NULL((void*)0))
5722 style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL];
5723 if (style_set == NULL((void*)0))
5724 return NULL((void*)0);
5725
5726 switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT))
5727 {
5728 case 0:
5729 state = META_FRAME_STATE_NORMAL;
5730 break;
5731 case META_FRAME_MAXIMIZED:
5732 state = META_FRAME_STATE_MAXIMIZED;
5733 break;
5734 case META_FRAME_TILED_LEFT:
5735 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_LEFT):
5736 state = META_FRAME_STATE_TILED_LEFT;
5737 break;
5738 case META_FRAME_TILED_RIGHT:
5739 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_RIGHT):
5740 state = META_FRAME_STATE_TILED_RIGHT;
5741 break;
5742 case META_FRAME_SHADED:
5743 state = META_FRAME_STATE_SHADED;
5744 break;
5745 case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
5746 state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
5747 break;
5748 case (META_FRAME_TILED_LEFT | META_FRAME_SHADED):
5749 state = META_FRAME_STATE_TILED_LEFT_AND_SHADED;
5750 break;
5751 case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED):
5752 state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
5753 break;
5754 default:
5755 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5755, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5756 state = META_FRAME_STATE_LAST; /* compiler */
5757 break;
5758 }
5759
5760 switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
5761 {
5762 case 0:
5763 resize = META_FRAME_RESIZE_NONE;
5764 break;
5765 case META_FRAME_ALLOWS_VERTICAL_RESIZE:
5766 resize = META_FRAME_RESIZE_VERTICAL;
5767 break;
5768 case META_FRAME_ALLOWS_HORIZONTAL_RESIZE:
5769 resize = META_FRAME_RESIZE_HORIZONTAL;
5770 break;
5771 case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE):
5772 resize = META_FRAME_RESIZE_BOTH;
5773 break;
5774 default:
5775 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5775, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5776 resize = META_FRAME_RESIZE_LAST; /* compiler */
5777 break;
5778 }
5779
5780 /* re invert the styles used for focus/unfocussed while flashing a frame */
5781 if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
5782 || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
5783 focus = META_FRAME_FOCUS_YES;
5784 else
5785 focus = META_FRAME_FOCUS_NO;
5786
5787 style = get_style (style_set, state, resize, focus);
5788
5789 return style;
5790}
5791
5792MetaFrameStyle*
5793meta_theme_get_frame_style (MetaTheme *theme,
5794 MetaFrameType type,
5795 MetaFrameFlags flags)
5796{
5797 MetaFrameStyle *style;
5798
5799 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (((void*)0)); } } while (0)
;
5800
5801 style = theme_get_style (theme, type, flags);
5802
5803 return style;
5804}
5805
5806double
5807meta_theme_get_title_scale (MetaTheme *theme,
5808 MetaFrameType type,
5809 MetaFrameFlags flags)
5810{
5811 MetaFrameStyle *style;
5812
5813 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (1.0); } } while (0)
;
5814
5815 style = theme_get_style (theme, type, flags);
5816
5817 /* Parser is not supposed to allow this currently */
5818 if (style == NULL((void*)0))
5819 return 1.0;
5820
5821 return style->layout->title_scale;
5822}
5823
5824void
5825meta_theme_draw_frame (MetaTheme *theme,
5826 GtkStyleContext *style_gtk,
5827 cairo_t *cr,
5828 MetaFrameType type,
5829 MetaFrameFlags flags,
5830 int client_width,
5831 int client_height,
5832 PangoLayout *title_layout,
5833 int text_height,
5834 const MetaButtonLayout *button_layout,
5835 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5836 GdkPixbuf *mini_icon,
5837 GdkPixbuf *icon)
5838{
5839 MetaFrameGeometry fgeom;
5840 MetaFrameStyle *style;
5841
5842 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5843
5844 style = theme_get_style (theme, type, flags);
5845
5846 /* Parser is not supposed to allow this currently */
5847 if (style == NULL((void*)0))
5848 return;
5849
5850 meta_frame_layout_calc_geometry (style->layout,
5851 text_height,
5852 flags,
5853 client_width, client_height,
5854 button_layout,
5855 &fgeom,
5856 theme);
5857
5858 meta_frame_style_draw_with_style (style,
5859 style_gtk,
5860 cr,
5861 &fgeom,
5862 client_width, client_height,
5863 title_layout,
5864 text_height,
5865 button_states,
5866 mini_icon, icon);
5867}
5868
5869void
5870meta_theme_draw_frame_by_name (MetaTheme *theme,
5871 GtkWidget *widget,
5872 cairo_t *cr,
5873 const gchar *style_name,
5874 MetaFrameFlags flags,
5875 int client_width,
5876 int client_height,
5877 PangoLayout *title_layout,
5878 int text_height,
5879 const MetaButtonLayout *button_layout,
5880 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5881 GdkPixbuf *mini_icon,
5882 GdkPixbuf *icon)
5883{
5884 MetaFrameGeometry fgeom;
5885 MetaFrameStyle *style;
5886
5887 style = meta_theme_lookup_style (theme, style_name);
5888
5889 /* Parser is not supposed to allow this currently */
5890 if (style == NULL((void*)0))
5891 return;
5892
5893 meta_frame_layout_calc_geometry (style->layout,
5894 text_height,
5895 flags,
5896 client_width, client_height,
5897 button_layout,
5898 &fgeom,
5899 theme);
5900
5901 meta_frame_style_draw (style,
5902 widget,
5903 cr,
5904 &fgeom,
5905 client_width, client_height,
5906 title_layout,
5907 text_height,
5908 button_states,
5909 mini_icon, icon);
5910}
5911
5912void
5913meta_theme_get_frame_borders (MetaTheme *theme,
5914 MetaFrameType type,
5915 int text_height,
5916 MetaFrameFlags flags,
5917 MetaFrameBorders *borders)
5918{
5919 MetaFrameStyle *style;
5920
5921 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5922
5923 style = theme_get_style (theme, type, flags);
5924
5925 meta_frame_borders_clear (borders);
5926
5927 /* Parser is not supposed to allow this currently */
5928 if (style == NULL((void*)0))
5929 return;
5930
5931 meta_frame_layout_get_borders (style->layout,
5932 text_height,
5933 flags,
5934 borders);
5935}
5936
5937void
5938meta_theme_calc_geometry (MetaTheme *theme,
5939 MetaFrameType type,
5940 int text_height,
5941 MetaFrameFlags flags,
5942 int client_width,
5943 int client_height,
5944 const MetaButtonLayout *button_layout,
5945 MetaFrameGeometry *fgeom)
5946{
5947 MetaFrameStyle *style;
5948
5949 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5950
5951 style = theme_get_style (theme, type, flags);
5952
5953 /* Parser is not supposed to allow this currently */
5954 if (style == NULL((void*)0))
5955 return;
5956
5957 meta_frame_layout_calc_geometry (style->layout,
5958 text_height,
5959 flags,
5960 client_width, client_height,
5961 button_layout,
5962 fgeom,
5963 theme);
5964}
5965
5966MetaFrameLayout*
5967meta_theme_lookup_layout (MetaTheme *theme,
5968 const char *name)
5969{
5970 return g_hash_table_lookup (theme->layouts_by_name, name);
5971}
5972
5973void
5974meta_theme_insert_layout (MetaTheme *theme,
5975 const char *name,
5976 MetaFrameLayout *layout)
5977{
5978 meta_frame_layout_ref (layout);
5979 g_hash_table_replace (theme->layouts_by_name, g_strdup (name)g_strdup_inline (name), layout);
5980}
5981
5982MetaDrawOpList*
5983meta_theme_lookup_draw_op_list (MetaTheme *theme,
5984 const char *name)
5985{
5986 return g_hash_table_lookup (theme->draw_op_lists_by_name, name);
5987}
5988
5989void
5990meta_theme_insert_draw_op_list (MetaTheme *theme,
5991 const char *name,
5992 MetaDrawOpList *op_list)
5993{
5994 meta_draw_op_list_ref (op_list);
5995 g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name)g_strdup_inline (name), op_list);
5996}
5997
5998MetaFrameStyle*
5999meta_theme_lookup_style (MetaTheme *theme,
6000 const char *name)
6001{
6002 return g_hash_table_lookup (theme->styles_by_name, name);
6003}
6004
6005void
6006meta_theme_insert_style (MetaTheme *theme,
6007 const char *name,
6008 MetaFrameStyle *style)
6009{
6010 meta_frame_style_ref (style);
6011 g_hash_table_replace (theme->styles_by_name, g_strdup (name)g_strdup_inline (name), style);
6012}
6013
6014MetaFrameStyleSet*
6015meta_theme_lookup_style_set (MetaTheme *theme,
6016 const char *name)
6017{
6018 return g_hash_table_lookup (theme->style_sets_by_name, name);
6019}
6020
6021void
6022meta_theme_insert_style_set (MetaTheme *theme,
6023 const char *name,
6024 MetaFrameStyleSet *style_set)
6025{
6026 meta_frame_style_set_ref (style_set);
6027 g_hash_table_replace (theme->style_sets_by_name, g_strdup (name)g_strdup_inline (name), style_set);
6028}
6029
6030static gboolean
6031first_uppercase (const char *str)
6032{
6033 return g_ascii_isupper (*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_UPPER) != 0);
6034}
6035
6036gboolean
6037meta_theme_define_int_constant (MetaTheme *theme,
6038 const char *name,
6039 int value,
6040 GError **error)
6041{
6042 if (theme->integer_constants == NULL((void*)0))
6043 theme->integer_constants = g_hash_table_new_full (g_str_hash,
6044 g_str_equal,
6045 g_free,
6046 NULL((void*)0));
6047
6048 if (!first_uppercase (name))
6049 {
6050 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6051 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6052 name);
6053 return FALSE(0);
6054 }
6055
6056 if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL((void*)0), NULL((void*)0)))
6057 {
6058 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6059 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6060 name);
6061
6062 return FALSE(0);
6063 }
6064
6065 g_hash_table_insert (theme->integer_constants,
6066 g_strdup (name)g_strdup_inline (name),
6067 GINT_TO_POINTER (value)((gpointer) (glong) (value)));
6068
6069 return TRUE(!(0));
6070}
6071
6072gboolean
6073meta_theme_lookup_int_constant (MetaTheme *theme,
6074 const char *name,
6075 int *value)
6076{
6077 gpointer old_value;
6078
6079 *value = 0;
6080
6081 if (theme->integer_constants == NULL((void*)0))
6082 return FALSE(0);
6083
6084 if (g_hash_table_lookup_extended (theme->integer_constants,
6085 name, NULL((void*)0), &old_value))
6086 {
6087 *value = GPOINTER_TO_INT (old_value)((gint) (glong) (old_value));
6088 return TRUE(!(0));
6089 }
6090 else
6091 {
6092 return FALSE(0);
6093 }
6094}
6095
6096gboolean
6097meta_theme_define_float_constant (MetaTheme *theme,
6098 const char *name,
6099 double value,
6100 GError **error)
6101{
6102 double *d;
6103
6104 if (theme->float_constants == NULL((void*)0))
6105 theme->float_constants = g_hash_table_new_full (g_str_hash,
6106 g_str_equal,
6107 g_free,
6108 g_free);
6109
6110 if (!first_uppercase (name))
6111 {
6112 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6113 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6114 name);
6115 return FALSE(0);
6116 }
6117
6118 if (g_hash_table_lookup_extended (theme->float_constants, name, NULL((void*)0), NULL((void*)0)))
6119 {
6120 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6121 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6122 name);
6123
6124 return FALSE(0);
6125 }
6126
6127 d = g_new (double, 1)((double *) g_malloc_n ((1), sizeof (double)));
6128 *d = value;
6129
6130 g_hash_table_insert (theme->float_constants,
6131 g_strdup (name)g_strdup_inline (name), d);
6132
6133 return TRUE(!(0));
6134}
6135
6136gboolean
6137meta_theme_lookup_float_constant (MetaTheme *theme,
6138 const char *name,
6139 double *value)
6140{
6141 double *d;
6142
6143 *value = 0.0;
6144
6145 if (theme->float_constants == NULL((void*)0))
6146 return FALSE(0);
6147
6148 d = g_hash_table_lookup (theme->float_constants, name);
6149
6150 if (d)
6151 {
6152 *value = *d;
6153 return TRUE(!(0));
6154 }
6155 else
6156 {
6157 return FALSE(0);
6158 }
6159}
6160
6161gboolean
6162meta_theme_define_color_constant (MetaTheme *theme,
6163 const char *name,
6164 const char *value,
6165 GError **error)
6166{
6167 if (theme->color_constants == NULL((void*)0))
6168 theme->color_constants = g_hash_table_new_full (g_str_hash,
6169 g_str_equal,
6170 g_free,
6171 NULL((void*)0));
6172
6173 if (!first_uppercase (name))
6174 {
6175 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6176 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6177 name);
6178 return FALSE(0);
6179 }
6180
6181 if (g_hash_table_lookup_extended (theme->color_constants, name, NULL((void*)0), NULL((void*)0)))
6182 {
6183 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6184 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6185 name);
6186
6187 return FALSE(0);
6188 }
6189
6190 g_hash_table_insert (theme->color_constants,
6191 g_strdup (name)g_strdup_inline (name),
6192 g_strdup (value)g_strdup_inline (value));
6193
6194 return TRUE(!(0));
6195}
6196
6197/**
6198 * Looks up a colour constant.
6199 *
6200 * \param theme the theme containing the constant
6201 * \param name the name of the constant
6202 * \param value [out] the string representation of the colour, or NULL if it
6203 * doesn't exist
6204 * \return TRUE if it exists, FALSE otherwise
6205 */
6206gboolean
6207meta_theme_lookup_color_constant (MetaTheme *theme,
6208 const char *name,
6209 char **value)
6210{
6211 char *result;
6212
6213 *value = NULL((void*)0);
6214
6215 if (theme->color_constants == NULL((void*)0))
6216 return FALSE(0);
6217
6218 result = g_hash_table_lookup (theme->color_constants, name);
6219
6220 if (result)
6221 {
6222 *value = result;
6223 return TRUE(!(0));
6224 }
6225 else
6226 {
6227 return FALSE(0);
6228 }
6229}
6230
6231PangoFontDescription*
6232meta_gtk_widget_get_font_desc (GtkWidget *widget,
6233 double scale,
6234 const PangoFontDescription *override)
6235{
6236 PangoFontDescription *font_desc;
6237 gint font_size;
6238
6239 GtkStyleContext *style = gtk_widget_get_style_context (widget);
6240 GtkStateFlags state = gtk_widget_get_state_flags (widget);
6241 gtk_style_context_get(style, state, GTK_STYLE_PROPERTY_FONT"font", &font_desc, NULL((void*)0));
6242
6243 if (override)
6244 pango_font_description_merge (font_desc, override, TRUE(!(0)));
6245
6246 font_size = pango_font_description_get_size (font_desc);
6247 pango_font_description_set_size (font_desc,
6248 MAX ((gint) (scale * (double) font_size), 1)((((gint) (scale * (double) font_size)) > (1)) ? ((gint) (
scale * (double) font_size)) : (1))
);
6249
6250 return font_desc;
6251}
6252
6253/**
6254 * Returns the height of the letters in a particular font.
6255 *
6256 * \param font_desc the font
6257 * \param context the context of the font
6258 * \return the height of the letters
6259 */
6260int
6261meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
6262 PangoContext *context)
6263{
6264 PangoFontMetrics *metrics;
6265 PangoLanguage *lang;
6266 int retval;
6267
6268 lang = pango_context_get_language (context);
6269 metrics = pango_context_get_metrics (context, font_desc, lang);
6270
6271 retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
6272 pango_font_metrics_get_descent (metrics))(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
;
6273
6274 pango_font_metrics_unref (metrics);
6275
6276 return retval;
6277}
6278
6279MetaGtkColorComponent
6280meta_color_component_from_string (const char *str)
6281{
6282 if (strcmp ("fg", str) == 0)
6283 return META_GTK_COLOR_FG;
6284 else if (strcmp ("bg", str) == 0)
6285 return META_GTK_COLOR_BG;
6286 else if (strcmp ("light", str) == 0)
6287 return META_GTK_COLOR_LIGHT;
6288 else if (strcmp ("dark", str) == 0)
6289 return META_GTK_COLOR_DARK;
6290 else if (strcmp ("mid", str) == 0)
6291 return META_GTK_COLOR_MID;
6292 else if (strcmp ("text", str) == 0)
6293 return META_GTK_COLOR_TEXT;
6294 else if (strcmp ("base", str) == 0)
6295 return META_GTK_COLOR_BASE;
6296 else if (strcmp ("text_aa", str) == 0)
6297 return META_GTK_COLOR_TEXT_AA;
6298 else
6299 return META_GTK_COLOR_LAST;
6300}
6301
6302const char*
6303meta_color_component_to_string (MetaGtkColorComponent component)
6304{
6305 switch (component)
6306 {
6307 case META_GTK_COLOR_FG:
6308 return "fg";
6309 case META_GTK_COLOR_BG:
6310 return "bg";
6311 case META_GTK_COLOR_LIGHT:
6312 return "light";
6313 case META_GTK_COLOR_DARK:
6314 return "dark";
6315 case META_GTK_COLOR_MID:
6316 return "mid";
6317 case META_GTK_COLOR_TEXT:
6318 return "text";
6319 case META_GTK_COLOR_BASE:
6320 return "base";
6321 case META_GTK_COLOR_TEXT_AA:
6322 return "text_aa";
6323 case META_GTK_COLOR_LAST:
6324 break;
6325 }
6326
6327 return "<unknown>";
6328}
6329
6330MetaButtonState
6331meta_button_state_from_string (const char *str)
6332{
6333 if (strcmp ("normal", str) == 0)
6334 return META_BUTTON_STATE_NORMAL;
6335 else if (strcmp ("pressed", str) == 0)
6336 return META_BUTTON_STATE_PRESSED;
6337 else if (strcmp ("prelight", str) == 0)
6338 return META_BUTTON_STATE_PRELIGHT;
6339 else
6340 return META_BUTTON_STATE_LAST;
6341}
6342
6343const char*
6344meta_button_state_to_string (MetaButtonState state)
6345{
6346 switch (state)
6347 {
6348 case META_BUTTON_STATE_NORMAL:
6349 return "normal";
6350 case META_BUTTON_STATE_PRESSED:
6351 return "pressed";
6352 case META_BUTTON_STATE_PRELIGHT:
6353 return "prelight";
6354 case META_BUTTON_STATE_LAST:
6355 break;
6356 }
6357
6358 return "<unknown>";
6359}
6360
6361MetaButtonType
6362meta_button_type_from_string (const char *str, MetaTheme *theme)
6363{
6364 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
6365 {
6366 if (strcmp ("shade", str) == 0)
6367 return META_BUTTON_TYPE_SHADE;
6368 else if (strcmp ("above", str) == 0)
6369 return META_BUTTON_TYPE_ABOVE;
6370 else if (strcmp ("stick", str) == 0)
6371 return META_BUTTON_TYPE_STICK;
6372 else if (strcmp ("unshade", str) == 0)
6373 return META_BUTTON_TYPE_UNSHADE;
6374 else if (strcmp ("unabove", str) == 0)
6375 return META_BUTTON_TYPE_UNABOVE;
6376 else if (strcmp ("unstick", str) == 0)
6377 return META_BUTTON_TYPE_UNSTICK;
6378 }
6379
6380 if (strcmp ("close", str) == 0)
6381 return META_BUTTON_TYPE_CLOSE;
6382 else if (strcmp ("maximize", str) == 0)
6383 return META_BUTTON_TYPE_MAXIMIZE;
6384 else if (strcmp ("minimize", str) == 0)
6385 return META_BUTTON_TYPE_MINIMIZE;
6386 else if (strcmp ("menu", str) == 0)
6387 return META_BUTTON_TYPE_MENU;
6388 else if (strcmp ("appmenu", str) == 0)
6389 return META_BUTTON_TYPE_APPMENU;
6390 else if (strcmp ("left_left_background", str) == 0)
6391 return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
6392 else if (strcmp ("left_middle_background", str) == 0)
6393 return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
6394 else if (strcmp ("left_right_background", str) == 0)
6395 return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
6396 else if (strcmp ("left_single_background", str) == 0)
6397 return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND;
6398 else if (strcmp ("right_left_background", str) == 0)
6399 return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
6400 else if (strcmp ("right_middle_background", str) == 0)
6401 return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
6402 else if (strcmp ("right_right_background", str) == 0)
6403 return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
6404 else if (strcmp ("right_single_background", str) == 0)
6405 return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND;
6406 else
6407 return META_BUTTON_TYPE_LAST;
6408}
6409
6410const char*
6411meta_button_type_to_string (MetaButtonType type)
6412{
6413 switch (type)
6414 {
6415 case META_BUTTON_TYPE_CLOSE:
6416 return "close";
6417 case META_BUTTON_TYPE_MAXIMIZE:
6418 return "maximize";
6419 case META_BUTTON_TYPE_MINIMIZE:
6420 return "minimize";
6421 case META_BUTTON_TYPE_SHADE:
6422 return "shade";
6423 case META_BUTTON_TYPE_ABOVE:
6424 return "above";
6425 case META_BUTTON_TYPE_STICK:
6426 return "stick";
6427 case META_BUTTON_TYPE_UNSHADE:
6428 return "unshade";
6429 case META_BUTTON_TYPE_UNABOVE:
6430 return "unabove";
6431 case META_BUTTON_TYPE_UNSTICK:
6432 return "unstick";
6433 case META_BUTTON_TYPE_MENU:
6434 return "menu";
6435 case META_BUTTON_TYPE_APPMENU:
6436 return "appmenu";
6437 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
6438 return "left_left_background";
6439 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
6440 return "left_middle_background";
6441 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
6442 return "left_right_background";
6443 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
6444 return "left_single_background";
6445 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
6446 return "right_left_background";
6447 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
6448 return "right_middle_background";
6449 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
6450 return "right_right_background";
6451 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
6452 return "right_single_background";
6453 case META_BUTTON_TYPE_LAST:
6454 break;
6455 }
6456
6457 return "<unknown>";
6458}
6459
6460MetaFramePiece
6461meta_frame_piece_from_string (const char *str)
6462{
6463 if (strcmp ("entire_background", str) == 0)
6464 return META_FRAME_PIECE_ENTIRE_BACKGROUND;
6465 else if (strcmp ("titlebar", str) == 0)
6466 return META_FRAME_PIECE_TITLEBAR;
6467 else if (strcmp ("titlebar_middle", str) == 0)
6468 return META_FRAME_PIECE_TITLEBAR_MIDDLE;
6469 else if (strcmp ("left_titlebar_edge", str) == 0)
6470 return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE;
6471 else if (strcmp ("right_titlebar_edge", str) == 0)
6472 return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE;
6473 else if (strcmp ("top_titlebar_edge", str) == 0)
6474 return META_FRAME_PIECE_TOP_TITLEBAR_EDGE;
6475 else if (strcmp ("bottom_titlebar_edge", str) == 0)
6476 return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE;
6477 else if (strcmp ("title", str) == 0)
6478 return META_FRAME_PIECE_TITLE;
6479 else if (strcmp ("left_edge", str) == 0)
6480 return META_FRAME_PIECE_LEFT_EDGE;
6481 else if (strcmp ("right_edge", str) == 0)
6482 return META_FRAME_PIECE_RIGHT_EDGE;
6483 else if (strcmp ("bottom_edge", str) == 0)
6484 return META_FRAME_PIECE_BOTTOM_EDGE;
6485 else if (strcmp ("overlay", str) == 0)
6486 return META_FRAME_PIECE_OVERLAY;
6487 else
6488 return META_FRAME_PIECE_LAST;
6489}
6490
6491const char*
6492meta_frame_piece_to_string (MetaFramePiece piece)
6493{
6494 switch (piece)
6495 {
6496 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
6497 return "entire_background";
6498 case META_FRAME_PIECE_TITLEBAR:
6499 return "titlebar";
6500 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
6501 return "titlebar_middle";
6502 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
6503 return "left_titlebar_edge";
6504 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
6505 return "right_titlebar_edge";
6506 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
6507 return "top_titlebar_edge";
6508 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
6509 return "bottom_titlebar_edge";
6510 case META_FRAME_PIECE_TITLE:
6511 return "title";
6512 case META_FRAME_PIECE_LEFT_EDGE:
6513 return "left_edge";
6514 case META_FRAME_PIECE_RIGHT_EDGE:
6515 return "right_edge";
6516 case META_FRAME_PIECE_BOTTOM_EDGE:
6517 return "bottom_edge";
6518 case META_FRAME_PIECE_OVERLAY:
6519 return "overlay";
6520 case META_FRAME_PIECE_LAST:
6521 break;
6522 }
6523
6524 return "<unknown>";
6525}
6526
6527MetaFrameState
6528meta_frame_state_from_string (const char *str)
6529{
6530 if (strcmp ("normal", str) == 0)
6531 return META_FRAME_STATE_NORMAL;
6532 else if (strcmp ("maximized", str) == 0)
6533 return META_FRAME_STATE_MAXIMIZED;
6534 else if (strcmp ("tiled_left", str) == 0)
6535 return META_FRAME_STATE_TILED_LEFT;
6536 else if (strcmp ("tiled_right", str) == 0)
6537 return META_FRAME_STATE_TILED_RIGHT;
6538 else if (strcmp ("shaded", str) == 0)
6539 return META_FRAME_STATE_SHADED;
6540 else if (strcmp ("maximized_and_shaded", str) == 0)
6541 return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
6542 else if (strcmp ("tiled_left_and_shaded", str) == 0)
6543 return META_FRAME_STATE_TILED_LEFT_AND_SHADED;
6544 else if (strcmp ("tiled_right_and_shaded", str) == 0)
6545 return META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
6546 else
6547 return META_FRAME_STATE_LAST;
6548}
6549
6550const char*
6551meta_frame_state_to_string (MetaFrameState state)
6552{
6553 switch (state)
6554 {
6555 case META_FRAME_STATE_NORMAL:
6556 return "normal";
6557 case META_FRAME_STATE_MAXIMIZED:
6558 return "maximized";
6559 case META_FRAME_STATE_TILED_LEFT:
6560 return "tiled_left";
6561 case META_FRAME_STATE_TILED_RIGHT:
6562 return "tiled_right";
6563 case META_FRAME_STATE_SHADED:
6564 return "shaded";
6565 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
6566 return "maximized_and_shaded";
6567 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
6568 return "tiled_left_and_shaded";
6569 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
6570 return "tiled_right_and_shaded";
6571 case META_FRAME_STATE_LAST:
6572 break;
6573 }
6574
6575 return "<unknown>";
6576}
6577
6578MetaFrameResize
6579meta_frame_resize_from_string (const char *str)
6580{
6581 if (strcmp ("none", str) == 0)
6582 return META_FRAME_RESIZE_NONE;
6583 else if (strcmp ("vertical", str) == 0)
6584 return META_FRAME_RESIZE_VERTICAL;
6585 else if (strcmp ("horizontal", str) == 0)
6586 return META_FRAME_RESIZE_HORIZONTAL;
6587 else if (strcmp ("both", str) == 0)
6588 return META_FRAME_RESIZE_BOTH;
6589 else
6590 return META_FRAME_RESIZE_LAST;
6591}
6592
6593const char*
6594meta_frame_resize_to_string (MetaFrameResize resize)
6595{
6596 switch (resize)
6597 {
6598 case META_FRAME_RESIZE_NONE:
6599 return "none";
6600 case META_FRAME_RESIZE_VERTICAL:
6601 return "vertical";
6602 case META_FRAME_RESIZE_HORIZONTAL:
6603 return "horizontal";
6604 case META_FRAME_RESIZE_BOTH:
6605 return "both";
6606 case META_FRAME_RESIZE_LAST:
6607 break;
6608 }
6609
6610 return "<unknown>";
6611}
6612
6613MetaFrameFocus
6614meta_frame_focus_from_string (const char *str)
6615{
6616 if (strcmp ("no", str) == 0)
6617 return META_FRAME_FOCUS_NO;
6618 else if (strcmp ("yes", str) == 0)
6619 return META_FRAME_FOCUS_YES;
6620 else
6621 return META_FRAME_FOCUS_LAST;
6622}
6623
6624const char*
6625meta_frame_focus_to_string (MetaFrameFocus focus)
6626{
6627 switch (focus)
6628 {
6629 case META_FRAME_FOCUS_NO:
6630 return "no";
6631 case META_FRAME_FOCUS_YES:
6632 return "yes";
6633 case META_FRAME_FOCUS_LAST:
6634 break;
6635 }
6636
6637 return "<unknown>";
6638}
6639
6640MetaFrameType
6641meta_frame_type_from_string (const char *str)
6642{
6643 if (strcmp ("normal", str) == 0)
6644 return META_FRAME_TYPE_NORMAL;
6645 else if (strcmp ("dialog", str) == 0)
6646 return META_FRAME_TYPE_DIALOG;
6647 else if (strcmp ("modal_dialog", str) == 0)
6648 return META_FRAME_TYPE_MODAL_DIALOG;
6649 else if (strcmp ("utility", str) == 0)
6650 return META_FRAME_TYPE_UTILITY;
6651 else if (strcmp ("menu", str) == 0)
6652 return META_FRAME_TYPE_MENU;
6653 else if (strcmp ("border", str) == 0)
6654 return META_FRAME_TYPE_BORDER;
6655 else if (strcmp ("attached", str) == 0)
6656 return META_FRAME_TYPE_ATTACHED;
6657#if 0
6658 else if (strcmp ("toolbar", str) == 0)
6659 return META_FRAME_TYPE_TOOLBAR;
6660#endif
6661 else
6662 return META_FRAME_TYPE_LAST;
6663}
6664
6665const char*
6666meta_frame_type_to_string (MetaFrameType type)
6667{
6668 switch (type)
6669 {
6670 case META_FRAME_TYPE_NORMAL:
6671 return "normal";
6672 case META_FRAME_TYPE_DIALOG:
6673 return "dialog";
6674 case META_FRAME_TYPE_MODAL_DIALOG:
6675 return "modal_dialog";
6676 case META_FRAME_TYPE_UTILITY:
6677 return "utility";
6678 case META_FRAME_TYPE_MENU:
6679 return "menu";
6680 case META_FRAME_TYPE_BORDER:
6681 return "border";
6682 case META_FRAME_TYPE_ATTACHED:
6683 return "attached";
6684#if 0
6685 case META_FRAME_TYPE_TOOLBAR:
6686 return "toolbar";
6687#endif
6688 case META_FRAME_TYPE_LAST:
6689 break;
6690 }
6691
6692 return "<unknown>";
6693}
6694
6695MetaGradientType
6696meta_gradient_type_from_string (const char *str)
6697{
6698 if (strcmp ("vertical", str) == 0)
6699 return META_GRADIENT_VERTICAL;
6700 else if (strcmp ("horizontal", str) == 0)
6701 return META_GRADIENT_HORIZONTAL;
6702 else if (strcmp ("diagonal", str) == 0)
6703 return META_GRADIENT_DIAGONAL;
6704 else
6705 return META_GRADIENT_LAST;
6706}
6707
6708const char*
6709meta_gradient_type_to_string (MetaGradientType type)
6710{
6711 switch (type)
6712 {
6713 case META_GRADIENT_VERTICAL:
6714 return "vertical";
6715 case META_GRADIENT_HORIZONTAL:
6716 return "horizontal";
6717 case META_GRADIENT_DIAGONAL:
6718 return "diagonal";
6719 case META_GRADIENT_LAST:
6720 break;
6721 }
6722
6723 return "<unknown>";
6724}
6725
6726GtkStateFlags
6727meta_gtk_state_from_string (const char *str)
6728{
6729 if (g_ascii_strcasecmp ("normal", str) == 0)
6730 return GTK_STATE_FLAG_NORMAL;
6731 else if (g_ascii_strcasecmp ("prelight", str) == 0)
6732 return GTK_STATE_FLAG_PRELIGHT;
6733 else if (g_ascii_strcasecmp ("active", str) == 0)
6734 return GTK_STATE_FLAG_ACTIVE;
6735 else if (g_ascii_strcasecmp ("selected", str) == 0)
6736 return GTK_STATE_FLAG_SELECTED;
6737 else if (g_ascii_strcasecmp ("insensitive", str) == 0)
6738 return GTK_STATE_FLAG_INSENSITIVE;
6739 else if (g_ascii_strcasecmp ("inconsistent", str) == 0)
6740 return GTK_STATE_FLAG_INCONSISTENT;
6741 else if (g_ascii_strcasecmp ("focused", str) == 0)
6742 return GTK_STATE_FLAG_FOCUSED;
6743 else if (g_ascii_strcasecmp ("backdrop", str) == 0)
6744 return GTK_STATE_FLAG_BACKDROP;
6745 else
6746 return -1; /* hack */
6747}
6748
6749GtkShadowType
6750meta_gtk_shadow_from_string (const char *str)
6751{
6752 if (strcmp ("none", str) == 0)
6753 return GTK_SHADOW_NONE;
6754 else if (strcmp ("in", str) == 0)
6755 return GTK_SHADOW_IN;
6756 else if (strcmp ("out", str) == 0)
6757 return GTK_SHADOW_OUT;
6758 else if (strcmp ("etched_in", str) == 0)
6759 return GTK_SHADOW_ETCHED_IN;
6760 else if (strcmp ("etched_out", str) == 0)
6761 return GTK_SHADOW_ETCHED_OUT;
6762 else
6763 return -1;
6764}
6765
6766const char*
6767meta_gtk_shadow_to_string (GtkShadowType shadow)
6768{
6769 switch (shadow)
6770 {
6771 case GTK_SHADOW_NONE:
6772 return "none";
6773 case GTK_SHADOW_IN:
6774 return "in";
6775 case GTK_SHADOW_OUT:
6776 return "out";
6777 case GTK_SHADOW_ETCHED_IN:
6778 return "etched_in";
6779 case GTK_SHADOW_ETCHED_OUT:
6780 return "etched_out";
6781 }
6782
6783 return "<unknown>";
6784}
6785
6786GtkArrowType
6787meta_gtk_arrow_from_string (const char *str)
6788{
6789 if (strcmp ("up", str) == 0)
6790 return GTK_ARROW_UP;
6791 else if (strcmp ("down", str) == 0)
6792 return GTK_ARROW_DOWN;
6793 else if (strcmp ("left", str) == 0)
6794 return GTK_ARROW_LEFT;
6795 else if (strcmp ("right", str) == 0)
6796 return GTK_ARROW_RIGHT;
6797 else if (strcmp ("none", str) == 0)
6798 return GTK_ARROW_NONE;
6799 else
6800 return -1;
6801}
6802
6803const char*
6804meta_gtk_arrow_to_string (GtkArrowType arrow)
6805{
6806 switch (arrow)
6807 {
6808 case GTK_ARROW_UP:
6809 return "up";
6810 case GTK_ARROW_DOWN:
6811 return "down";
6812 case GTK_ARROW_LEFT:
6813 return "left";
6814 case GTK_ARROW_RIGHT:
6815 return "right";
6816 case GTK_ARROW_NONE:
6817 return "none";
6818 }
6819
6820 return "<unknown>";
6821}
6822
6823/**
6824 * Returns a fill_type from a string. The inverse of
6825 * meta_image_fill_type_to_string().
6826 *
6827 * \param str a string representing a fill_type
6828 * \result the fill_type, or -1 if it represents no fill_type.
6829 */
6830MetaImageFillType
6831meta_image_fill_type_from_string (const char *str)
6832{
6833 if (strcmp ("tile", str) == 0)
6834 return META_IMAGE_FILL_TILE;
6835 else if (strcmp ("scale", str) == 0)
6836 return META_IMAGE_FILL_SCALE;
6837 else
6838 return -1;
6839}
6840
6841/**
6842 * Returns a string representation of a fill_type. The inverse of
6843 * meta_image_fill_type_from_string().
6844 *
6845 * \param fill_type the fill type
6846 * \result a string representing that type
6847 */
6848const char*
6849meta_image_fill_type_to_string (MetaImageFillType fill_type)
6850{
6851 switch (fill_type)
6852 {
6853 case META_IMAGE_FILL_TILE:
6854 return "tile";
6855 case META_IMAGE_FILL_SCALE:
6856 return "scale";
6857 }
6858
6859 return "<unknown>";
This statement is never executed
6860}
6861
6862/**
6863 * Takes a colour "a", scales the lightness and saturation by a certain amount,
6864 * and sets "b" to the resulting colour.
6865 * gtkstyle.c cut-and-pastage.
6866 *
6867 * \param a the starting colour
6868 * \param b [out] the resulting colour
6869 * \param k amount to scale lightness and saturation by
6870 */
6871static void
6872gtk_style_shade (GdkRGBA *a,
6873 GdkRGBA *b,
6874 gdouble k)
6875{
6876 gdouble red;
6877 gdouble green;
6878 gdouble blue;
6879
6880 red = a->red;
6881 green = a->green;
6882 blue = a->blue;
6883
6884 rgb_to_hls (&red, &green, &blue);
6885
6886 green *= k;
6887 if (green > 1.0)
6888 green = 1.0;
6889 else if (green < 0.0)
6890 green = 0.0;
6891
6892 blue *= k;
6893 if (blue > 1.0)
6894 blue = 1.0;
6895 else if (blue < 0.0)
6896 blue = 0.0;
6897
6898 hls_to_rgb (&red, &green, &blue);
6899
6900 b->red = red;
6901 b->green = green;
6902 b->blue = blue;
6903}
6904
6905/**
6906 * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
6907 *
6908 * \param r on input, red; on output, hue
6909 * \param g on input, green; on output, lightness
6910 * \param b on input, blue; on output, saturation
6911 */
6912static void
6913rgb_to_hls (gdouble *r,
6914 gdouble *g,
6915 gdouble *b)
6916{
6917 gdouble min;
6918 gdouble max;
6919 gdouble red;
6920 gdouble green;
6921 gdouble blue;
6922 gdouble h, l, s;
6923 gdouble delta;
6924
6925 red = *r;
6926 green = *g;
6927 blue = *b;
6928
6929 if (red > green)
6930 {
6931 if (red > blue)
6932 max = red;
6933 else
6934 max = blue;
6935
6936 if (green < blue)
6937 min = green;
6938 else
6939 min = blue;
6940 }
6941 else
6942 {
6943 if (green > blue)
6944 max = green;
6945 else
6946 max = blue;
6947
6948 if (red < blue)
6949 min = red;
6950 else
6951 min = blue;
6952 }
6953
6954 l = (max + min) / 2;
6955 s = 0;
6956 h = 0;
6957
6958 if (max != min)
6959 {
6960 if (l <= 0.5)
6961 s = (max - min) / (max + min);
6962 else
6963 s = (max - min) / (2 - max - min);
6964
6965 delta = max -min;
6966 if (red == max)
6967 h = (green - blue) / delta;
6968 else if (green == max)
6969 h = 2 + (blue - red) / delta;
6970 else if (blue == max)
6971 h = 4 + (red - green) / delta;
6972
6973 h *= 60;
6974 if (h < 0.0)
6975 h += 360;
6976 }
6977
6978 *r = h;
6979 *g = l;
6980 *b = s;
6981}
6982
6983/**
6984 * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
6985 *
6986 * \param h on input, hue; on output, red
6987 * \param l on input, lightness; on output, green
6988 * \param s on input, saturation; on output, blue
6989 */
6990static void
6991hls_to_rgb (gdouble *h,
6992 gdouble *l,
6993 gdouble *s)
6994{
6995 gdouble hue;
6996 gdouble lightness;
6997 gdouble saturation;
6998 gdouble m1, m2;
6999 gdouble r, g, b;
7000
7001 lightness = *l;
7002 saturation = *s;
7003
7004 if (lightness <= 0.5)
7005 m2 = lightness * (1 + saturation);
7006 else
7007 m2 = lightness + saturation - lightness * saturation;
7008 m1 = 2 * lightness - m2;
7009
7010 if (saturation == 0)
7011 {
7012 *h = lightness;
7013 *l = lightness;
7014 *s = lightness;
7015 }
7016 else
7017 {
7018 hue = *h + 120;
7019 while (hue > 360)
7020 hue -= 360;
7021 while (hue < 0)
7022 hue += 360;
7023
7024 if (hue < 60)
7025 r = m1 + (m2 - m1) * hue / 60;
7026 else if (hue < 180)
7027 r = m2;
7028 else if (hue < 240)
7029 r = m1 + (m2 - m1) * (240 - hue) / 60;
7030 else
7031 r = m1;
7032
7033 hue = *h;
7034 while (hue > 360)
7035 hue -= 360;
7036 while (hue < 0)
7037 hue += 360;
7038
7039 if (hue < 60)
7040 g = m1 + (m2 - m1) * hue / 60;
7041 else if (hue < 180)
7042 g = m2;
7043 else if (hue < 240)
7044 g = m1 + (m2 - m1) * (240 - hue) / 60;
7045 else
7046 g = m1;
7047
7048 hue = *h - 120;
7049 while (hue > 360)
7050 hue -= 360;
7051 while (hue < 0)
7052 hue += 360;
7053
7054 if (hue < 60)
7055 b = m1 + (m2 - m1) * hue / 60;
7056 else if (hue < 180)
7057 b = m2;
7058 else if (hue < 240)
7059 b = m1 + (m2 - m1) * (240 - hue) / 60;
7060 else
7061 b = m1;
7062
7063 *h = r;
7064 *l = g;
7065 *s = b;
7066 }
7067}
7068
7069#if 0
7070/* These are some functions I'm saving to use in optimizing
7071 * MetaDrawOpList, namely to pre-composite pixbufs on client side
7072 * prior to rendering to the server
7073 */
7074static void
7075draw_bg_solid_composite (const MetaTextureSpec *bg,
7076 const MetaTextureSpec *fg,
7077 double alpha,
7078 GtkWidget *widget,
7079 GdkDrawable *drawable,
7080 const GdkRectangle *clip,
7081 MetaTextureDrawMode mode,
7082 double xalign,
7083 double yalign,
7084 int x,
7085 int y,
7086 int width,
7087 int height)
7088{
7089 GdkColor bg_color;
7090
7091 g_assert (bg->type == META_TEXTURE_SOLID)do { if (bg->type == META_TEXTURE_SOLID) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7091, ((const char*) (__func__)), "bg->type == META_TEXTURE_SOLID"
); } while (0)
;
7092 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7092, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7093 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7093, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7094
7095 meta_color_spec_render (bg->data.solid.color_spec,
7096 widget,
7097 &bg_color);
7098
7099 switch (fg->type)
7100 {
7101 case META_TEXTURE_SOLID:
7102 {
7103 GdkColor fg_color;
7104
7105 meta_color_spec_render (fg->data.solid.color_spec,
7106 widget,
7107 &fg_color);
7108
7109 color_composite (&bg_color, &fg_color,
7110 alpha, &fg_color);
7111
7112 draw_color_rectangle (widget, drawable, &fg_color, clip,
7113 x, y, width, height);
7114 }
7115 break;
7116
7117 case META_TEXTURE_GRADIENT:
7118 /* FIXME I think we could just composite all the colors in
7119 * the gradient prior to generating the gradient?
7120 */
7121 /* FALL THRU */
7122 case META_TEXTURE_IMAGE:
7123 {
7124 GdkPixbuf *pixbuf;
7125 GdkPixbuf *composited;
7126
7127 pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7128 width, height);
7129
7130 if (pixbuf == NULL((void*)0))
7131 return;
7132
7133 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7134 gdk_pixbuf_get_has_alpha (pixbuf), 8,
7135 gdk_pixbuf_get_width (pixbuf),
7136 gdk_pixbuf_get_height (pixbuf));
7137
7138 if (composited == NULL((void*)0))
7139 {
7140 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7141 return;
7142 }
7143
7144 gdk_pixbuf_composite_color (pixbuf,
7145 composited,
7146 0, 0,
7147 gdk_pixbuf_get_width (pixbuf),
7148 gdk_pixbuf_get_height (pixbuf),
7149 0.0, 0.0, /* offsets */
7150 1.0, 1.0, /* scale */
7151 GDK_INTERP_BILINEAR,
7152 255 * alpha,
7153 0, 0, /* check offsets */
7154 0, /* check size */
7155 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
,
7156 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
);
7157
7158 /* Need to draw background since pixbuf is not
7159 * necessarily covering the whole thing
7160 */
7161 draw_color_rectangle (widget, drawable, &bg_color, clip,
7162 x, y, width, height);
7163
7164 render_pixbuf_aligned (drawable, clip, composited,
7165 xalign, yalign,
7166 x, y, width, height);
7167
7168 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7169 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7170 }
7171 break;
7172
7173 case META_TEXTURE_BLANK:
7174 case META_TEXTURE_COMPOSITE:
7175 case META_TEXTURE_SHAPE_LIST:
7176 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7176, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7177 break;
7178 }
7179}
7180
7181static void
7182draw_bg_gradient_composite (const MetaTextureSpec *bg,
7183 const MetaTextureSpec *fg,
7184 double alpha,
7185 GtkWidget *widget,
7186 GdkDrawable *drawable,
7187 const GdkRectangle *clip,
7188 MetaTextureDrawMode mode,
7189 double xalign,
7190 double yalign,
7191 int x,
7192 int y,
7193 int width,
7194 int height)
7195{
7196 g_assert (bg->type == META_TEXTURE_GRADIENT)do { if (bg->type == META_TEXTURE_GRADIENT) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7196, ((const char*) (__func__)), "bg->type == META_TEXTURE_GRADIENT"
); } while (0)
;
7197 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7197, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7198 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7198, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7199
7200 switch (fg->type)
7201 {
7202 case META_TEXTURE_SOLID:
7203 case META_TEXTURE_GRADIENT:
7204 case META_TEXTURE_IMAGE:
7205 {
7206 GdkPixbuf *bg_pixbuf;
7207 GdkPixbuf *fg_pixbuf;
7208 GdkPixbuf *composited;
7209 int fg_width, fg_height;
7210
7211 bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255,
7212 width, height);
7213
7214 if (bg_pixbuf == NULL((void*)0))
7215 return;
7216
7217 fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7218 width, height);
7219
7220 if (fg_pixbuf == NULL((void*)0))
7221 {
7222 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7223 return;
7224 }
7225
7226 /* gradients always fill the entire target area */
7227 g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width)do { if (gdk_pixbuf_get_width (bg_pixbuf) == width) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7227, ((const char*) (__func__)), "gdk_pixbuf_get_width (bg_pixbuf) == width"
); } while (0)
;
7228 g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height)do { if (gdk_pixbuf_get_height (bg_pixbuf) == height) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7228, ((const char*) (__func__)), "gdk_pixbuf_get_height (bg_pixbuf) == height"
); } while (0)
;
7229
7230 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7231 gdk_pixbuf_get_has_alpha (bg_pixbuf), 8,
7232 gdk_pixbuf_get_width (bg_pixbuf),
7233 gdk_pixbuf_get_height (bg_pixbuf));
7234
7235 if (composited == NULL((void*)0))
7236 {
7237 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7238 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7239 return;
7240 }
7241
7242 fg_width = gdk_pixbuf_get_width (fg_pixbuf);
7243 fg_height = gdk_pixbuf_get_height (fg_pixbuf);
7244
7245 /* If we wanted to be all cool we could deal with the
7246 * offsets and try to composite only in the clip rectangle,
7247 * but I just don't care enough to figure it out.
7248 */
7249
7250 gdk_pixbuf_composite (fg_pixbuf,
7251 composited,
7252 x + (width - fg_width) * xalign,
7253 y + (height - fg_height) * yalign,
7254 gdk_pixbuf_get_width (fg_pixbuf),
7255 gdk_pixbuf_get_height (fg_pixbuf),
7256 0.0, 0.0, /* offsets */
7257 1.0, 1.0, /* scale */
7258 GDK_INTERP_BILINEAR,
7259 255 * alpha);
7260
7261 gdk_cairo_set_source_pixbuf (cr, composited, x, y);
7262 cairo_paint (cr);
7263
7264 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7265 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7266 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7267 }
7268 break;
7269
7270 case META_TEXTURE_BLANK:
7271 case META_TEXTURE_SHAPE_LIST:
7272 case META_TEXTURE_COMPOSITE:
7273 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7273, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7274 break;
7275 }
7276}
7277#endif
7278
7279/**
7280 * Returns the earliest version of the theme format which required support
7281 * for a particular button. (For example, "shade" first appeared in v2, and
7282 * "close" in v1.)
7283 *
7284 * \param type the button type
7285 * \return the number of the theme format
7286 */
7287guint
7288meta_theme_earliest_version_with_button (MetaButtonType type)
7289{
7290 switch (type)
7291 {
7292 case META_BUTTON_TYPE_CLOSE:
7293 case META_BUTTON_TYPE_MAXIMIZE:
7294 case META_BUTTON_TYPE_MINIMIZE:
7295 case META_BUTTON_TYPE_MENU:
7296 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
7297 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
7298 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
7299 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
7300 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
7301 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
7302 return 1000;
7303
7304 case META_BUTTON_TYPE_SHADE:
7305 case META_BUTTON_TYPE_ABOVE:
7306 case META_BUTTON_TYPE_STICK:
7307 case META_BUTTON_TYPE_UNSHADE:
7308 case META_BUTTON_TYPE_UNABOVE:
7309 case META_BUTTON_TYPE_UNSTICK:
7310 return 2000;
7311
7312 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
7313 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
7314 return 3003;
7315
7316 case META_BUTTON_TYPE_APPMENU:
7317 return 3005;
7318
7319 default:
7320 meta_warning("Unknown button %d\n", type);
7321 return 1000;
7322 }
7323}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-82159e.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-82159e.html new file mode 100644 index 00000000..7f8aaaf8 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-82159e.html @@ -0,0 +1,2038 @@ + + + +core/xprops.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/xprops.c
Warning:line 475, column 7
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name xprops.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/xprops.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco X property convenience routines */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 * Copyright (C) 2002 Red Hat Inc.
8 *
9 * Some trivial property-unpacking code from Xlib:
10 * Copyright 1987, 1988, 1998 The Open Group
11 * Copyright 1988 by Wyse Technology, Inc., San Jose, Ca,
12 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27 * 02110-1301, USA.
28 */
29
30/***********************************************************
31Copyright 1988 by Wyse Technology, Inc., San Jose, Ca,
32Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
33
34 All Rights Reserved
35
36Permission to use, copy, modify, and distribute this software and its
37documentation for any purpose and without fee is hereby granted,
38provided that the above copyright notice appear in all copies and that
39both that copyright notice and this permission notice appear in
40supporting documentation, and that the name Digital not be
41used in advertising or publicity pertaining to distribution of the
42software without specific, written prior permission.
43
44DIGITAL AND WYSE DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
45INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
46EVENT SHALL DIGITAL OR WYSE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
47CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
48USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
49OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
50PERFORMANCE OF THIS SOFTWARE.
51
52******************************************************************/
53
54/*
55
56Copyright 1987, 1988, 1998 The Open Group
57
58Permission to use, copy, modify, distribute, and sell this software and its
59documentation for any purpose is hereby granted without fee, provided that
60the above copyright notice appear in all copies and that both that
61copyright notice and this permission notice appear in supporting
62documentation.
63
64The above copyright notice and this permission notice shall be included
65in all copies or substantial portions of the Software.
66
67THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
68OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
69MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
70IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
71OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
72ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
73OTHER DEALINGS IN THE SOFTWARE.
74
75Except as contained in this notice, the name of The Open Group shall
76not be used in advertising or otherwise to promote the sale, use or
77other dealings in this Software without prior written authorization
78from The Open Group.
79
80*/
81
82#include <config.h>
83#include <glib/gi18n-lib.h>
84
85#include "xprops.h"
86#include "errors.h"
87#include "util.h"
88#include "async-getprop.h"
89#include "ui.h"
90#include "marco-Xatomtype.h"
91#include <X11/Xatom.h>
92#include <string.h>
93#include "window-private.h"
94
95typedef struct
96{
97 MetaDisplay *display;
98 Window xwindow;
99 Atom xatom;
100 Atom type;
101 int format;
102 unsigned long n_items;
103 unsigned long bytes_after;
104 unsigned char *prop;
105} GetPropertyResults;
106
107static gboolean
108validate_or_free_results (GetPropertyResults *results,
109 int expected_format,
110 Atom expected_type,
111 gboolean must_have_items)
112{
113 char *type_name;
114 char *expected_name;
115 char *prop_name;
116 const char *title;
117 const char *res_class;
118 const char *res_name;
119 MetaWindow *w;
120
121 if (expected_format == results->format &&
122 expected_type == results->type &&
123 (!must_have_items || results->n_items > 0))
124 return TRUE(!(0));
125
126 meta_error_trap_push (results->display);
127 type_name = XGetAtomName (results->display->xdisplay, results->type);
128 expected_name = XGetAtomName (results->display->xdisplay, expected_type);
129 prop_name = XGetAtomName (results->display->xdisplay, results->xatom);
130 meta_error_trap_pop (results->display, TRUE(!(0)));
131
132 w = meta_display_lookup_x_window (results->display, results->xwindow);
133
134 if (w != NULL((void*)0))
135 {
136 title = w->title;
137 res_class = w->res_class;
138 res_name = w->res_name;
139 }
140 else
141 {
142 title = NULL((void*)0);
143 res_class = NULL((void*)0);
144 res_name = NULL((void*)0);
145 }
146
147 if (title == NULL((void*)0))
148 title = "unknown";
149
150 if (res_class == NULL((void*)0))
151 res_class = "unknown";
152
153 if (res_name == NULL((void*)0))
154 res_name = "unknown";
155
156 meta_warning (_("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n")((char *) g_dgettext ("marco", "Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n"
))
,
157 results->xwindow,
158 prop_name ? prop_name : "(bad atom)",
159 expected_name ? expected_name : "(bad atom)",
160 expected_format,
161 type_name ? type_name : "(bad atom)",
162 results->format, (int) results->n_items,
163 title, res_class, res_name);
164
165 if (type_name)
166 XFree (type_name);
167 if (expected_name)
168 XFree (expected_name);
169 if (prop_name)
170 XFree (prop_name);
171
172 if (results->prop)
173 {
174 XFree (results->prop);
175 results->prop = NULL((void*)0);
176 }
177
178 return FALSE(0);
179}
180
181static gboolean
182get_property (MetaDisplay *display,
183 Window xwindow,
184 Atom xatom,
185 Atom req_type,
186 GetPropertyResults *results)
187{
188 results->display = display;
189 results->xwindow = xwindow;
190 results->xatom = xatom;
191 results->prop = NULL((void*)0);
192 results->n_items = 0;
193 results->type = None0L;
194 results->bytes_after = 0;
195 results->format = 0;
196
197 meta_error_trap_push (display);
198 if (XGetWindowProperty (display->xdisplay, xwindow, xatom,
199 0, G_MAXLONG9223372036854775807L,
200 False0, req_type, &results->type, &results->format,
201 &results->n_items,
202 &results->bytes_after,
203 &results->prop) != Success0 ||
204 results->type == None0L)
205 {
206 if (results->prop)
207 XFree (results->prop);
208 meta_error_trap_pop_with_return (display, TRUE(!(0)));
209 return FALSE(0);
210 }
211
212 if (meta_error_trap_pop_with_return (display, TRUE(!(0))) != Success0)
213 {
214 if (results->prop)
215 XFree (results->prop);
216 return FALSE(0);
217 }
218
219 return TRUE(!(0));
220}
221
222static gboolean
223atom_list_from_results (GetPropertyResults *results,
224 Atom **atoms_p,
225 int *n_atoms_p)
226{
227 if (!validate_or_free_results (results, 32, XA_ATOM((Atom) 4), FALSE(0)))
228 return FALSE(0);
229
230 *atoms_p = (Atom*) results->prop;
231 *n_atoms_p = results->n_items;
232 results->prop = NULL((void*)0);
233
234 return TRUE(!(0));
235}
236
237gboolean
238meta_prop_get_atom_list (MetaDisplay *display,
239 Window xwindow,
240 Atom xatom,
241 Atom **atoms_p,
242 int *n_atoms_p)
243{
244 GetPropertyResults results;
245
246 *atoms_p = NULL((void*)0);
247 *n_atoms_p = 0;
248
249 if (!get_property (display, xwindow, xatom, XA_ATOM((Atom) 4),
250 &results))
251 return FALSE(0);
252
253 return atom_list_from_results (&results, atoms_p, n_atoms_p);
254}
255
256static gboolean
257cardinal_list_from_results (GetPropertyResults *results,
258 gulong **cardinals_p,
259 int *n_cardinals_p)
260{
261 if (!validate_or_free_results (results, 32, XA_CARDINAL((Atom) 6), FALSE(0)))
262 return FALSE(0);
263
264 *cardinals_p = (gulong*) results->prop;
265 *n_cardinals_p = results->n_items;
266 results->prop = NULL((void*)0);
267
268#if GLIB_SIZEOF_LONG8 == 8
269 /* Xlib sign-extends format=32 items, but we want them unsigned */
270 {
271 int i;
272
273 for (i = 0; i < *n_cardinals_p; i++)
274 (*cardinals_p)[i] = (*cardinals_p)[i] & 0xffffffff;
275 }
276#endif
277
278 return TRUE(!(0));
279}
280
281gboolean
282meta_prop_get_cardinal_list (MetaDisplay *display,
283 Window xwindow,
284 Atom xatom,
285 gulong **cardinals_p,
286 int *n_cardinals_p)
287{
288 GetPropertyResults results;
289
290 *cardinals_p = NULL((void*)0);
291 *n_cardinals_p = 0;
292
293 if (!get_property (display, xwindow, xatom, XA_CARDINAL((Atom) 6),
294 &results))
295 return FALSE(0);
296
297 return cardinal_list_from_results (&results, cardinals_p, n_cardinals_p);
298}
299
300static gboolean
301motif_hints_from_results (GetPropertyResults *results,
302 MotifWmHints **hints_p)
303{
304 int real_size, max_size;
305#define MAX_ITEMSsizeof (MotifWmHints)/sizeof (gulong) sizeof (MotifWmHints)/sizeof (gulong)
306
307 *hints_p = NULL((void*)0);
308
309 if (results->type == None0L || results->n_items <= 0)
310 {
311 meta_verbosemeta_verbose_real ("Motif hints had unexpected type or n_items\n");
312 if (results->prop)
313 {
314 XFree (results->prop);
315 results->prop = NULL((void*)0);
316 }
317 return FALSE(0);
318 }
319
320 /* The issue here is that some old crufty code will set a smaller
321 * MotifWmHints than the one we expect, apparently. I'm not sure of
322 * the history behind it. See bug #89841 for example.
323 */
324 *hints_p = ag_Xmalloc (sizeof (MotifWmHints));
325 if (*hints_p == NULL((void*)0))
326 {
327 if (results->prop)
328 {
329 XFree (results->prop);
330 results->prop = NULL((void*)0);
331 }
332 return FALSE(0);
333 }
334 real_size = results->n_items * sizeof (gulong);
335 max_size = MAX_ITEMSsizeof (MotifWmHints)/sizeof (gulong) * sizeof (gulong);
336 memcpy (*hints_p, results->prop, MIN (real_size, max_size)(((real_size) < (max_size)) ? (real_size) : (max_size)));
337
338 if (results->prop)
339 {
340 XFree (results->prop);
341 results->prop = NULL((void*)0);
342 }
343
344 return TRUE(!(0));
345}
346
347gboolean
348meta_prop_get_motif_hints (MetaDisplay *display,
349 Window xwindow,
350 Atom xatom,
351 MotifWmHints **hints_p)
352{
353 GetPropertyResults results;
354
355 *hints_p = NULL((void*)0);
356
357 if (!get_property (display, xwindow, xatom, AnyPropertyType0L,
358 &results))
359 return FALSE(0);
360
361 return motif_hints_from_results (&results, hints_p);
362}
363
364static gboolean
365latin1_string_from_results (GetPropertyResults *results,
366 char **str_p)
367{
368 *str_p = NULL((void*)0);
369
370 if (!validate_or_free_results (results, 8, XA_STRING((Atom) 31), FALSE(0)))
371 return FALSE(0);
372
373 *str_p = (char*) results->prop;
374 results->prop = NULL((void*)0);
375
376 return TRUE(!(0));
377}
378
379gboolean
380meta_prop_get_latin1_string (MetaDisplay *display,
381 Window xwindow,
382 Atom xatom,
383 char **str_p)
384{
385 GetPropertyResults results;
386
387 *str_p = NULL((void*)0);
388
389 if (!get_property (display, xwindow, xatom, XA_STRING((Atom) 31),
390 &results))
391 return FALSE(0);
392
393 return latin1_string_from_results (&results, str_p);
394}
395
396static gboolean
397utf8_string_from_results (GetPropertyResults *results,
398 char **str_p)
399{
400 *str_p = NULL((void*)0);
401
402 if (!validate_or_free_results (results, 8,
403 results->display->atom_UTF8_STRING, FALSE(0)))
404 return FALSE(0);
405
406 if (results->n_items > 0 &&
407 !g_utf8_validate ((gchar *)results->prop, results->n_items, NULL((void*)0)))
408 {
409 char *name;
410
411 name = XGetAtomName (results->display->xdisplay, results->xatom);
412 meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8\n")((char *) g_dgettext ("marco", "Property %s on window 0x%lx contained invalid UTF-8\n"
))
,
413 name, results->xwindow);
414 meta_XFree (name)do { if ((name)) XFree ((name)); } while (0);
415 XFree (results->prop);
416 results->prop = NULL((void*)0);
417
418 return FALSE(0);
419 }
420
421 *str_p = (char*) results->prop;
422 results->prop = NULL((void*)0);
423
424 return TRUE(!(0));
425}
426
427gboolean
428meta_prop_get_utf8_string (MetaDisplay *display,
429 Window xwindow,
430 Atom xatom,
431 char **str_p)
432{
433 GetPropertyResults results;
434
435 *str_p = NULL((void*)0);
436
437 if (!get_property (display, xwindow, xatom,
438 display->atom_UTF8_STRING,
439 &results))
440 return FALSE(0);
441
442 return utf8_string_from_results (&results, str_p);
443}
444
445/* this one freakishly returns g_malloc memory */
446static gboolean
447utf8_list_from_results (GetPropertyResults *results,
448 char ***str_p,
449 int *n_str_p)
450{
451 int i;
452 int n_strings;
453 char **retval;
454 const char *p;
455
456 *str_p = NULL((void*)0);
457 *n_str_p = 0;
458
459 if (!validate_or_free_results (results, 8,
25
Taking false branch
460 results->display->atom_UTF8_STRING, FALSE(0)))
461 return FALSE(0);
462
463 /* I'm not sure this is right, but I'm guessing the
464 * property is nul-separated
465 */
466 i = 0;
467 n_strings = 0;
468 while (i < (int) results->n_items)
26
Assuming 'i' is >= field 'n_items'
27
Loop condition is false. Execution continues on line 475
469 {
470 if (results->prop[i] == '\0')
471 ++n_strings;
472 ++i;
473 }
474
475 if (results->prop[results->n_items - 1] != '\0')
28
Out of bound memory access (access exceeds upper limit of memory block)
476 ++n_strings;
477
478 /* we're guaranteed that results->prop has a nul on the end
479 * by XGetWindowProperty
480 */
481
482 retval = g_new0 (char*, n_strings + 1)((char* *) g_malloc0_n ((n_strings + 1), sizeof (char*)));
483
484 p = (char *)results->prop;
485 i = 0;
486 while (i < n_strings)
487 {
488 if (!g_utf8_validate (p, -1, NULL((void*)0)))
489 {
490 char *name;
491
492 meta_error_trap_push (results->display);
493 name = XGetAtomName (results->display->xdisplay, results->xatom);
494 meta_error_trap_pop (results->display, TRUE(!(0)));
495 meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n")((char *) g_dgettext ("marco", "Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n"
))
,
496 name, results->xwindow, i);
497 meta_XFree (name)do { if ((name)) XFree ((name)); } while (0);
498 meta_XFree (results->prop)do { if ((results->prop)) XFree ((results->prop)); } while
(0)
;
499 results->prop = NULL((void*)0);
500
501 g_strfreev (retval);
502 return FALSE(0);
503 }
504
505 retval[i] = g_strdup (p)g_strdup_inline (p);
506
507 p = p + strlen (p) + 1;
508 ++i;
509 }
510
511 *str_p = retval;
512 *n_str_p = i;
513
514 meta_XFree (results->prop)do { if ((results->prop)) XFree ((results->prop)); } while
(0)
;
515 results->prop = NULL((void*)0);
516
517 return TRUE(!(0));
518}
519
520/* returns g_malloc not Xmalloc memory */
521gboolean
522meta_prop_get_utf8_list (MetaDisplay *display,
523 Window xwindow,
524 Atom xatom,
525 char ***str_p,
526 int *n_str_p)
527{
528 GetPropertyResults results;
529
530 *str_p = NULL((void*)0);
531
532 if (!get_property (display, xwindow, xatom,
533 display->atom_UTF8_STRING,
534 &results))
535 return FALSE(0);
536
537 return utf8_list_from_results (&results, str_p, n_str_p);
538}
539
540void
541meta_prop_set_utf8_string_hint (MetaDisplay *display,
542 Window xwindow,
543 Atom atom,
544 const char *val)
545{
546 meta_error_trap_push (display);
547 XChangeProperty (display->xdisplay,
548 xwindow, atom,
549 display->atom_UTF8_STRING,
550 8, PropModeReplace0, (guchar*) val, strlen (val));
551 meta_error_trap_pop (display, FALSE(0));
552}
553
554static gboolean
555window_from_results (GetPropertyResults *results,
556 Window *window_p)
557{
558 if (!validate_or_free_results (results, 32, XA_WINDOW((Atom) 33), TRUE(!(0))))
559 return FALSE(0);
560
561 *window_p = *(Window*) results->prop;
562 XFree (results->prop);
563 results->prop = NULL((void*)0);
564
565 return TRUE(!(0));
566}
567
568#ifdef HAVE_XSYNC
569static gboolean
570counter_from_results (GetPropertyResults *results,
571 XSyncCounter *counter_p)
572{
573 if (!validate_or_free_results (results, 32,
574 XA_CARDINAL((Atom) 6),
575 TRUE(!(0))))
576 return FALSE(0);
577
578 *counter_p = *(XSyncCounter*) results->prop;
579 XFree (results->prop);
580 results->prop = NULL((void*)0);
581
582 return TRUE(!(0));
583}
584#endif
585
586gboolean
587meta_prop_get_window (MetaDisplay *display,
588 Window xwindow,
589 Atom xatom,
590 Window *window_p)
591{
592 GetPropertyResults results;
593
594 *window_p = None0L;
595
596 if (!get_property (display, xwindow, xatom, XA_WINDOW((Atom) 33),
597 &results))
598 return FALSE(0);
599
600 return window_from_results (&results, window_p);
601}
602
603gboolean
604meta_prop_get_cardinal (MetaDisplay *display,
605 Window xwindow,
606 Atom xatom,
607 gulong *cardinal_p)
608{
609 return meta_prop_get_cardinal_with_atom_type (display, xwindow, xatom,
610 XA_CARDINAL((Atom) 6), cardinal_p);
611}
612
613static gboolean
614cardinal_with_atom_type_from_results (GetPropertyResults *results,
615 Atom prop_type,
616 gulong *cardinal_p)
617{
618 if (!validate_or_free_results (results, 32, prop_type, TRUE(!(0))))
619 return FALSE(0);
620
621 *cardinal_p = *(gulong*) results->prop;
622#if GLIB_SIZEOF_LONG8 == 8
623 /* Xlib sign-extends format=32 items, but we want them unsigned */
624 *cardinal_p &= 0xffffffff;
625#endif
626 XFree (results->prop);
627 results->prop = NULL((void*)0);
628
629 return TRUE(!(0));
630}
631
632gboolean
633meta_prop_get_cardinal_with_atom_type (MetaDisplay *display,
634 Window xwindow,
635 Atom xatom,
636 Atom prop_type,
637 gulong *cardinal_p)
638{
639 GetPropertyResults results;
640
641 *cardinal_p = 0;
642
643 if (!get_property (display, xwindow, xatom, prop_type,
644 &results))
645 return FALSE(0);
646
647 return cardinal_with_atom_type_from_results (&results, prop_type, cardinal_p);
648}
649
650static char *
651text_property_to_utf8 (Display *xdisplay,
652 const XTextProperty *prop)
653{
654 char *ret = NULL((void*)0);
655 char **local_list = NULL((void*)0);
656 const char *charset = NULL((void*)0);
657 int count = 0;
658 int res;
659
660 res = XmbTextPropertyToTextList (xdisplay, prop, &local_list, &count);
661 if (res == XNoMemory-1 || res == XLocaleNotSupported-2 || res == XConverterNotFound-3)
662 return NULL((void*)0);
663
664 if (count == 0)
665 {
666 XFreeStringList (local_list);
667 return NULL((void*)0);
668 }
669
670 if (g_get_charset (&charset))
671 ret = g_strdup (local_list[0])g_strdup_inline (local_list[0]);
672 else
673 ret = g_convert (local_list[0], -1, "UTF-8", charset, NULL((void*)0), NULL((void*)0), NULL((void*)0));
674
675 XFreeStringList (local_list);
676 return ret;
677}
678
679static gboolean
680text_property_from_results (GetPropertyResults *results,
681 char **utf8_str_p)
682{
683 XTextProperty tp;
684
685 *utf8_str_p = NULL((void*)0);
686
687 tp.value = results->prop;
688 results->prop = NULL((void*)0);
689 tp.encoding = results->type;
690 tp.format = results->format;
691 tp.nitems = results->n_items;
692
693 *utf8_str_p = text_property_to_utf8 (results->display->xdisplay, &tp);
694
695 if (tp.value != NULL((void*)0))
696 XFree (tp.value);
697
698 return *utf8_str_p != NULL((void*)0);
699}
700
701gboolean
702meta_prop_get_text_property (MetaDisplay *display,
703 Window xwindow,
704 Atom xatom,
705 char **utf8_str_p)
706{
707 GetPropertyResults results;
708
709 if (!get_property (display, xwindow, xatom, AnyPropertyType0L,
710 &results))
711 return FALSE(0);
712
713 return text_property_from_results (&results, utf8_str_p);
714}
715
716/* From Xmd.h */
717#ifndef cvtINT32toInt
718#if SIZEOF_VOID_P8 == 8
719#define cvtINT8toInt(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
((((unsigned int)val) & 0x00000080) ? (((unsigned int)val) | 0xffffffffffffff00) : ((unsigned int)val))
720#define cvtINT16toInt(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
((((unsigned int)val) & 0x00008000) ? (((unsigned int)val) | 0xffffffffffff0000) : ((unsigned int)val))
721#define cvtINT32toInt(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
((((unsigned int)val) & 0x80000000) ? (((unsigned int)val) | 0xffffffff00000000) : ((unsigned int)val))
722#define cvtINT8toShort(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
cvtINT8toInt(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
723#define cvtINT16toShort(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
cvtINT16toInt(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
724#define cvtINT32toShort(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
cvtINT32toInt(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
725#define cvtINT8toLong(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
cvtINT8toInt(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
726#define cvtINT16toLong(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
cvtINT16toInt(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
727#define cvtINT32toLong(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
cvtINT32toInt(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
728#else
729#define cvtINT8toInt(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
(val)
730#define cvtINT16toInt(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
(val)
731#define cvtINT32toInt(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
(val)
732#define cvtINT8toShort(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
(val)
733#define cvtINT16toShort(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
(val)
734#define cvtINT32toShort(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
(val)
735#define cvtINT8toLong(val)((((unsigned int)val) & 0x00000080) ? (((unsigned int)val
) | 0xffffffffffffff00) : ((unsigned int)val))
(val)
736#define cvtINT16toLong(val)((((unsigned int)val) & 0x00008000) ? (((unsigned int)val
) | 0xffffffffffff0000) : ((unsigned int)val))
(val)
737#define cvtINT32toLong(val)((((unsigned int)val) & 0x80000000) ? (((unsigned int)val
) | 0xffffffff00000000) : ((unsigned int)val))
(val)
738#endif /* SIZEOF_VOID_P == 8 */
739#endif /* cvtINT32toInt() */
740
741static gboolean
742wm_hints_from_results (GetPropertyResults *results,
743 XWMHints **hints_p)
744{
745 XWMHints *hints;
746 xPropWMHints *raw;
747
748 *hints_p = NULL((void*)0);
749
750 if (!validate_or_free_results (results, 32, XA_WM_HINTS((Atom) 35), TRUE(!(0))))
751 return FALSE(0);
752
753 /* pre-R3 bogusly truncated window_group, don't fail on them */
754 if (results->n_items < (NumPropWMHintsElements9 - 1))
755 {
756 meta_verbosemeta_verbose_real ("WM_HINTS property too short: %d should be %d\n",
757 (int) results->n_items, NumPropWMHintsElements9 - 1);
758 if (results->prop)
759 {
760 XFree (results->prop);
761 results->prop = NULL((void*)0);
762 }
763 return FALSE(0);
764 }
765
766 hints = ag_Xmalloc0 (sizeof (XWMHints));
767
768 raw = (xPropWMHints*) (gpointer) results->prop;
769
770 hints->flags = raw->flags;
771 hints->input = (raw->input ? True1 : False0);
772 hints->initial_state = cvtINT32toInt (raw->initialState)((((unsigned int)raw->initialState) & 0x80000000) ? ((
(unsigned int)raw->initialState) | 0xffffffff00000000) : (
(unsigned int)raw->initialState))
;
773 hints->icon_pixmap = raw->iconPixmap;
774 hints->icon_window = raw->iconWindow;
775 hints->icon_x = cvtINT32toInt (raw->iconX)((((unsigned int)raw->iconX) & 0x80000000) ? (((unsigned
int)raw->iconX) | 0xffffffff00000000) : ((unsigned int)raw
->iconX))
;
776 hints->icon_y = cvtINT32toInt (raw->iconY)((((unsigned int)raw->iconY) & 0x80000000) ? (((unsigned
int)raw->iconY) | 0xffffffff00000000) : ((unsigned int)raw
->iconY))
;
777 hints->icon_mask = raw->iconMask;
778 if (results->n_items >= NumPropWMHintsElements9)
779 hints->window_group = raw->windowGroup;
780 else
781 hints->window_group = 0;
782
783 if (results->prop)
784 {
785 XFree (results->prop);
786 results->prop = NULL((void*)0);
787 }
788
789 *hints_p = hints;
790
791 return TRUE(!(0));
792}
793
794gboolean
795meta_prop_get_wm_hints (MetaDisplay *display,
796 Window xwindow,
797 Atom xatom,
798 XWMHints **hints_p)
799{
800 GetPropertyResults results;
801
802 *hints_p = NULL((void*)0);
803
804 if (!get_property (display, xwindow, xatom, XA_WM_HINTS((Atom) 35),
805 &results))
806 return FALSE(0);
807
808 return wm_hints_from_results (&results, hints_p);
809}
810
811static gboolean
812class_hint_from_results (GetPropertyResults *results,
813 XClassHint *class_hint)
814{
815 int len_name, len_class;
816
817 class_hint->res_class = NULL((void*)0);
818 class_hint->res_name = NULL((void*)0);
819
820 if (!validate_or_free_results (results, 8, XA_STRING((Atom) 31), FALSE(0)))
821 return FALSE(0);
822
823 len_name = strlen ((char *) results->prop);
824 if (! (class_hint->res_name = ag_Xmalloc (len_name+1)))
825 {
826 XFree (results->prop);
827 results->prop = NULL((void*)0);
828 return FALSE(0);
829 }
830
831 g_strlcpy (class_hint->res_name, (char *)results->prop, (len_name + 1));
832
833 if (len_name == (int) results->n_items)
834 len_name--;
835
836 len_class = strlen ((char *)results->prop + len_name + 1);
837
838 if (! (class_hint->res_class = ag_Xmalloc(len_class+1)))
839 {
840 XFree(class_hint->res_name);
841 class_hint->res_name = NULL((void*)0);
842 XFree (results->prop);
843 results->prop = NULL((void*)0);
844 return FALSE(0);
845 }
846
847 g_strlcpy (class_hint->res_class, (char *)results->prop + len_name + 1, (len_class + 1));
848
849 XFree (results->prop);
850 results->prop = NULL((void*)0);
851
852 return TRUE(!(0));
853}
854
855gboolean
856meta_prop_get_class_hint (MetaDisplay *display,
857 Window xwindow,
858 Atom xatom,
859 XClassHint *class_hint)
860{
861 GetPropertyResults results;
862
863 class_hint->res_class = NULL((void*)0);
864 class_hint->res_name = NULL((void*)0);
865
866 if (!get_property (display, xwindow, xatom, XA_STRING((Atom) 31),
867 &results))
868 return FALSE(0);
869
870 return class_hint_from_results (&results, class_hint);
871}
872
873static gboolean
874size_hints_from_results (GetPropertyResults *results,
875 XSizeHints **hints_p,
876 gulong *flags_p)
877{
878 xPropSizeHints *raw;
879 XSizeHints *hints;
880
881 *hints_p = NULL((void*)0);
882 *flags_p = 0;
883
884 if (!validate_or_free_results (results, 32, XA_WM_SIZE_HINTS((Atom) 41), FALSE(0)))
885 return FALSE(0);
886
887 if (results->n_items < OldNumPropSizeElements15)
888 return FALSE(0);
889
890 raw = (xPropSizeHints*) (gpointer) results->prop;
891
892 hints = ag_Xmalloc (sizeof (XSizeHints));
893
894 /* XSizeHints misdeclares these as int instead of long */
895 hints->flags = raw->flags;
896 hints->x = cvtINT32toInt (raw->x)((((unsigned int)raw->x) & 0x80000000) ? (((unsigned int
)raw->x) | 0xffffffff00000000) : ((unsigned int)raw->x)
)
;
897 hints->y = cvtINT32toInt (raw->y)((((unsigned int)raw->y) & 0x80000000) ? (((unsigned int
)raw->y) | 0xffffffff00000000) : ((unsigned int)raw->y)
)
;
898 hints->width = cvtINT32toInt (raw->width)((((unsigned int)raw->width) & 0x80000000) ? (((unsigned
int)raw->width) | 0xffffffff00000000) : ((unsigned int)raw
->width))
;
899 hints->height = cvtINT32toInt (raw->height)((((unsigned int)raw->height) & 0x80000000) ? (((unsigned
int)raw->height) | 0xffffffff00000000) : ((unsigned int)raw
->height))
;
900 hints->min_width = cvtINT32toInt (raw->minWidth)((((unsigned int)raw->minWidth) & 0x80000000) ? (((unsigned
int)raw->minWidth) | 0xffffffff00000000) : ((unsigned int
)raw->minWidth))
;
901 hints->min_height = cvtINT32toInt (raw->minHeight)((((unsigned int)raw->minHeight) & 0x80000000) ? (((unsigned
int)raw->minHeight) | 0xffffffff00000000) : ((unsigned int
)raw->minHeight))
;
902 hints->max_width = cvtINT32toInt (raw->maxWidth)((((unsigned int)raw->maxWidth) & 0x80000000) ? (((unsigned
int)raw->maxWidth) | 0xffffffff00000000) : ((unsigned int
)raw->maxWidth))
;
903 hints->max_height = cvtINT32toInt (raw->maxHeight)((((unsigned int)raw->maxHeight) & 0x80000000) ? (((unsigned
int)raw->maxHeight) | 0xffffffff00000000) : ((unsigned int
)raw->maxHeight))
;
904 hints->width_inc = cvtINT32toInt (raw->widthInc)((((unsigned int)raw->widthInc) & 0x80000000) ? (((unsigned
int)raw->widthInc) | 0xffffffff00000000) : ((unsigned int
)raw->widthInc))
;
905 hints->height_inc = cvtINT32toInt (raw->heightInc)((((unsigned int)raw->heightInc) & 0x80000000) ? (((unsigned
int)raw->heightInc) | 0xffffffff00000000) : ((unsigned int
)raw->heightInc))
;
906 hints->min_aspect.x = cvtINT32toInt (raw->minAspectX)((((unsigned int)raw->minAspectX) & 0x80000000) ? (((unsigned
int)raw->minAspectX) | 0xffffffff00000000) : ((unsigned int
)raw->minAspectX))
;
907 hints->min_aspect.y = cvtINT32toInt (raw->minAspectY)((((unsigned int)raw->minAspectY) & 0x80000000) ? (((unsigned
int)raw->minAspectY) | 0xffffffff00000000) : ((unsigned int
)raw->minAspectY))
;
908 hints->max_aspect.x = cvtINT32toInt (raw->maxAspectX)((((unsigned int)raw->maxAspectX) & 0x80000000) ? (((unsigned
int)raw->maxAspectX) | 0xffffffff00000000) : ((unsigned int
)raw->maxAspectX))
;
909 hints->max_aspect.y = cvtINT32toInt (raw->maxAspectY)((((unsigned int)raw->maxAspectY) & 0x80000000) ? (((unsigned
int)raw->maxAspectY) | 0xffffffff00000000) : ((unsigned int
)raw->maxAspectY))
;
910
911 *flags_p = (USPosition(1L << 0) | USSize(1L << 1) | PAllHints((1L << 2)|(1L << 3)|(1L << 4)|(1L <<
5)|(1L << 6)|(1L << 7))
);
912 if (results->n_items >= NumPropSizeElements18)
913 {
914 hints->base_width= cvtINT32toInt (raw->baseWidth)((((unsigned int)raw->baseWidth) & 0x80000000) ? (((unsigned
int)raw->baseWidth) | 0xffffffff00000000) : ((unsigned int
)raw->baseWidth))
;
915 hints->base_height= cvtINT32toInt (raw->baseHeight)((((unsigned int)raw->baseHeight) & 0x80000000) ? (((unsigned
int)raw->baseHeight) | 0xffffffff00000000) : ((unsigned int
)raw->baseHeight))
;
916 hints->win_gravity= cvtINT32toInt (raw->winGravity)((((unsigned int)raw->winGravity) & 0x80000000) ? (((unsigned
int)raw->winGravity) | 0xffffffff00000000) : ((unsigned int
)raw->winGravity))
;
917 *flags_p |= (PBaseSize(1L << 8) | PWinGravity(1L << 9));
918 }
919
920 hints->flags &= (*flags_p); /* get rid of unwanted bits */
921
922 XFree (results->prop);
923 results->prop = NULL((void*)0);
924
925 *hints_p = hints;
926
927 return TRUE(!(0));
928}
929
930gboolean
931meta_prop_get_size_hints (MetaDisplay *display,
932 Window xwindow,
933 Atom xatom,
934 XSizeHints **hints_p,
935 gulong *flags_p)
936{
937 GetPropertyResults results;
938
939 *hints_p = NULL((void*)0);
940 *flags_p = 0;
941
942 if (!get_property (display, xwindow, xatom, XA_WM_SIZE_HINTS((Atom) 41),
943 &results))
944 return FALSE(0);
945
946 return size_hints_from_results (&results, hints_p, flags_p);
947}
948
949static AgGetPropertyTask*
950get_task (MetaDisplay *display,
951 Window xwindow,
952 Atom xatom,
953 Atom req_type)
954{
955 return ag_task_create (display->xdisplay,
956 xwindow,
957 xatom, 0, G_MAXLONG9223372036854775807L,
958 False0, req_type);
959}
960
961static char*
962latin1_to_utf8 (const char *text)
963{
964 GString *str;
965 const char *p;
966
967 str = g_string_new ("");
968
969 p = text;
970 while (*p)
971 {
972 g_string_append_unichar (str, *p);
973 ++p;
974 }
975
976 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
977}
978
979void
980meta_prop_get_values (MetaDisplay *display,
981 Window xwindow,
982 MetaPropValue *values,
983 int n_values)
984{
985 int i;
986 AgGetPropertyTask **tasks;
987
988 meta_verbosemeta_verbose_real ("Requesting %d properties of 0x%lx at once\n",
989 n_values, xwindow);
990
991 if (n_values == 0)
1
Assuming 'n_values' is not equal to 0
2
Taking false branch
992 return;
993
994 tasks = g_new0 (AgGetPropertyTask*, n_values)((AgGetPropertyTask* *) g_malloc0_n ((n_values), sizeof (AgGetPropertyTask
*)))
;
995
996 /* Start up tasks. The "values" array can have values
997 * with atom == None, which means to ignore that element.
998 */
999 i = 0;
1000 while (i < n_values)
3
Assuming 'i' is < 'n_values'
4
Loop condition is true. Entering loop body
9
Assuming 'i' is >= 'n_values'
10
Loop condition is false. Execution continues on line 1060
1001 {
1002 if (values[i].required_type == None0L)
5
Assuming field 'required_type' is not equal to None
6
Taking false branch
1003 {
1004 switch (values[i].type)
1005 {
1006 case META_PROP_VALUE_INVALID:
1007 /* This means we don't really want a value, e.g. got
1008 * property notify on an atom we don't care about.
1009 */
1010 if (values[i].atom != None0L)
1011 meta_bug ("META_PROP_VALUE_INVALID requested in %s\n", G_STRFUNC((const char*) (__func__)));
1012 break;
1013 case META_PROP_VALUE_UTF8_LIST:
1014 case META_PROP_VALUE_UTF8:
1015 values[i].required_type = display->atom_UTF8_STRING;
1016 break;
1017 case META_PROP_VALUE_STRING:
1018 case META_PROP_VALUE_STRING_AS_UTF8:
1019 values[i].required_type = XA_STRING((Atom) 31);
1020 break;
1021 case META_PROP_VALUE_MOTIF_HINTS:
1022 values[i].required_type = AnyPropertyType0L;
1023 break;
1024 case META_PROP_VALUE_CARDINAL_LIST:
1025 case META_PROP_VALUE_CARDINAL:
1026 values[i].required_type = XA_CARDINAL((Atom) 6);
1027 break;
1028 case META_PROP_VALUE_WINDOW:
1029 values[i].required_type = XA_WINDOW((Atom) 33);
1030 break;
1031 case META_PROP_VALUE_ATOM_LIST:
1032 values[i].required_type = XA_ATOM((Atom) 4);
1033 break;
1034 case META_PROP_VALUE_TEXT_PROPERTY:
1035 values[i].required_type = AnyPropertyType0L;
1036 break;
1037 case META_PROP_VALUE_WM_HINTS:
1038 values[i].required_type = XA_WM_HINTS((Atom) 35);
1039 break;
1040 case META_PROP_VALUE_CLASS_HINT:
1041 values[i].required_type = XA_STRING((Atom) 31);
1042 break;
1043 case META_PROP_VALUE_SIZE_HINTS:
1044 values[i].required_type = XA_WM_SIZE_HINTS((Atom) 41);
1045 break;
1046 case META_PROP_VALUE_SYNC_COUNTER:
1047 values[i].required_type = XA_CARDINAL((Atom) 6);
1048 break;
1049 }
1050 }
1051
1052 if (values[i].atom != None0L)
7
Assuming field 'atom' is not equal to None
8
Taking true branch
1053 tasks[i] = get_task (display, xwindow,
1054 values[i].atom, values[i].required_type);
1055
1056 ++i;
1057 }
1058
1059 /* Get replies for all our tasks */
1060 meta_topicmeta_topic_real (META_DEBUG_SYNC, "Syncing to get %d GetProperty replies in %s\n",
1061 n_values, G_STRFUNC((const char*) (__func__)));
1062 XSync (display->xdisplay, False0);
1063
1064 /* Collect results, should arrive in order requested */
1065 i = 0;
1066 while (i < n_values)
11
Loop condition is true. Entering loop body
1067 {
1068 AgGetPropertyTask *task;
1069 GetPropertyResults results;
1070
1071 if (tasks[i] == NULL((void*)0))
12
Assuming the condition is false
13
Taking false branch
1072 {
1073 /* Probably values[i].type was None, or ag_task_create()
1074 * returned NULL.
1075 */
1076 values[i].type = META_PROP_VALUE_INVALID;
1077 goto next;
1078 }
1079
1080 task = ag_get_next_completed_task (display->xdisplay);
1081 g_assert (task != NULL)do { if (task != ((void*)0)) ; else g_assertion_message_expr (
"marco", "core/xprops.c", 1081, ((const char*) (__func__)), "task != NULL"
); } while (0)
;
14
Assuming 'task' is not equal to null
15
Taking true branch
16
Loop condition is false. Exiting loop
1082 g_assert (ag_task_have_reply (task))do { if (ag_task_have_reply (task)) ; else g_assertion_message_expr
("marco", "core/xprops.c", 1082, ((const char*) (__func__)),
"ag_task_have_reply (task)"); } while (0)
;
17
Assuming the condition is true
18
Taking true branch
19
Loop condition is false. Exiting loop
1083
1084 results.display = display;
1085 results.xwindow = xwindow;
1086 results.xatom = values[i].atom;
1087 results.prop = NULL((void*)0);
1088 results.n_items = 0;
1089 results.type = None0L;
1090 results.bytes_after = 0;
1091 results.format = 0;
1092
1093 if (ag_task_get_reply_and_free (task,
20
Assuming the condition is false
22
Taking false branch
1094 &results.type, &results.format,
1095 &results.n_items,
1096 &results.bytes_after,
1097 &results.prop) != Success0 ||
1098 results.type == None0L)
21
Assuming field 'type' is not equal to None
1099 {
1100 values[i].type = META_PROP_VALUE_INVALID;
1101 if (results.prop)
1102 {
1103 XFree (results.prop);
1104 results.prop = NULL((void*)0);
1105 }
1106 goto next;
1107 }
1108
1109 switch (values[i].type)
23
Control jumps to 'case META_PROP_VALUE_UTF8_LIST:' at line 1114
1110 {
1111 case META_PROP_VALUE_INVALID:
1112 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/xprops.c", 1112
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1113 break;
1114 case META_PROP_VALUE_UTF8_LIST:
1115 if (!utf8_list_from_results (&results,
24
Calling 'utf8_list_from_results'
1116 &values[i].v.string_list.strings,
1117 &values[i].v.string_list.n_strings))
1118 values[i].type = META_PROP_VALUE_INVALID;
1119 break;
1120 case META_PROP_VALUE_UTF8:
1121 if (!utf8_string_from_results (&results,
1122 &values[i].v.str))
1123 values[i].type = META_PROP_VALUE_INVALID;
1124 break;
1125 case META_PROP_VALUE_STRING:
1126 if (!latin1_string_from_results (&results,
1127 &values[i].v.str))
1128 values[i].type = META_PROP_VALUE_INVALID;
1129 break;
1130 case META_PROP_VALUE_STRING_AS_UTF8:
1131 if (!latin1_string_from_results (&results,
1132 &values[i].v.str))
1133 values[i].type = META_PROP_VALUE_INVALID;
1134 else
1135 {
1136 char *new_str;
1137 char *xmalloc_new_str;
1138
1139 new_str = latin1_to_utf8 (values[i].v.str);
1140 xmalloc_new_str = ag_Xmalloc (strlen (new_str) + 1);
1141 if (xmalloc_new_str != NULL((void*)0))
1142 {
1143 g_strlcpy (xmalloc_new_str, new_str, (strlen (new_str) + 1));
1144 meta_XFree (values[i].v.str)do { if ((values[i].v.str)) XFree ((values[i].v.str)); } while
(0)
;
1145 values[i].v.str = xmalloc_new_str;
1146 }
1147
1148 g_free (new_str);
1149 }
1150 break;
1151 case META_PROP_VALUE_MOTIF_HINTS:
1152 if (!motif_hints_from_results (&results,
1153 &values[i].v.motif_hints))
1154 values[i].type = META_PROP_VALUE_INVALID;
1155 break;
1156 case META_PROP_VALUE_CARDINAL_LIST:
1157 if (!cardinal_list_from_results (&results,
1158 &values[i].v.cardinal_list.cardinals,
1159 &values[i].v.cardinal_list.n_cardinals))
1160 values[i].type = META_PROP_VALUE_INVALID;
1161 break;
1162 case META_PROP_VALUE_CARDINAL:
1163 if (!cardinal_with_atom_type_from_results (&results,
1164 values[i].required_type,
1165 &values[i].v.cardinal))
1166 values[i].type = META_PROP_VALUE_INVALID;
1167 break;
1168 case META_PROP_VALUE_WINDOW:
1169 if (!window_from_results (&results,
1170 &values[i].v.xwindow))
1171 values[i].type = META_PROP_VALUE_INVALID;
1172 break;
1173 case META_PROP_VALUE_ATOM_LIST:
1174 if (!atom_list_from_results (&results,
1175 &values[i].v.atom_list.atoms,
1176 &values[i].v.atom_list.n_atoms))
1177 values[i].type = META_PROP_VALUE_INVALID;
1178 break;
1179 case META_PROP_VALUE_TEXT_PROPERTY:
1180 if (!text_property_from_results (&results, &values[i].v.str))
1181 values[i].type = META_PROP_VALUE_INVALID;
1182 break;
1183 case META_PROP_VALUE_WM_HINTS:
1184 if (!wm_hints_from_results (&results, &values[i].v.wm_hints))
1185 values[i].type = META_PROP_VALUE_INVALID;
1186 break;
1187 case META_PROP_VALUE_CLASS_HINT:
1188 if (!class_hint_from_results (&results, &values[i].v.class_hint))
1189 values[i].type = META_PROP_VALUE_INVALID;
1190 break;
1191 case META_PROP_VALUE_SIZE_HINTS:
1192 if (!size_hints_from_results (&results,
1193 &values[i].v.size_hints.hints,
1194 &values[i].v.size_hints.flags))
1195 values[i].type = META_PROP_VALUE_INVALID;
1196 break;
1197 case META_PROP_VALUE_SYNC_COUNTER:
1198#ifdef HAVE_XSYNC
1199 if (!counter_from_results (&results,
1200 &values[i].v.xcounter))
1201 values[i].type = META_PROP_VALUE_INVALID;
1202#else
1203 values[i].type = META_PROP_VALUE_INVALID;
1204 if (results.prop)
1205 {
1206 XFree (results.prop);
1207 results.prop = NULL((void*)0);
1208 }
1209#endif
1210 break;
1211 }
1212
1213 next:
1214 ++i;
1215 }
1216
1217 g_free (tasks);
1218}
1219
1220static void
1221free_value (MetaPropValue *value)
1222{
1223 switch (value->type)
1224 {
1225 case META_PROP_VALUE_INVALID:
1226 break;
1227 case META_PROP_VALUE_UTF8:
1228 case META_PROP_VALUE_STRING:
1229 case META_PROP_VALUE_STRING_AS_UTF8:
1230 meta_XFree (value->v.str)do { if ((value->v.str)) XFree ((value->v.str)); } while
(0)
;
1231 break;
1232 case META_PROP_VALUE_MOTIF_HINTS:
1233 meta_XFree (value->v.motif_hints)do { if ((value->v.motif_hints)) XFree ((value->v.motif_hints
)); } while (0)
;
1234 break;
1235 case META_PROP_VALUE_CARDINAL:
1236 break;
1237 case META_PROP_VALUE_WINDOW:
1238 break;
1239 case META_PROP_VALUE_ATOM_LIST:
1240 meta_XFree (value->v.atom_list.atoms)do { if ((value->v.atom_list.atoms)) XFree ((value->v.atom_list
.atoms)); } while (0)
;
1241 break;
1242 case META_PROP_VALUE_TEXT_PROPERTY:
1243 meta_XFree (value->v.str)do { if ((value->v.str)) XFree ((value->v.str)); } while
(0)
;
1244 break;
1245 case META_PROP_VALUE_WM_HINTS:
1246 meta_XFree (value->v.wm_hints)do { if ((value->v.wm_hints)) XFree ((value->v.wm_hints
)); } while (0)
;
1247 break;
1248 case META_PROP_VALUE_CLASS_HINT:
1249 meta_XFree (value->v.class_hint.res_class)do { if ((value->v.class_hint.res_class)) XFree ((value->
v.class_hint.res_class)); } while (0)
;
1250 meta_XFree (value->v.class_hint.res_name)do { if ((value->v.class_hint.res_name)) XFree ((value->
v.class_hint.res_name)); } while (0)
;
1251 break;
1252 case META_PROP_VALUE_SIZE_HINTS:
1253 meta_XFree (value->v.size_hints.hints)do { if ((value->v.size_hints.hints)) XFree ((value->v.
size_hints.hints)); } while (0)
;
1254 break;
1255 case META_PROP_VALUE_UTF8_LIST:
1256 g_strfreev (value->v.string_list.strings);
1257 break;
1258 case META_PROP_VALUE_CARDINAL_LIST:
1259 meta_XFree (value->v.cardinal_list.cardinals)do { if ((value->v.cardinal_list.cardinals)) XFree ((value
->v.cardinal_list.cardinals)); } while (0)
;
1260 break;
1261 case META_PROP_VALUE_SYNC_COUNTER:
1262 break;
1263 }
1264}
1265
1266void
1267meta_prop_free_values (MetaPropValue *values,
1268 int n_values)
1269{
1270 int i;
1271
1272 i = 0;
1273 while (i < n_values)
1274 {
1275 free_value (&values[i]);
1276 ++i;
1277 }
1278
1279 /* Zero the whole thing to quickly detect breakage */
1280 memset (values, '\0', sizeof (MetaPropValue) * n_values);
1281}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-857384.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-857384.html new file mode 100644 index 00000000..f98111cd --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-857384.html @@ -0,0 +1,8010 @@ + + + +ui/theme.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme.c
Warning:line 3174, column 8
Cast a region whose size is not a multiple of the destination type size
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco Theme Rendering */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24/**
25 * \file theme.c Making Marco look pretty
26 *
27 * The window decorations drawn by Marco are described by files on disk
28 * known internally as "themes" (externally as "window border themes" on
29 * http://art.gnome.org/themes/marco/ or "Marco themes"). This file
30 * contains most of the code necessary to support themes; it does not
31 * contain the XML parser, which is in theme-parser.c.
32 *
33 * \bug This is a big file with lots of different subsystems, which might
34 * be better split out into separate files.
35 */
36
37/**
38 * \defgroup tokenizer The theme expression tokenizer
39 *
40 * Themes can use a simple expression language to represent the values of
41 * things. This is the tokeniser used for that language.
42 *
43 * \bug We could remove almost all this code by using GScanner instead,
44 * but we would also have to find every expression in every existing theme
45 * we could and make sure the parse trees were the same.
46 */
47
48/**
49 * \defgroup parser The theme expression parser
50 *
51 * Themes can use a simple expression language to represent the values of
52 * things. This is the parser used for that language.
53 */
54
55#include <config.h>
56#include <glib/gi18n-lib.h>
57
58#include "prefs.h"
59#include "theme.h"
60#include "theme-parser.h"
61#include "util.h"
62#include "gradient.h"
63#include <gtk/gtk.h>
64#include <string.h>
65#include <stdlib.h>
66#define __USE_XOPEN
67#include <math.h>
68
69#define GDK_COLOR_RGBA(color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
\
70 ((guint32) (0xff | \
71 ((int)((color).red * 255) << 24) | \
72 ((int)((color).green * 255) << 16) | \
73 ((int)((color).blue * 255) << 8)))
74
75#define GDK_COLOR_RGB(color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
\
76 ((guint32) (((int)((color).red * 255) << 16) | \
77 ((int)((color).green * 255) << 8) | \
78 ((int)((color).blue * 255))))
79
80#define DEBUG_FILL_STRUCT(s)memset ((s), 0xef, sizeof (*(s))) memset ((s), 0xef, sizeof (*(s)))
81#define CLAMP_UCHAR(v)((guchar) ((((((int)v)) > ((int)255)) ? ((int)255) : (((((
int)v)) < ((int)0)) ? ((int)0) : (((int)v))))))
((guchar) (CLAMP (((int)v), (int)0, (int)255)(((((int)v)) > ((int)255)) ? ((int)255) : (((((int)v)) <
((int)0)) ? ((int)0) : (((int)v))))
))
82#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
83
84static void gtk_style_shade (GdkRGBA *a,
85 GdkRGBA *b,
86 gdouble k);
87static void rgb_to_hls (gdouble *r,
88 gdouble *g,
89 gdouble *b);
90static void hls_to_rgb (gdouble *h,
91 gdouble *l,
92 gdouble *s);
93
94/**
95 * The current theme. (Themes are singleton.)
96 */
97static MetaTheme *meta_current_theme = NULL((void*)0);
98
99static cairo_surface_t *
100scale_surface (cairo_surface_t *surface,
101 gdouble old_width,
102 gdouble old_height,
103 gdouble new_width,
104 gdouble new_height,
105 gboolean vertical_stripes,
106 gboolean horizontal_stripes)
107{
108 gdouble scale_x;
109 gdouble scale_y;
110 cairo_content_t content;
111 gdouble width;
112 gdouble height;
113 cairo_surface_t *scaled;
114 cairo_t *cr;
115
116 scale_x = new_width / old_width;
117 scale_y = new_height / old_height;
118
119 if (horizontal_stripes && !vertical_stripes)
120 {
121 new_width = old_width;
122 scale_x = 1.0;
123 }
124 else if (vertical_stripes && !horizontal_stripes)
125 {
126 new_height = old_height;
127 scale_y = 1.0;
128 }
129
130 content = CAIRO_CONTENT_COLOR_ALPHA;
131 width = ceil (new_width);
132 height = ceil (new_height);
133
134 scaled = cairo_surface_create_similar (surface, content, (int) width, (int) height);
135 cr = cairo_create (scaled);
136
137 cairo_scale (cr, scale_x, scale_y);
138 cairo_set_source_surface (cr, surface, 0, 0);
139
140 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
141
142 cairo_paint (cr);
143 cairo_destroy (cr);
144
145 return scaled;
146}
147
148static cairo_surface_t *
149get_surface_from_pixbuf (GdkPixbuf *pixbuf,
150 MetaImageFillType fill_type,
151 gdouble width,
152 gdouble height,
153 gboolean vertical_stripes,
154 gboolean horizontal_stripes)
155{
156 gdouble pixbuf_width;
157 gdouble pixbuf_height;
158 cairo_surface_t *surface;
159 cairo_content_t content;
160 cairo_surface_t *copy;
161 cairo_t *cr;
162
163 pixbuf_width = gdk_pixbuf_get_width (pixbuf);
164 pixbuf_height = gdk_pixbuf_get_height (pixbuf);
165 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL((void*)0));
166
167 if (pixbuf_width == width && pixbuf_height == height)
168 {
169 return surface;
170 }
171
172 if (fill_type != META_IMAGE_FILL_TILE)
173 {
174 cairo_surface_t *scaled;
175
176 scaled = scale_surface (surface, pixbuf_width, pixbuf_height,
177 width, height, vertical_stripes,
178 horizontal_stripes);
179
180 cairo_surface_destroy (surface);
181 surface = scaled;
182 }
183
184 content = CAIRO_CONTENT_COLOR_ALPHA;
185 width = ceil (width);
186 height = ceil (height);
187
188 copy = cairo_surface_create_similar (surface, content, (int) width, (int) height);
189 cr = cairo_create (copy);
190
191 cairo_set_source_surface (cr, surface, 0, 0);
192
193 if (fill_type == META_IMAGE_FILL_TILE ||
194 vertical_stripes || horizontal_stripes)
195 {
196 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
197 }
198
199 cairo_paint (cr);
200 cairo_destroy (cr);
201
202 cairo_surface_destroy (surface);
203
204 return copy;
205}
206
207static GdkPixbuf *
208colorize_pixbuf (GdkPixbuf *orig,
209 GdkRGBA *new_color)
210{
211 GdkPixbuf *pixbuf;
212 double intensity;
213 int x, y;
214 const guchar *src;
215 guchar *dest;
216 int orig_rowstride;
217 int dest_rowstride;
218 int width, height;
219 gboolean has_alpha;
220 const guchar *src_pixels;
221 guchar *dest_pixels;
222
223 pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
224 gdk_pixbuf_get_bits_per_sample (orig),
225 gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
226
227 if (pixbuf == NULL((void*)0))
228 return NULL((void*)0);
229
230 orig_rowstride = gdk_pixbuf_get_rowstride (orig);
231 dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
232 width = gdk_pixbuf_get_width (pixbuf);
233 height = gdk_pixbuf_get_height (pixbuf);
234 has_alpha = gdk_pixbuf_get_has_alpha (orig);
235 src_pixels = gdk_pixbuf_get_pixels (orig);
236 dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
237
238 for (y = 0; y < height; y++)
239 {
240 src = src_pixels + y * orig_rowstride;
241 dest = dest_pixels + y * dest_rowstride;
242
243 for (x = 0; x < width; x++)
244 {
245 double dr, dg, db;
246
247 intensity = INTENSITY (src[0], src[1], src[2])((src[0]) * 0.30 + (src[1]) * 0.59 + (src[2]) * 0.11) / 255.0;
248
249 if (intensity <= 0.5)
250 {
251 /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
252 dr = new_color->red * intensity * 2.0;
253 dg = new_color->green * intensity * 2.0;
254 db = new_color->blue * intensity * 2.0;
255 }
256 else
257 {
258 /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
259 dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
260 dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
261 db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
262 }
263
264 dest[0] = CLAMP_UCHAR (255 * dr)((guchar) ((((((int)255 * dr)) > ((int)255)) ? ((int)255) :
(((((int)255 * dr)) < ((int)0)) ? ((int)0) : (((int)255 *
dr))))))
;
265 dest[1] = CLAMP_UCHAR (255 * dg)((guchar) ((((((int)255 * dg)) > ((int)255)) ? ((int)255) :
(((((int)255 * dg)) < ((int)0)) ? ((int)0) : (((int)255 *
dg))))))
;
266 dest[2] = CLAMP_UCHAR (255 * db)((guchar) ((((((int)255 * db)) > ((int)255)) ? ((int)255) :
(((((int)255 * db)) < ((int)0)) ? ((int)0) : (((int)255 *
db))))))
;
267
268 if (has_alpha)
269 {
270 dest[3] = src[3];
271 src += 4;
272 dest += 4;
273 }
274 else
275 {
276 src += 3;
277 dest += 3;
278 }
279 }
280 }
281
282 return pixbuf;
283}
284
285static void
286color_composite (const GdkRGBA *bg,
287 const GdkRGBA *fg,
288 double alpha,
289 GdkRGBA *color)
290{
291 *color = *bg;
292 color->red = color->red + (fg->red - color->red) * alpha;
293 color->green = color->green + (fg->green - color->green) * alpha;
294 color->blue = color->blue + (fg->blue - color->blue) * alpha;
295}
296
297/**
298 * Sets all the fields of a border to dummy values.
299 *
300 * \param border The border whose fields should be reset.
301 */
302static void
303init_border (GtkBorder *border)
304{
305 border->top = -1;
306 border->bottom = -1;
307 border->left = -1;
308 border->right = -1;
309}
310
311/**
312 * Creates a new, empty MetaFrameLayout. The fields will be set to dummy
313 * values.
314 *
315 * \return The newly created MetaFrameLayout.
316 */
317MetaFrameLayout*
318meta_frame_layout_new (void)
319{
320 MetaFrameLayout *layout;
321
322 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
323
324 layout->refcount = 1;
325
326 /* Fill with -1 values to detect invalid themes */
327 layout->left_width = -1;
328 layout->right_width = -1;
329 layout->bottom_height = -1;
330
331 layout->invisible_border.left = 10;
332 layout->invisible_border.right = 10;
333 layout->invisible_border.bottom = 10;
334 layout->invisible_border.top = 10;
335
336 init_border (&layout->title_border);
337
338 layout->title_vertical_pad = -1;
339
340 layout->right_titlebar_edge = -1;
341 layout->left_titlebar_edge = -1;
342
343 layout->button_sizing = META_BUTTON_SIZING_LAST;
344 layout->button_aspect = 1.0;
345 layout->button_width = -1;
346 layout->button_height = -1;
347
348 layout->has_title = TRUE(!(0));
349 layout->title_scale = 1.0;
350
351 init_border (&layout->button_border);
352
353 return layout;
354}
355
356/**
357 *
358 */
359static gboolean
360validate_border (const GtkBorder *border,
361 const char **bad)
362{
363 *bad = NULL((void*)0);
364
365 if (border->top < 0)
366 *bad = _("top")((char *) g_dgettext ("marco", "top"));
367 else if (border->bottom < 0)
368 *bad = _("bottom")((char *) g_dgettext ("marco", "bottom"));
369 else if (border->left < 0)
370 *bad = _("left")((char *) g_dgettext ("marco", "left"));
371 else if (border->right < 0)
372 *bad = _("right")((char *) g_dgettext ("marco", "right"));
373
374 return *bad == NULL((void*)0);
375}
376
377/**
378 * Ensures that the theme supplied a particular dimension. When a
379 * MetaFrameLayout is created, all its integer fields are set to -1
380 * by meta_frame_layout_new(). After an instance of this type
381 * should have been initialised, this function checks that
382 * a given field is not still at -1. It is never called directly, but
383 * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER
384 * macros.
385 *
386 * \param val The value to check
387 * \param name The name to use in the error message
388 * \param[out] error Set to an error if val was not initialised
389 */
390static gboolean
391validate_geometry_value (int val,
392 const char *name,
393 GError **error)
394{
395 if (val < 0)
396 {
397 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
398 META_THEME_ERROR_FRAME_GEOMETRY,
399 _("frame geometry does not specify \"%s\" dimension")((char *) g_dgettext ("marco", "frame geometry does not specify \"%s\" dimension"
))
,
400 name);
401 return FALSE(0);
402 }
403 else
404 return TRUE(!(0));
405}
406
407static gboolean
408validate_geometry_border (const GtkBorder *border,
409 const char *name,
410 GError **error)
411{
412 const char *bad;
413
414 if (!validate_border (border, &bad))
415 {
416 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
417 META_THEME_ERROR_FRAME_GEOMETRY,
418 _("frame geometry does not specify dimension \"%s\" for border \"%s\"")((char *) g_dgettext ("marco", "frame geometry does not specify dimension \"%s\" for border \"%s\""
))
,
419 bad, name);
420 return FALSE(0);
421 }
422 else
423 return TRUE(!(0));
424}
425
426gboolean
427meta_frame_layout_validate (const MetaFrameLayout *layout,
428 GError **error)
429{
430 g_return_val_if_fail (layout != NULL, FALSE)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
((0)); } } while (0)
;
431
432#define CHECK_GEOMETRY_VALUE(vname)if (!validate_geometry_value (layout->vname, "vname", error
)) return (0)
if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE(0)
433
434#define CHECK_GEOMETRY_BORDER(bname)if (!validate_geometry_border (&layout->bname, "bname"
, error)) return (0)
if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE(0)
435
436 CHECK_GEOMETRY_VALUE (left_width)if (!validate_geometry_value (layout->left_width, "left_width"
, error)) return (0)
;
437 CHECK_GEOMETRY_VALUE (right_width)if (!validate_geometry_value (layout->right_width, "right_width"
, error)) return (0)
;
438 CHECK_GEOMETRY_VALUE (bottom_height)if (!validate_geometry_value (layout->bottom_height, "bottom_height"
, error)) return (0)
;
439
440 CHECK_GEOMETRY_BORDER (title_border)if (!validate_geometry_border (&layout->title_border, "title_border"
, error)) return (0)
;
441
442 CHECK_GEOMETRY_VALUE (title_vertical_pad)if (!validate_geometry_value (layout->title_vertical_pad, "title_vertical_pad"
, error)) return (0)
;
443
444 CHECK_GEOMETRY_VALUE (right_titlebar_edge)if (!validate_geometry_value (layout->right_titlebar_edge,
"right_titlebar_edge", error)) return (0)
;
445 CHECK_GEOMETRY_VALUE (left_titlebar_edge)if (!validate_geometry_value (layout->left_titlebar_edge, "left_titlebar_edge"
, error)) return (0)
;
446
447 switch (layout->button_sizing)
448 {
449 case META_BUTTON_SIZING_ASPECT:
450 if (layout->button_aspect < (0.1) ||
451 layout->button_aspect > (15.0))
452 {
453 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
454 META_THEME_ERROR_FRAME_GEOMETRY,
455 _("Button aspect ratio %g is not reasonable")((char *) g_dgettext ("marco", "Button aspect ratio %g is not reasonable"
))
,
456 layout->button_aspect);
457 return FALSE(0);
458 }
459 break;
460 case META_BUTTON_SIZING_FIXED:
461 CHECK_GEOMETRY_VALUE (button_width)if (!validate_geometry_value (layout->button_width, "button_width"
, error)) return (0)
;
462 CHECK_GEOMETRY_VALUE (button_height)if (!validate_geometry_value (layout->button_height, "button_height"
, error)) return (0)
;
463 break;
464 case META_BUTTON_SIZING_LAST:
465 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
466 META_THEME_ERROR_FRAME_GEOMETRY,
467 _("Frame geometry does not specify size of buttons")((char *) g_dgettext ("marco", "Frame geometry does not specify size of buttons"
))
);
468 return FALSE(0);
469 }
470
471 CHECK_GEOMETRY_BORDER (button_border)if (!validate_geometry_border (&layout->button_border,
"button_border", error)) return (0)
;
472
473 return TRUE(!(0));
474}
475
476MetaFrameLayout*
477meta_frame_layout_copy (const MetaFrameLayout *src)
478{
479 MetaFrameLayout *layout;
480
481 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
482
483 *layout = *src;
484
485 layout->refcount = 1;
486
487 return layout;
488}
489
490void
491meta_frame_layout_ref (MetaFrameLayout *layout)
492{
493 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
494
495 layout->refcount += 1;
496}
497
498void
499meta_frame_layout_unref (MetaFrameLayout *layout)
500{
501 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
502 g_return_if_fail (layout->refcount > 0)do { if ((layout->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout->refcount > 0"
); return; } } while (0)
;
503
504 layout->refcount -= 1;
505
506 if (layout->refcount == 0)
507 {
508 DEBUG_FILL_STRUCT (layout)memset ((layout), 0xef, sizeof (*(layout)));
509 g_free (layout);
510 }
511}
512
513void
514meta_frame_layout_get_borders (const MetaFrameLayout *layout,
515 int text_height,
516 MetaFrameFlags flags,
517 MetaFrameBorders *borders)
518{
519 int buttons_height, title_height;
520
521 meta_frame_borders_clear (borders);
522
523 /* For a full-screen window, we don't have any borders, visible or not. */
524 if (flags & META_FRAME_FULLSCREEN)
525 return;
526
527 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
528
529 if (!layout->has_title)
530 text_height = 0;
531
532 buttons_height = layout->button_height +
533 layout->button_border.top + layout->button_border.bottom;
534 title_height = text_height +
535 layout->title_vertical_pad +
536 layout->title_border.top + layout->title_border.bottom;
537
538 borders->visible.top = MAX (buttons_height, title_height)(((buttons_height) > (title_height)) ? (buttons_height) : (
title_height))
;
539 borders->visible.left = layout->left_width;
540 borders->visible.right = layout->right_width;
541 borders->visible.bottom = layout->bottom_height;
542
543 if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
544 {
545 borders->invisible.left = layout->invisible_border.left;
546 borders->invisible.right = layout->invisible_border.right;
547 }
548
549 if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
550 {
551 borders->invisible.bottom = layout->invisible_border.bottom;
552 borders->invisible.top = layout->invisible_border.top;
553 }
554
555 if (flags & META_FRAME_SHADED)
556 borders->visible.bottom = borders->invisible.bottom = 0;
557
558 borders->total.left = borders->invisible.left + borders->visible.left;
559 borders->total.right = borders->invisible.right + borders->visible.right;
560 borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
561 borders->total.top = borders->invisible.top + borders->visible.top;
562}
563
564static MetaButtonType
565map_button_function_to_type (MetaButtonFunction function)
566{
567 switch (function)
568 {
569 case META_BUTTON_FUNCTION_SHADE:
570 return META_BUTTON_TYPE_SHADE;
571 case META_BUTTON_FUNCTION_ABOVE:
572 return META_BUTTON_TYPE_ABOVE;
573 case META_BUTTON_FUNCTION_STICK:
574 return META_BUTTON_TYPE_STICK;
575 case META_BUTTON_FUNCTION_UNSHADE:
576 return META_BUTTON_TYPE_UNSHADE;
577 case META_BUTTON_FUNCTION_UNABOVE:
578 return META_BUTTON_TYPE_UNABOVE;
579 case META_BUTTON_FUNCTION_UNSTICK:
580 return META_BUTTON_TYPE_UNSTICK;
581 case META_BUTTON_FUNCTION_MENU:
582 return META_BUTTON_TYPE_MENU;
583 case META_BUTTON_FUNCTION_APPMENU:
584 return META_BUTTON_TYPE_APPMENU;
585 case META_BUTTON_FUNCTION_MINIMIZE:
586 return META_BUTTON_TYPE_MINIMIZE;
587 case META_BUTTON_FUNCTION_MAXIMIZE:
588 return META_BUTTON_TYPE_MAXIMIZE;
589 case META_BUTTON_FUNCTION_CLOSE:
590 return META_BUTTON_TYPE_CLOSE;
591 case META_BUTTON_FUNCTION_LAST:
592 return META_BUTTON_TYPE_LAST;
593 }
594
595 return META_BUTTON_TYPE_LAST;
596}
597
598static MetaButtonSpace*
599rect_for_function (MetaFrameGeometry *fgeom,
600 MetaFrameFlags flags,
601 MetaButtonFunction function,
602 MetaTheme *theme)
603{
604
605 /* Firstly, check version-specific things. */
606
607 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
608 {
609 switch (function)
610 {
611 case META_BUTTON_FUNCTION_SHADE:
612 if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
613 return &fgeom->shade_rect;
614 else
615 return NULL((void*)0);
616 case META_BUTTON_FUNCTION_ABOVE:
617 if (!(flags & META_FRAME_ABOVE))
618 return &fgeom->above_rect;
619 else
620 return NULL((void*)0);
621 case META_BUTTON_FUNCTION_STICK:
622 if (!(flags & META_FRAME_STUCK))
623 return &fgeom->stick_rect;
624 else
625 return NULL((void*)0);
626 case META_BUTTON_FUNCTION_UNSHADE:
627 if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
628 return &fgeom->unshade_rect;
629 else
630 return NULL((void*)0);
631 case META_BUTTON_FUNCTION_UNABOVE:
632 if (flags & META_FRAME_ABOVE)
633 return &fgeom->unabove_rect;
634 else
635 return NULL((void*)0);
636 case META_BUTTON_FUNCTION_UNSTICK:
637 if (flags & META_FRAME_STUCK)
638 return &fgeom->unstick_rect;
639 default:
640 /* just go on to the next switch block */;
641 }
642 }
643
644 /* now consider the buttons which exist in all versions */
645
646 switch (function)
647 {
648 case META_BUTTON_FUNCTION_MENU:
649 if (flags & META_FRAME_ALLOWS_MENU)
650 return &fgeom->menu_rect;
651 else
652 return NULL((void*)0);
653 case META_BUTTON_FUNCTION_APPMENU:
654 if (flags & META_FRAME_ALLOWS_APPMENU)
655 return &fgeom->appmenu_rect;
656 else
657 return NULL((void*)0);
658 case META_BUTTON_FUNCTION_MINIMIZE:
659 if (flags & META_FRAME_ALLOWS_MINIMIZE)
660 return &fgeom->min_rect;
661 else
662 return NULL((void*)0);
663 case META_BUTTON_FUNCTION_MAXIMIZE:
664 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
665 return &fgeom->max_rect;
666 else
667 return NULL((void*)0);
668 case META_BUTTON_FUNCTION_CLOSE:
669 if (flags & META_FRAME_ALLOWS_DELETE)
670 return &fgeom->close_rect;
671 else
672 return NULL((void*)0);
673 case META_BUTTON_FUNCTION_STICK:
674 case META_BUTTON_FUNCTION_SHADE:
675 case META_BUTTON_FUNCTION_ABOVE:
676 case META_BUTTON_FUNCTION_UNSTICK:
677 case META_BUTTON_FUNCTION_UNSHADE:
678 case META_BUTTON_FUNCTION_UNABOVE:
679 /* we are being asked for a >v1 button which hasn't been handled yet,
680 * so obviously we're not in a theme which supports that version.
681 * therefore, we don't show the button. return NULL and all will
682 * be well.
683 */
684 return NULL((void*)0);
685
686 case META_BUTTON_FUNCTION_LAST:
687 return NULL((void*)0);
688 }
689
690 return NULL((void*)0);
691}
692
693static gboolean
694strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
695 GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
696 int *n_rects,
697 MetaButtonSpace *to_strip)
698{
699 int i;
700
701 i = 0;
702 while (i < *n_rects)
703 {
704 if (func_rects[i] == to_strip)
705 {
706 *n_rects -= 1;
707
708 /* shift the other rects back in the array */
709 while (i < *n_rects)
710 {
711 func_rects[i] = func_rects[i+1];
712 bg_rects[i] = bg_rects[i+1];
713
714 ++i;
715 }
716
717 func_rects[i] = NULL((void*)0);
718 bg_rects[i] = NULL((void*)0);
719
720 return TRUE(!(0));
721 }
722
723 ++i;
724 }
725
726 return FALSE(0); /* did not strip anything */
727}
728
729void
730meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
731 int text_height,
732 MetaFrameFlags flags,
733 int client_width,
734 int client_height,
735 const MetaButtonLayout *button_layout,
736 MetaFrameGeometry *fgeom,
737 MetaTheme *theme)
738{
739 int i, n_left, n_right, n_left_spacers, n_right_spacers;
740 int x;
741 int button_y;
742 int title_right_edge;
743 int width, height;
744 int button_width, button_height;
745 int min_size_for_rounding;
746
747 /* the left/right rects in order; the max # of rects
748 * is the number of button functions
749 */
750 MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
751 MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
752 GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
753 gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
754 GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
755 gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
756
757 MetaFrameBorders borders;
758
759 meta_frame_layout_get_borders (layout, text_height,
760 flags,
761 &borders);
762
763 fgeom->borders = borders;
764
765 width = client_width + borders.total.left + borders.total.right;
766
767 height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
768 borders.total.top + borders.total.bottom;
769
770 fgeom->width = width;
771 fgeom->height = height;
772
773 fgeom->top_titlebar_edge = layout->title_border.top;
774 fgeom->bottom_titlebar_edge = layout->title_border.bottom;
775 fgeom->left_titlebar_edge = layout->left_titlebar_edge;
776 fgeom->right_titlebar_edge = layout->right_titlebar_edge;
777
778 switch (layout->button_sizing)
779 {
780 case META_BUTTON_SIZING_ASPECT:
781 button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
782 button_width = (int) (((double) button_height) / layout->button_aspect);
783 break;
784 case META_BUTTON_SIZING_FIXED:
785 button_width = layout->button_width;
786 button_height = layout->button_height;
787 break;
788 case META_BUTTON_SIZING_LAST:
789 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 789, ((
const char*) (__func__)), ((void*)0)); } while (0)
;
790 default:
791 button_width = -1;
792 button_height = -1;
793 }
794
795 /* FIXME all this code sort of pretends that duplicate buttons
796 * with the same function are allowed, but that breaks the
797 * code in frames.c, so isn't really allowed right now.
798 * Would need left_close_rect, right_close_rect, etc.
799 */
800
801 /* Init all button rects to 0, lame hack */
802 memset (ADDRESS_OF_BUTTON_RECTS (fgeom)(((char*)(fgeom)) + ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
, '\0',
803 LENGTH_OF_BUTTON_RECTS(((glong) __builtin_offsetof(MetaFrameGeometry, right_single_background
)) + sizeof (GdkRectangle) - ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
);
804
805 n_left = 0;
806 n_right = 0;
807 n_left_spacers = 0;
808 n_right_spacers = 0;
809
810 if (!layout->hide_buttons)
811 {
812 /* Try to fill in rects */
813 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
814 {
815 left_func_rects[n_left] = rect_for_function (fgeom, flags,
816 button_layout->left_buttons[i],
817 theme);
818 if (left_func_rects[n_left] != NULL((void*)0))
819 {
820 left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
821 if (button_layout->left_buttons_has_spacer[i])
822 ++n_left_spacers;
823
824 ++n_left;
825 }
826 }
827
828 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
829 {
830 right_func_rects[n_right] = rect_for_function (fgeom, flags,
831 button_layout->right_buttons[i],
832 theme);
833 if (right_func_rects[n_right] != NULL((void*)0))
834 {
835 right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
836 if (button_layout->right_buttons_has_spacer[i])
837 ++n_right_spacers;
838
839 ++n_right;
840 }
841 }
842 }
843
844 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST; i++)
845 {
846 left_bg_rects[i] = NULL((void*)0);
847 right_bg_rects[i] = NULL((void*)0);
848 }
849
850 for (i = 0; i < n_left; i++)
851 {
852 if (n_left == 1)
853 left_bg_rects[i] = &fgeom->left_single_background;
854 else if (i == 0)
855 left_bg_rects[i] = &fgeom->left_left_background;
856 else if (i == (n_left - 1))
857 left_bg_rects[i] = &fgeom->left_right_background;
858 else
859 left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
860 }
861
862 for (i = 0; i < n_right; i++)
863 {
864 if (n_right == 1)
865 right_bg_rects[i] = &fgeom->right_single_background;
866 else if (i == (n_right - 1))
867 right_bg_rects[i] = &fgeom->right_right_background;
868 else if (i == 0)
869 right_bg_rects[i] = &fgeom->right_left_background;
870 else
871 right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
872 }
873
874 /* Be sure buttons fit */
875 while (n_left > 0 || n_right > 0)
876 {
877 int space_used_by_buttons;
878 int space_available;
879
880 space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
881
882 space_used_by_buttons = 0;
883
884 space_used_by_buttons += button_width * n_left;
885 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_left_spacers));
886 space_used_by_buttons += layout->button_border.left * n_left;
887 space_used_by_buttons += layout->button_border.right * n_left;
888
889 space_used_by_buttons += button_width * n_right;
890 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_right_spacers));
891 space_used_by_buttons += layout->button_border.left * n_right;
892 space_used_by_buttons += layout->button_border.right * n_right;
893
894 if (space_used_by_buttons <= space_available)
895 break; /* Everything fits, bail out */
896
897 /* First try to remove separators */
898 if (n_left_spacers > 0)
899 {
900 left_buttons_has_spacer[--n_left_spacers] = FALSE(0);
901 continue;
902 }
903 else if (n_right_spacers > 0)
904 {
905 right_buttons_has_spacer[--n_right_spacers] = FALSE(0);
906 continue;
907 }
908
909 /* Otherwise we need to shave out a button. Shave
910 * above, stick, shade, min, max, close, then menu (menu is most useful);
911 * prefer the default button locations.
912 */
913 if (strip_button (left_func_rects, left_bg_rects,
914 &n_left, &fgeom->above_rect))
915 continue;
916 else if (strip_button (right_func_rects, right_bg_rects,
917 &n_right, &fgeom->above_rect))
918 continue;
919 else if (strip_button (left_func_rects, left_bg_rects,
920 &n_left, &fgeom->stick_rect))
921 continue;
922 else if (strip_button (right_func_rects, right_bg_rects,
923 &n_right, &fgeom->stick_rect))
924 continue;
925 else if (strip_button (left_func_rects, left_bg_rects,
926 &n_left, &fgeom->shade_rect))
927 continue;
928 else if (strip_button (right_func_rects, right_bg_rects,
929 &n_right, &fgeom->shade_rect))
930 continue;
931 else if (strip_button (left_func_rects, left_bg_rects,
932 &n_left, &fgeom->min_rect))
933 continue;
934 else if (strip_button (right_func_rects, right_bg_rects,
935 &n_right, &fgeom->min_rect))
936 continue;
937 else if (strip_button (left_func_rects, left_bg_rects,
938 &n_left, &fgeom->max_rect))
939 continue;
940 else if (strip_button (right_func_rects, right_bg_rects,
941 &n_right, &fgeom->max_rect))
942 continue;
943 else if (strip_button (left_func_rects, left_bg_rects,
944 &n_left, &fgeom->close_rect))
945 continue;
946 else if (strip_button (right_func_rects, right_bg_rects,
947 &n_right, &fgeom->close_rect))
948 continue;
949 else if (strip_button (right_func_rects, right_bg_rects,
950 &n_right, &fgeom->menu_rect))
951 continue;
952 else if (strip_button (left_func_rects, left_bg_rects,
953 &n_left, &fgeom->menu_rect))
954 continue;
955 else if (strip_button (right_func_rects, right_bg_rects,
956 &n_right, &fgeom->appmenu_rect))
957 continue;
958 else if (strip_button (left_func_rects, left_bg_rects,
959 &n_left, &fgeom->appmenu_rect))
960 continue;
961 else
962 {
963 meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
964 n_left, n_right);
965 }
966 }
967
968 /* Save the button layout */
969 fgeom->button_layout = *button_layout;
970 fgeom->n_left_buttons = n_left;
971 fgeom->n_right_buttons = n_right;
972
973 /* center buttons vertically */
974 button_y = (borders.visible.top -
975 (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + borders.invisible.top;
976
977 /* right edge of farthest-right button */
978 x = width - layout->right_titlebar_edge - borders.invisible.right;
979
980 i = n_right - 1;
981 while (i >= 0)
982 {
983 MetaButtonSpace *rect;
984
985 if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
986 break;
987
988 rect = right_func_rects[i];
989 rect->visible.x = x - layout->button_border.right - button_width;
990 if (right_buttons_has_spacer[i])
991 rect->visible.x -= (int) (0.75 * (double) button_width);
992
993 rect->visible.y = button_y;
994 rect->visible.width = button_width;
995 rect->visible.height = button_height;
996
997 if (flags & META_FRAME_MAXIMIZED ||
998 flags & META_FRAME_TILED_LEFT ||
999 flags & META_FRAME_TILED_RIGHT)
1000 {
1001 rect->clickable.x = rect->visible.x;
1002 rect->clickable.y = rect->visible.y;
1003 rect->clickable.width = button_width;
1004 rect->clickable.height = button_height;
1005
1006 if (i == n_right - 1)
1007 rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
1008
1009 }
1010 else
1011 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1012
1013 *(right_bg_rects[i]) = rect->visible;
1014
1015 x = rect->visible.x - layout->button_border.left;
1016
1017 --i;
1018 }
1019
1020 /* save right edge of titlebar for later use */
1021 title_right_edge = x - layout->title_border.right;
1022
1023 /* Now x changes to be position from the left and we go through
1024 * the left-side buttons
1025 */
1026 x = layout->left_titlebar_edge + borders.invisible.left;
1027 for (i = 0; i < n_left; i++)
1028 {
1029 MetaButtonSpace *rect;
1030
1031 rect = left_func_rects[i];
1032
1033 rect->visible.x = x + layout->button_border.left;
1034 rect->visible.y = button_y;
1035 rect->visible.width = button_width;
1036 rect->visible.height = button_height;
1037
1038 if (flags & META_FRAME_MAXIMIZED)
1039 {
1040 rect->clickable.x = rect->visible.x;
1041 rect->clickable.y = rect->visible.y;
1042 rect->clickable.width = button_width;
1043 rect->clickable.height = button_height;
1044 }
1045 else
1046 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1047
1048 x = rect->visible.x + rect->visible.width + layout->button_border.right;
1049 if (left_buttons_has_spacer[i])
1050 x += (int) (0.75 * (double) button_width);
1051
1052 *(left_bg_rects[i]) = rect->visible;
1053 }
1054
1055 /* We always fill as much vertical space as possible with title rect,
1056 * rather than centering it like the buttons
1057 */
1058 fgeom->title_rect.x = x + layout->title_border.left;
1059 fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
1060 fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
1061 fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
1062
1063 /* Nuke title if it won't fit */
1064 if (fgeom->title_rect.width < 0 ||
1065 fgeom->title_rect.height < 0)
1066 {
1067 fgeom->title_rect.width = 0;
1068 fgeom->title_rect.height = 0;
1069 }
1070
1071 if (flags & META_FRAME_SHADED)
1072 min_size_for_rounding = 0;
1073 else
1074 min_size_for_rounding = 5;
1075
1076 fgeom->top_left_corner_rounded_radius = 0;
1077 fgeom->top_right_corner_rounded_radius = 0;
1078 fgeom->bottom_left_corner_rounded_radius = 0;
1079 fgeom->bottom_right_corner_rounded_radius = 0;
1080
1081 if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
1082 fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
1083 if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
1084 fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
1085
1086 if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
1087 fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
1088 if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
1089 fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
1090}
1091
1092MetaGradientSpec*
1093meta_gradient_spec_new (MetaGradientType type)
1094{
1095 MetaGradientSpec *spec;
1096
1097 spec = g_new (MetaGradientSpec, 1)((MetaGradientSpec *) g_malloc_n ((1), sizeof (MetaGradientSpec
)))
;
1098
1099 spec->type = type;
1100 spec->color_specs = NULL((void*)0);
1101
1102 return spec;
1103}
1104
1105static cairo_pattern_t *
1106create_cairo_pattern_from_gradient_spec (const MetaGradientSpec *spec,
1107 const MetaAlphaGradientSpec *alpha_spec,
1108 GtkStyleContext *context)
1109{
1110 gint n_colors;
1111 cairo_pattern_t *pattern;
1112 GSList *tmp;
1113 gint i;
1114
1115 n_colors = g_slist_length (spec->color_specs);
1116 if (n_colors == 0)
1117 return NULL((void*)0);
1118
1119 if (alpha_spec != NULL((void*)0) && alpha_spec->n_alphas != 1)
1120 g_assert (n_colors == alpha_spec->n_alphas)do { if (n_colors == alpha_spec->n_alphas) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1120, ((const char*) (__func__)), "n_colors == alpha_spec->n_alphas"
); } while (0)
;
1121
1122 if (spec->type == META_GRADIENT_HORIZONTAL)
1123 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1124 else if (spec->type == META_GRADIENT_VERTICAL)
1125 pattern = cairo_pattern_create_linear (0, 0, 0, 1);
1126 else if (spec->type == META_GRADIENT_DIAGONAL)
1127 pattern = cairo_pattern_create_linear (0, 0, 1, 1);
1128 else
1129 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1129, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1130
1131 i = 0;
1132 tmp = spec->color_specs;
1133 while (tmp != NULL((void*)0))
1134 {
1135 GdkRGBA color;
1136
1137 meta_color_spec_render (tmp->data, context, &color);
1138
1139 if (alpha_spec != NULL((void*)0))
1140 {
1141 gdouble alpha;
1142
1143 if (alpha_spec->n_alphas == 1)
1144 alpha = alpha_spec->alphas[0] / 255.0;
1145 else
1146 alpha = alpha_spec->alphas[i] / 255.0;
1147
1148 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_colors - 1),
1149 color.red, color.green, color.blue,
1150 alpha);
1151 }
1152 else
1153 cairo_pattern_add_color_stop_rgb (pattern, i / (gfloat) (n_colors - 1),
1154 color.red, color.green, color.blue);
1155
1156 tmp = tmp->next;
1157 ++i;
1158 }
1159
1160 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1161 {
1162 cairo_pattern_destroy (pattern);
1163 return NULL((void*)0);
1164 }
1165
1166 return pattern;
1167}
1168
1169static void
1170free_color_spec (gpointer spec, gpointer user_data)
1171{
1172 meta_color_spec_free (spec);
1173}
1174
1175void
1176meta_gradient_spec_free (MetaGradientSpec *spec)
1177{
1178 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1179
1180 g_slist_foreach (spec->color_specs, free_color_spec, NULL((void*)0));
1181 g_slist_free (spec->color_specs);
1182
1183 DEBUG_FILL_STRUCT (spec)memset ((spec), 0xef, sizeof (*(spec)));
1184 g_free (spec);
1185}
1186
1187void
1188meta_gradient_spec_render (const MetaGradientSpec *spec,
1189 const MetaAlphaGradientSpec *alpha_spec,
1190 cairo_t *cr,
1191 GtkStyleContext *context,
1192 gint x,
1193 gint y,
1194 gint width,
1195 gint height)
1196{
1197 cairo_pattern_t *pattern;
1198
1199 pattern = create_cairo_pattern_from_gradient_spec (spec, alpha_spec, context);
1200 if (pattern == NULL((void*)0))
1201 return;
1202
1203 cairo_save (cr);
1204
1205 cairo_rectangle (cr, x, y, width, height);
1206
1207 cairo_translate (cr, x, y);
1208 cairo_scale (cr, width, height);
1209
1210 cairo_set_source (cr, pattern);
1211 cairo_fill (cr);
1212 cairo_pattern_destroy (pattern);
1213
1214 cairo_restore (cr);
1215}
1216
1217gboolean
1218meta_gradient_spec_validate (MetaGradientSpec *spec,
1219 GError **error)
1220{
1221 g_return_val_if_fail (spec != NULL, FALSE)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
((0)); } } while (0)
;
1222
1223 if (g_slist_length (spec->color_specs) < 2)
1224 {
1225 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1226 META_THEME_ERROR_FAILED,
1227 _("Gradients should have at least two colors")((char *) g_dgettext ("marco", "Gradients should have at least two colors"
))
);
1228 return FALSE(0);
1229 }
1230
1231 return TRUE(!(0));
1232}
1233
1234MetaAlphaGradientSpec*
1235meta_alpha_gradient_spec_new (MetaGradientType type,
1236 int n_alphas)
1237{
1238 MetaAlphaGradientSpec *spec;
1239
1240 g_return_val_if_fail (n_alphas > 0, NULL)do { if ((n_alphas > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_alphas > 0"); return
(((void*)0)); } } while (0)
;
1241
1242 spec = g_new0 (MetaAlphaGradientSpec, 1)((MetaAlphaGradientSpec *) g_malloc0_n ((1), sizeof (MetaAlphaGradientSpec
)))
;
1243
1244 spec->type = type;
1245 spec->alphas = g_new0 (unsigned char, n_alphas)((unsigned char *) g_malloc0_n ((n_alphas), sizeof (unsigned char
)))
;
1246 spec->n_alphas = n_alphas;
1247
1248 return spec;
1249}
1250
1251void
1252meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
1253{
1254 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1255
1256 g_free (spec->alphas);
1257 g_free (spec);
1258}
1259
1260cairo_pattern_t *
1261meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec)
1262{
1263 gint n_alphas;
1264 cairo_pattern_t *pattern;
1265 gint i;
1266
1267 /* Hardcoded in theme-parser.c */
1268 g_assert (spec->type == META_GRADIENT_HORIZONTAL)do { if (spec->type == META_GRADIENT_HORIZONTAL) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1268, ((const char*) (__func__)), "spec->type == META_GRADIENT_HORIZONTAL"
); } while (0)
;
1269
1270 n_alphas = spec->n_alphas;
1271 if (n_alphas == 0)
1272 return NULL((void*)0);
1273
1274 if (n_alphas == 1)
1275 return cairo_pattern_create_rgba (0, 0, 0, spec->alphas[0] / 255.0);
1276
1277 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1278
1279 for (i = 0; i < n_alphas; i++)
1280 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_alphas - 1),
1281 0, 0, 0, spec->alphas[i] / 255.0);
1282
1283 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1284 {
1285 cairo_pattern_destroy (pattern);
1286 return NULL((void*)0);
1287 }
1288
1289 return pattern;
1290}
1291
1292MetaColorSpec*
1293meta_color_spec_new (MetaColorSpecType type)
1294{
1295 MetaColorSpec *spec;
1296 MetaColorSpec dummy;
1297 int size;
1298
1299 size = G_STRUCT_OFFSET (MetaColorSpec, data)((glong) __builtin_offsetof(MetaColorSpec, data));
1300
1301 switch (type)
1302 {
1303 case META_COLOR_SPEC_BASIC:
1304 size += sizeof (dummy.data.basic);
1305 break;
1306
1307 case META_COLOR_SPEC_GTK:
1308 size += sizeof (dummy.data.gtk);
1309 break;
1310
1311 case META_COLOR_SPEC_GTK_CUSTOM:
1312 size += sizeof (dummy.data.gtkcustom);
1313 break;
1314
1315 case META_COLOR_SPEC_BLEND:
1316 size += sizeof (dummy.data.blend);
1317 break;
1318
1319 case META_COLOR_SPEC_SHADE:
1320 size += sizeof (dummy.data.shade);
1321 break;
1322 }
1323
1324 spec = g_malloc0 (size);
1325
1326 spec->type = type;
1327
1328 return spec;
1329}
1330
1331void
1332meta_color_spec_free (MetaColorSpec *spec)
1333{
1334 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1335
1336 switch (spec->type)
1337 {
1338 case META_COLOR_SPEC_BASIC:
1339 DEBUG_FILL_STRUCT (&spec->data.basic)memset ((&spec->data.basic), 0xef, sizeof (*(&spec
->data.basic)))
;
1340 break;
1341
1342 case META_COLOR_SPEC_GTK:
1343 DEBUG_FILL_STRUCT (&spec->data.gtk)memset ((&spec->data.gtk), 0xef, sizeof (*(&spec->
data.gtk)))
;
1344 break;
1345
1346 case META_COLOR_SPEC_GTK_CUSTOM:
1347 if (spec->data.gtkcustom.color_name)
1348 g_free (spec->data.gtkcustom.color_name);
1349 if (spec->data.gtkcustom.fallback)
1350 meta_color_spec_free (spec->data.gtkcustom.fallback);
1351 DEBUG_FILL_STRUCT (&spec->data.gtkcustom)memset ((&spec->data.gtkcustom), 0xef, sizeof (*(&
spec->data.gtkcustom)))
;
1352 break;
1353
1354 case META_COLOR_SPEC_BLEND:
1355 if (spec->data.blend.foreground)
1356 meta_color_spec_free (spec->data.blend.foreground);
1357 if (spec->data.blend.background)
1358 meta_color_spec_free (spec->data.blend.background);
1359 DEBUG_FILL_STRUCT (&spec->data.blend)memset ((&spec->data.blend), 0xef, sizeof (*(&spec
->data.blend)))
;
1360 break;
1361
1362 case META_COLOR_SPEC_SHADE:
1363 if (spec->data.shade.base)
1364 meta_color_spec_free (spec->data.shade.base);
1365 DEBUG_FILL_STRUCT (&spec->data.shade)memset ((&spec->data.shade), 0xef, sizeof (*(&spec
->data.shade)))
;
1366 break;
1367 }
1368
1369 g_free (spec);
1370}
1371
1372MetaColorSpec*
1373meta_color_spec_new_from_string (const char *str,
1374 GError **err)
1375{
1376 MetaColorSpec *spec;
1377
1378 spec = NULL((void*)0);
1379
1380 if (strncmp (str, "gtk:custom", 10) == 0)
1381 {
1382 const char *color_name_start, *fallback_str_start, *end;
1383 char *color_name;
1384 MetaColorSpec *fallback = NULL((void*)0);
1385 static gboolean debug, debug_set = FALSE(0);
1386
1387 if (!debug_set)
1388 {
1389 debug = g_getenv ("MARCO_DISABLE_FALLBACK_COLOR") != NULL((void*)0);
1390 debug_set = TRUE(!(0));
1391 }
1392
1393 if (str[10] != '(')
1394 {
1395 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1396 META_THEME_ERROR_FAILED,
1397 _("GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""
))
,
1398 str);
1399 return NULL((void*)0);
1400 }
1401
1402 color_name_start = str + 11;
1403
1404 fallback_str_start = color_name_start;
1405 while (*fallback_str_start && *fallback_str_start != ',')
1406 {
1407 if (!(g_ascii_isalnum (*fallback_str_start)((g_ascii_table[(guchar) (*fallback_str_start)] & G_ASCII_ALNUM
) != 0)
1408 || *fallback_str_start == '-'
1409 || *fallback_str_start == '_'))
1410 {
1411 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1412 META_THEME_ERROR_FAILED,
1413 _("Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid")((char *) g_dgettext ("marco", "Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid"
))
,
1414 *fallback_str_start);
1415 return NULL((void*)0);
1416 }
1417 fallback_str_start++;
1418 }
1419 fallback_str_start++;
1420
1421 end = strrchr (str, ')');
1422
1423 if (color_name_start == NULL((void*)0) || fallback_str_start == NULL((void*)0) || end == NULL((void*)0))
1424 {
1425 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1426 META_THEME_ERROR_FAILED,
1427 _("Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format"
))
,
1428 str);
1429 return NULL((void*)0);
1430 }
1431
1432 if (!debug)
1433 {
1434 char *fallback_str;
1435 fallback_str = g_strndup (fallback_str_start,
1436 end - fallback_str_start);
1437 fallback = meta_color_spec_new_from_string (fallback_str, err);
1438 g_free (fallback_str);
1439 }
1440 else
1441 {
1442 fallback = meta_color_spec_new_from_string ("pink", err);
1443 }
1444
1445 if (fallback == NULL((void*)0))
1446 return NULL((void*)0);
1447
1448 color_name = g_strndup (color_name_start, fallback_str_start - color_name_start - 1);
1449
1450 spec = meta_color_spec_new (META_COLOR_SPEC_GTK_CUSTOM);
1451 spec->data.gtkcustom.color_name = color_name;
1452 spec->data.gtkcustom.fallback = fallback;
1453 }
1454 else if (strncmp (str, "gtk:", 4) == 0)
1455 {
1456 /* GTK color */
1457 const char *bracket;
1458 const char *end_bracket;
1459 char *tmp;
1460 GtkStateFlags state;
1461 MetaGtkColorComponent component;
1462
1463 bracket = str;
1464 while (*bracket && *bracket != '[')
1465 ++bracket;
1466
1467 if (*bracket == '\0')
1468 {
1469 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1470 META_THEME_ERROR_FAILED,
1471 _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1472 str);
1473 return NULL((void*)0);
1474 }
1475
1476 end_bracket = bracket;
1477 ++end_bracket;
1478 while (*end_bracket && *end_bracket != ']')
1479 ++end_bracket;
1480
1481 if (*end_bracket == '\0')
1482 {
1483 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1484 META_THEME_ERROR_FAILED,
1485 _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1486 str);
1487 return NULL((void*)0);
1488 }
1489
1490 tmp = g_strndup (bracket + 1, end_bracket - bracket - 1);
1491 state = meta_gtk_state_from_string (tmp);
1492 if (((int) state) == -1)
1493 {
1494 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1495 META_THEME_ERROR_FAILED,
1496 _("Did not understand state \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand state \"%s\" in color specification"
))
,
1497 tmp);
1498 g_free (tmp);
1499 return NULL((void*)0);
1500 }
1501 g_free (tmp);
1502
1503 tmp = g_strndup (str + 4, bracket - str - 4);
1504 component = meta_color_component_from_string (tmp);
1505 if (component == META_GTK_COLOR_LAST)
1506 {
1507 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1508 META_THEME_ERROR_FAILED,
1509 _("Did not understand color component \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand color component \"%s\" in color specification"
))
,
1510 tmp);
1511 g_free (tmp);
1512 return NULL((void*)0);
1513 }
1514 g_free (tmp);
1515
1516 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1517 spec->data.gtk.state = state;
1518 spec->data.gtk.component = component;
1519 g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST)do { if (spec->data.gtk.component < META_GTK_COLOR_LAST
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 1519
, ((const char*) (__func__)), "spec->data.gtk.component < META_GTK_COLOR_LAST"
); } while (0)
;
1520 }
1521 else if (strncmp (str, "blend/", 6) == 0)
1522 {
1523 /* blend */
1524 char **split;
1525 double alpha;
1526 char *end;
1527 MetaColorSpec *fg;
1528 MetaColorSpec *bg;
1529
1530 split = g_strsplit (str, "/", 4);
1531
1532 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1533 split[2] == NULL((void*)0) || split[3] == NULL((void*)0))
1534 {
1535 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1536 META_THEME_ERROR_FAILED,
1537 _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"
))
,
1538 str);
1539 g_strfreev (split);
1540 return NULL((void*)0);
1541 }
1542
1543 alpha = g_ascii_strtod (split[3], &end);
1544 if (end == split[3])
1545 {
1546 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1547 META_THEME_ERROR_FAILED,
1548 _("Could not parse alpha value \"%s\" in blended color")((char *) g_dgettext ("marco", "Could not parse alpha value \"%s\" in blended color"
))
,
1549 split[3]);
1550 g_strfreev (split);
1551 return NULL((void*)0);
1552 }
1553
1554 if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6))
1555 {
1556 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1557 META_THEME_ERROR_FAILED,
1558 _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0")((char *) g_dgettext ("marco", "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
))
,
1559 split[3]);
1560 g_strfreev (split);
1561 return NULL((void*)0);
1562 }
1563
1564 fg = NULL((void*)0);
1565 bg = NULL((void*)0);
1566
1567 bg = meta_color_spec_new_from_string (split[1], err);
1568 if (bg == NULL((void*)0))
1569 {
1570 g_strfreev (split);
1571 return NULL((void*)0);
1572 }
1573
1574 fg = meta_color_spec_new_from_string (split[2], err);
1575 if (fg == NULL((void*)0))
1576 {
1577 meta_color_spec_free (bg);
1578 g_strfreev (split);
1579 return NULL((void*)0);
1580 }
1581
1582 g_strfreev (split);
1583
1584 spec = meta_color_spec_new (META_COLOR_SPEC_BLEND);
1585 spec->data.blend.alpha = alpha;
1586 spec->data.blend.background = bg;
1587 spec->data.blend.foreground = fg;
1588 }
1589 else if (strncmp (str, "shade/", 6) == 0)
1590 {
1591 /* shade */
1592 char **split;
1593 double factor;
1594 char *end;
1595 MetaColorSpec *base;
1596
1597 split = g_strsplit (str, "/", 3);
1598
1599 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1600 split[2] == NULL((void*)0))
1601 {
1602 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1603 META_THEME_ERROR_FAILED,
1604 _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
))
,
1605 str);
1606 g_strfreev (split);
1607 return NULL((void*)0);
1608 }
1609
1610 factor = g_ascii_strtod (split[2], &end);
1611 if (end == split[2])
1612 {
1613 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1614 META_THEME_ERROR_FAILED,
1615 _("Could not parse shade factor \"%s\" in shaded color")((char *) g_dgettext ("marco", "Could not parse shade factor \"%s\" in shaded color"
))
,
1616 split[2]);
1617 g_strfreev (split);
1618 return NULL((void*)0);
1619 }
1620
1621 if (factor < (0.0 - 1e6))
1622 {
1623 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1624 META_THEME_ERROR_FAILED,
1625 _("Shade factor \"%s\" in shaded color is negative")((char *) g_dgettext ("marco", "Shade factor \"%s\" in shaded color is negative"
))
,
1626 split[2]);
1627 g_strfreev (split);
1628 return NULL((void*)0);
1629 }
1630
1631 base = NULL((void*)0);
1632
1633 base = meta_color_spec_new_from_string (split[1], err);
1634 if (base == NULL((void*)0))
1635 {
1636 g_strfreev (split);
1637 return NULL((void*)0);
1638 }
1639
1640 g_strfreev (split);
1641
1642 spec = meta_color_spec_new (META_COLOR_SPEC_SHADE);
1643 spec->data.shade.factor = factor;
1644 spec->data.shade.base = base;
1645 }
1646 else
1647 {
1648 spec = meta_color_spec_new (META_COLOR_SPEC_BASIC);
1649
1650 if (!gdk_rgba_parse (&spec->data.basic.color, str))
1651 {
1652 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1653 META_THEME_ERROR_FAILED,
1654 _("Could not parse color \"%s\"")((char *) g_dgettext ("marco", "Could not parse color \"%s\""
))
,
1655 str);
1656 meta_color_spec_free (spec);
1657 return NULL((void*)0);
1658 }
1659 }
1660
1661 g_assert (spec)do { if (spec) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 1661, ((const char*) (__func__)), "spec"); } while (0)
;
1662
1663 return spec;
1664}
1665
1666MetaColorSpec*
1667meta_color_spec_new_gtk (MetaGtkColorComponent component,
1668 GtkStateFlags state)
1669{
1670 MetaColorSpec *spec;
1671
1672 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1673
1674 spec->data.gtk.component = component;
1675 spec->data.gtk.state = state;
1676
1677 return spec;
1678}
1679
1680static void
1681get_background_color_real (GtkStyleContext *context,
1682 GtkStateFlags state,
1683 GdkRGBA *color)
1684{
1685 GdkRGBA *c;
1686
1687 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "color != NULL"); return
; } } while (0)
;
1688 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context)); GType __t = ((gtk_style_context_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "GTK_IS_STYLE_CONTEXT (context)"); return; } }
while (0)
;
1689
1690 gtk_style_context_get (context,
1691 state,
1692 "background-color", &c,
1693 NULL((void*)0));
1694
1695 *color = *c;
1696 gdk_rgba_free (c);
1697}
1698
1699static void
1700get_background_color (GtkStyleContext *context,
1701 GtkStateFlags state,
1702 GdkRGBA *color)
1703{
1704 GdkRGBA empty = { 0.0, 0.0, 0.0, 0.0 };
1705 GdkRGBA rgba;
1706
1707 get_background_color_real (context, state, &rgba);
1708
1709 if (gdk_rgba_equal (&rgba, &empty))
1710 {
1711 GtkWidget *toplevel;
1712 GtkStyleContext *tmp;
1713
1714 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1715 tmp = gtk_widget_get_style_context (toplevel);
1716
1717 get_background_color_real (tmp, state, &rgba);
1718
1719 gtk_widget_destroy (toplevel);
1720 }
1721
1722 *color = rgba;
1723}
1724
1725/* Based on set_color() in gtkstyle.c */
1726#define LIGHTNESS_MULT1.3 1.3
1727#define DARKNESS_MULT0.7 0.7
1728void
1729meta_gtk_style_get_light_color (GtkStyleContext *style,
1730 GtkStateFlags state,
1731 GdkRGBA *color)
1732{
1733 get_background_color (style, state, color);
1734 gtk_style_shade (color, color, LIGHTNESS_MULT1.3);
1735}
1736
1737void
1738meta_gtk_style_get_dark_color (GtkStyleContext *style,
1739 GtkStateFlags state,
1740 GdkRGBA *color)
1741{
1742 get_background_color (style, state, color);
1743 gtk_style_shade (color, color, DARKNESS_MULT0.7);
1744}
1745
1746static void
1747meta_set_color_from_style (GdkRGBA *color,
1748 GtkStyleContext *context,
1749 GtkStateFlags state,
1750 MetaGtkColorComponent component)
1751{
1752 GdkRGBA other;
1753
1754 /* Add background class to context to get the correct colors from the GTK+
1755 theme instead of white text over black background. */
1756 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND"background");
1757
1758 switch (component)
1759 {
1760 case META_GTK_COLOR_BG:
1761 case META_GTK_COLOR_BASE:
1762 get_background_color (context, state, color);
1763 break;
1764 case META_GTK_COLOR_FG:
1765 case META_GTK_COLOR_TEXT:
1766 gtk_style_context_get_color (context, state, color);
1767 break;
1768 case META_GTK_COLOR_TEXT_AA:
1769 gtk_style_context_get_color (context, state, color);
1770 meta_set_color_from_style (&other, context, state, META_GTK_COLOR_BASE);
1771
1772 color->red = (color->red + other.red) / 2;
1773 color->green = (color->green + other.green) / 2;
1774 color->blue = (color->blue + other.blue) / 2;
1775 break;
1776 case META_GTK_COLOR_MID:
1777 meta_gtk_style_get_light_color (context, state, color);
1778 meta_gtk_style_get_dark_color (context, state, &other);
1779
1780 color->red = (color->red + other.red) / 2;
1781 color->green = (color->green + other.green) / 2;
1782 color->blue = (color->blue + other.blue) / 2;
1783 break;
1784 case META_GTK_COLOR_LIGHT:
1785 meta_gtk_style_get_light_color (context, state, color);
1786 break;
1787 case META_GTK_COLOR_DARK:
1788 meta_gtk_style_get_dark_color (context, state, color);
1789 break;
1790 case META_GTK_COLOR_LAST:
1791 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1791, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1792 break;
1793 }
1794}
1795
1796static void
1797meta_set_custom_color_from_style (GdkRGBA *color,
1798 GtkStyleContext *context,
1799 char *color_name,
1800 MetaColorSpec *fallback)
1801{
1802 if (!gtk_style_context_lookup_color (context, color_name, color))
1803 meta_color_spec_render (fallback, context, color);
1804}
1805
1806void
1807meta_color_spec_render (MetaColorSpec *spec,
1808 GtkStyleContext *style,
1809 GdkRGBA *color)
1810{
1811 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1812
1813 g_return_if_fail (GTK_IS_STYLE_CONTEXT (style))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((style)); GType __t = ((gtk_style_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GTK_IS_STYLE_CONTEXT (style)"); return; } } while (0)
;
1814
1815 switch (spec->type)
1816 {
1817 case META_COLOR_SPEC_BASIC:
1818 *color = spec->data.basic.color;
1819 break;
1820
1821 case META_COLOR_SPEC_GTK:
1822 meta_set_color_from_style (color,
1823 style,
1824 spec->data.gtk.state,
1825 spec->data.gtk.component);
1826 break;
1827
1828 case META_COLOR_SPEC_GTK_CUSTOM:
1829 meta_set_custom_color_from_style (color,
1830 style,
1831 spec->data.gtkcustom.color_name,
1832 spec->data.gtkcustom.fallback);
1833 break;
1834
1835 case META_COLOR_SPEC_BLEND:
1836 {
1837 GdkRGBA bg, fg;
1838
1839 meta_color_spec_render (spec->data.blend.background, style, &bg);
1840 meta_color_spec_render (spec->data.blend.foreground, style, &fg);
1841
1842 color_composite (&bg, &fg, spec->data.blend.alpha,
1843 &spec->data.blend.color);
1844
1845 *color = spec->data.blend.color;
1846 }
1847 break;
1848
1849 case META_COLOR_SPEC_SHADE:
1850 {
1851 meta_color_spec_render (spec->data.shade.base, style,
1852 &spec->data.shade.color);
1853
1854 gtk_style_shade (&spec->data.shade.color,
1855 &spec->data.shade.color, spec->data.shade.factor);
1856
1857 *color = spec->data.shade.color;
1858 }
1859 break;
1860 }
1861}
1862
1863/**
1864 * Represents an operation as a string.
1865 *
1866 * \param type an operation, such as addition
1867 * \return a string, such as "+"
1868 */
1869static const char*
1870op_name (PosOperatorType type)
1871{
1872 switch (type)
1873 {
1874 case POS_OP_ADD:
1875 return "+";
1876 case POS_OP_SUBTRACT:
1877 return "-";
1878 case POS_OP_MULTIPLY:
1879 return "*";
1880 case POS_OP_DIVIDE:
1881 return "/";
1882 case POS_OP_MOD:
1883 return "%";
1884 case POS_OP_MAX:
1885 return "`max`";
1886 case POS_OP_MIN:
1887 return "`min`";
1888 case POS_OP_NONE:
1889 break;
1890 }
1891
1892 return "<unknown>";
1893}
1894
1895/**
1896 * Parses a string and returns an operation.
1897 *
1898 * \param p a pointer into a string representing an operation; part of an
1899 * expression somewhere, so not null-terminated
1900 * \param len set to the length of the string found. Set to 0 if none is.
1901 * \return the operation found. If none was, returns POS_OP_NONE.
1902 */
1903static PosOperatorType
1904op_from_string (const char *p,
1905 int *len)
1906{
1907 *len = 0;
1908
1909 switch (*p)
1910 {
1911 case '+':
1912 *len = 1;
1913 return POS_OP_ADD;
1914 case '-':
1915 *len = 1;
1916 return POS_OP_SUBTRACT;
1917 case '*':
1918 *len = 1;
1919 return POS_OP_MULTIPLY;
1920 case '/':
1921 *len = 1;
1922 return POS_OP_DIVIDE;
1923 case '%':
1924 *len = 1;
1925 return POS_OP_MOD;
1926
1927 case '`':
1928 if (strncmp (p, "`max`", 5) == 0)
1929 {
1930 *len = 5;
1931 return POS_OP_MAX;
1932 }
1933 else if (strncmp (p, "`min`", 5) == 0)
1934 {
1935 *len = 5;
1936 return POS_OP_MIN;
1937 }
1938 }
1939
1940 return POS_OP_NONE;
1941}
1942
1943/**
1944 * Frees an array of tokens. All the tokens and their associated memory
1945 * will be freed.
1946 *
1947 * \param tokens an array of tokens to be freed
1948 * \param n_tokens how many tokens are in the array.
1949 */
1950static void
1951free_tokens (PosToken *tokens,
1952 int n_tokens)
1953{
1954 int i;
1955
1956 /* n_tokens can be 0 since tokens may have been allocated more than
1957 * it was initialized
1958 */
1959
1960 for (i = 0; i < n_tokens; i++)
1961 if (tokens[i].type == POS_TOKEN_VARIABLE)
1962 g_free (tokens[i].d.v.name);
1963
1964 g_free (tokens);
1965}
1966
1967/**
1968 * Tokenises a number in an expression.
1969 *
1970 * \param p a pointer into a string representing an operation; part of an
1971 * expression somewhere, so not null-terminated
1972 * \param end_return set to a pointer to the end of the number found; but
1973 * not updated if no number was found at all
1974 * \param next set to either an integer or a float token
1975 * \param[out] err set to the problem if there was a problem
1976 * \return TRUE if a valid number was found, FALSE otherwise (and "err" will
1977 * have been set)
1978 *
1979 * \bug The "while (*start)..." part: what's wrong with strchr-ish things?
1980 * \bug The name is wrong: it doesn't parse anything.
1981 * \ingroup tokenizer
1982 */
1983static gboolean
1984parse_number (const char *p,
1985 const char **end_return,
1986 PosToken *next,
1987 GError **err)
1988{
1989 const char *start = p;
1990 char *end;
1991 gboolean is_float;
1992 char *num_str;
1993
1994 while (*p && (*p == '.' || g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0)))
1995 ++p;
1996
1997 if (p == start)
1998 {
1999 char buf[7] = { '\0' };
2000 buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0';
2001 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2002 META_THEME_ERROR_BAD_CHARACTER,
2003 _("Coordinate expression contains character '%s' which is not allowed")((char *) g_dgettext ("marco", "Coordinate expression contains character '%s' which is not allowed"
))
,
2004 buf);
2005 return FALSE(0);
2006 }
2007
2008 *end_return = p;
2009
2010 /* we need this to exclude floats like "1e6" */
2011 num_str = g_strndup (start, p - start);
2012 start = num_str;
2013 is_float = FALSE(0);
2014 while (*start)
2015 {
2016 if (*start == '.')
2017 is_float = TRUE(!(0));
2018 ++start;
2019 }
2020
2021 if (is_float)
2022 {
2023 next->type = POS_TOKEN_DOUBLE;
2024 next->d.d.val = g_ascii_strtod (num_str, &end);
2025
2026 if (end == num_str)
2027 {
2028 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2029 META_THEME_ERROR_FAILED,
2030 _("Coordinate expression contains floating point number '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains floating point number '%s' which could not be parsed"
))
,
2031 num_str);
2032 g_free (num_str);
2033 return FALSE(0);
2034 }
2035 }
2036 else
2037 {
2038 next->type = POS_TOKEN_INT;
2039 next->d.i.val = strtol (num_str, &end, 10);
2040 if (end == num_str)
2041 {
2042 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2043 META_THEME_ERROR_FAILED,
2044 _("Coordinate expression contains integer '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains integer '%s' which could not be parsed"
))
,
2045 num_str);
2046 g_free (num_str);
2047 return FALSE(0);
2048 }
2049 }
2050
2051 g_free (num_str);
2052
2053 g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE)do { if (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 2053
, ((const char*) (__func__)), "next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE"
); } while (0)
;
2054
2055 return TRUE(!(0));
2056}
2057
2058/**
2059 * Whether a variable can validly appear as part of the name of a variable.
2060 */
2061#define IS_VARIABLE_CHAR(c)(((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) ||
(c) == '_')
(g_ascii_isalpha ((c))((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) || (c) == '_')
2062
2063#if 0
2064static void
2065debug_print_tokens (PosToken *tokens,
2066 int n_tokens)
2067{
2068 int i;
2069
2070 for (i = 0; i < n_tokens; i++)
2071 {
2072 PosToken *t = &tokens[i];
2073
2074 g_print (" ");
2075
2076 switch (t->type)
2077 {
2078 case POS_TOKEN_INT:
2079 g_print ("\"%d\"", t->d.i.val);
2080 break;
2081 case POS_TOKEN_DOUBLE:
2082 g_print ("\"%g\"", t->d.d.val);
2083 break;
2084 case POS_TOKEN_OPEN_PAREN:
2085 g_print ("\"(\"");
2086 break;
2087 case POS_TOKEN_CLOSE_PAREN:
2088 g_print ("\")\"");
2089 break;
2090 case POS_TOKEN_VARIABLE:
2091 g_print ("\"%s\"", t->d.v.name);
2092 break;
2093 case POS_TOKEN_OPERATOR:
2094 g_print ("\"%s\"", op_name (t->d.o.op));
2095 break;
2096 }
2097 }
2098
2099 g_print ("\n");
2100}
2101#endif
2102
2103/**
2104 * Tokenises an expression.
2105 *
2106 * \param expr The expression
2107 * \param[out] tokens_p The resulting tokens
2108 * \param[out] n_tokens_p The number of resulting tokens
2109 * \param[out] err set to the problem if there was a problem
2110 *
2111 * \return True if the expression was successfully tokenised; false otherwise.
2112 *
2113 * \ingroup tokenizer
2114 */
2115static gboolean
2116pos_tokenize (const char *expr,
2117 PosToken **tokens_p,
2118 int *n_tokens_p,
2119 GError **err)
2120{
2121 PosToken *tokens;
2122 int n_tokens;
2123 int allocated;
2124 const char *p;
2125
2126 *tokens_p = NULL((void*)0);
2127 *n_tokens_p = 0;
2128
2129 allocated = 3;
2130 n_tokens = 0;
2131 tokens = g_new (PosToken, allocated)((PosToken *) g_malloc_n ((allocated), sizeof (PosToken)));
2132
2133 p = expr;
2134 while (*p)
2135 {
2136 PosToken *next;
2137 int len;
2138
2139 if (n_tokens == allocated)
2140 {
2141 allocated *= 2;
2142 tokens = g_renew (PosToken, tokens, allocated)((PosToken *) g_realloc_n (tokens, (allocated), sizeof (PosToken
)))
;
2143 }
2144
2145 next = &tokens[n_tokens];
2146
2147 switch (*p)
2148 {
2149 case '*':
2150 case '/':
2151 case '+':
2152 case '-': /* negative numbers aren't allowed so this is easy */
2153 case '%':
2154 case '`':
2155 next->type = POS_TOKEN_OPERATOR;
2156 next->d.o.op = op_from_string (p, &len);
2157 if (next->d.o.op != POS_OP_NONE)
2158 {
2159 ++n_tokens;
2160 p = p + (len - 1); /* -1 since we ++p later */
2161 }
2162 else
2163 {
2164 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2165 META_THEME_ERROR_FAILED,
2166 _("Coordinate expression contained unknown operator at the start of this text: \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression contained unknown operator at the start of this text: \"%s\""
))
,
2167 p);
2168
2169 goto error;
2170 }
2171 break;
2172
2173 case '(':
2174 next->type = POS_TOKEN_OPEN_PAREN;
2175 ++n_tokens;
2176 break;
2177
2178 case ')':
2179 next->type = POS_TOKEN_CLOSE_PAREN;
2180 ++n_tokens;
2181 break;
2182
2183 case ' ':
2184 case '\t':
2185 case '\n':
2186 break;
2187
2188 default:
2189 if (IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2190 {
2191 /* Assume variable */
2192 const char *start = p;
2193 while (*p && IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2194 ++p;
2195 g_assert (p != start)do { if (p != start) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2195, ((const char*) (__func__)), "p != start"
); } while (0)
;
2196 next->type = POS_TOKEN_VARIABLE;
2197 next->d.v.name = g_strndup (start, p - start);
2198 ++n_tokens;
2199 --p; /* since we ++p again at the end of while loop */
2200 }
2201 else
2202 {
2203 /* Assume number */
2204 const char *end;
2205
2206 if (!parse_number (p, &end, next, err))
2207 goto error;
2208
2209 ++n_tokens;
2210 p = end - 1; /* -1 since we ++p again at the end of while loop */
2211 }
2212
2213 break;
2214 }
2215
2216 ++p;
2217 }
2218
2219 if (n_tokens == 0)
2220 {
2221 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2222 META_THEME_ERROR_FAILED,
2223 _("Coordinate expression was empty or not understood")((char *) g_dgettext ("marco", "Coordinate expression was empty or not understood"
))
);
2224
2225 goto error;
2226 }
2227
2228 *tokens_p = tokens;
2229 *n_tokens_p = n_tokens;
2230
2231 return TRUE(!(0));
2232
2233 error:
2234 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2234, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2235
2236 free_tokens (tokens, n_tokens);
2237 return FALSE(0);
2238}
2239
2240/**
2241 * The type of a PosExpr: either integer, double, or an operation.
2242 * \ingroup parser
2243 */
2244typedef enum
2245{
2246 POS_EXPR_INT,
2247 POS_EXPR_DOUBLE,
2248 POS_EXPR_OPERATOR
2249} PosExprType;
2250
2251/**
2252 * Type and value of an expression in a parsed sequence. We don't
2253 * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR,
2254 * the arguments of the operator will be in the array positions
2255 * immediately preceding and following this operator; they cannot
2256 * themselves be operators.
2257 *
2258 * \bug operator is char; it should really be of PosOperatorType.
2259 * \ingroup parser
2260 */
2261typedef struct
2262{
2263 PosExprType type;
2264 union
2265 {
2266 double double_val;
2267 int int_val;
2268 char operator;
2269 } d;
2270} PosExpr;
2271
2272#if 0
2273static void
2274debug_print_exprs (PosExpr *exprs,
2275 int n_exprs)
2276{
2277 int i;
2278
2279 for (i = 0; i < n_exprs; i++)
2280 {
2281 switch (exprs[i].type)
2282 {
2283 case POS_EXPR_INT:
2284 g_print (" %d", exprs[i].d.int_val);
2285 break;
2286 case POS_EXPR_DOUBLE:
2287 g_print (" %g", exprs[i].d.double_val);
2288 break;
2289 case POS_EXPR_OPERATOR:
2290 g_print (" %s", op_name (exprs[i].d.operator));
2291 break;
2292 }
2293 }
2294 g_print ("\n");
2295}
2296#endif
2297
2298static gboolean
2299do_operation (PosExpr *a,
2300 PosExpr *b,
2301 PosOperatorType op,
2302 GError **err)
2303{
2304 /* Promote types to double if required */
2305 if (a->type == POS_EXPR_DOUBLE ||
2306 b->type == POS_EXPR_DOUBLE)
2307 {
2308 if (a->type != POS_EXPR_DOUBLE)
2309 {
2310 a->type = POS_EXPR_DOUBLE;
2311 a->d.double_val = a->d.int_val;
2312 }
2313 if (b->type != POS_EXPR_DOUBLE)
2314 {
2315 b->type = POS_EXPR_DOUBLE;
2316 b->d.double_val = b->d.int_val;
2317 }
2318 }
2319
2320 g_assert (a->type == b->type)do { if (a->type == b->type) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2320, ((const char*) (__func__)), "a->type == b->type"
); } while (0)
;
2321
2322 if (a->type == POS_EXPR_INT)
2323 {
2324 switch (op)
2325 {
2326 case POS_OP_MULTIPLY:
2327 a->d.int_val = a->d.int_val * b->d.int_val;
2328 break;
2329 case POS_OP_DIVIDE:
2330 if (b->d.int_val == 0)
2331 {
2332 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2333 META_THEME_ERROR_DIVIDE_BY_ZERO,
2334 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2335 return FALSE(0);
2336 }
2337 a->d.int_val = a->d.int_val / b->d.int_val;
2338 break;
2339 case POS_OP_MOD:
2340 if (b->d.int_val == 0)
2341 {
2342 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2343 META_THEME_ERROR_DIVIDE_BY_ZERO,
2344 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2345 return FALSE(0);
2346 }
2347 a->d.int_val = a->d.int_val % b->d.int_val;
2348 break;
2349 case POS_OP_ADD:
2350 a->d.int_val = a->d.int_val + b->d.int_val;
2351 break;
2352 case POS_OP_SUBTRACT:
2353 a->d.int_val = a->d.int_val - b->d.int_val;
2354 break;
2355 case POS_OP_MAX:
2356 a->d.int_val = MAX (a->d.int_val, b->d.int_val)(((a->d.int_val) > (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2357 break;
2358 case POS_OP_MIN:
2359 a->d.int_val = MIN (a->d.int_val, b->d.int_val)(((a->d.int_val) < (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2360 break;
2361 case POS_OP_NONE:
2362 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2362, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2363 break;
2364 }
2365 }
2366 else if (a->type == POS_EXPR_DOUBLE)
2367 {
2368 switch (op)
2369 {
2370 case POS_OP_MULTIPLY:
2371 a->d.double_val = a->d.double_val * b->d.double_val;
2372 break;
2373 case POS_OP_DIVIDE:
2374 if (b->d.double_val == 0.0)
2375 {
2376 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2377 META_THEME_ERROR_DIVIDE_BY_ZERO,
2378 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2379 return FALSE(0);
2380 }
2381 a->d.double_val = a->d.double_val / b->d.double_val;
2382 break;
2383 case POS_OP_MOD:
2384 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2385 META_THEME_ERROR_MOD_ON_FLOAT,
2386 _("Coordinate expression tries to use mod operator on a floating-point number")((char *) g_dgettext ("marco", "Coordinate expression tries to use mod operator on a floating-point number"
))
);
2387 return FALSE(0);
2388 case POS_OP_ADD:
2389 a->d.double_val = a->d.double_val + b->d.double_val;
2390 break;
2391 case POS_OP_SUBTRACT:
2392 a->d.double_val = a->d.double_val - b->d.double_val;
2393 break;
2394 case POS_OP_MAX:
2395 a->d.double_val = MAX (a->d.double_val, b->d.double_val)(((a->d.double_val) > (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2396 break;
2397 case POS_OP_MIN:
2398 a->d.double_val = MIN (a->d.double_val, b->d.double_val)(((a->d.double_val) < (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2399 break;
2400 case POS_OP_NONE:
2401 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2401, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2402 break;
2403 }
2404 }
2405 else
2406 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2406, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2407
2408 return TRUE(!(0));
2409}
2410
2411static gboolean
2412do_operations (PosExpr *exprs,
2413 int *n_exprs,
2414 int precedence,
2415 GError **err)
2416{
2417 int i;
2418
2419#if 0
2420 g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs);
2421 debug_print_exprs (exprs, *n_exprs);
2422#endif
2423
2424 i = 1;
2425 while (i < *n_exprs)
2426 {
2427 gboolean compress;
2428
2429 /* exprs[i-1] first operand
2430 * exprs[i] operator
2431 * exprs[i+1] second operand
2432 *
2433 * we replace first operand with result of mul/div/mod,
2434 * or skip over operator and second operand if we have
2435 * an add/subtract
2436 */
2437
2438 if (exprs[i-1].type == POS_EXPR_OPERATOR)
2439 {
2440 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2441 META_THEME_ERROR_FAILED,
2442 _("Coordinate expression has an operator \"%s\" where an operand was expected")((char *) g_dgettext ("marco", "Coordinate expression has an operator \"%s\" where an operand was expected"
))
,
2443 op_name (exprs[i-1].d.operator));
2444 return FALSE(0);
2445 }
2446
2447 if (exprs[i].type != POS_EXPR_OPERATOR)
2448 {
2449 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2450 META_THEME_ERROR_FAILED,
2451 _("Coordinate expression had an operand where an operator was expected")((char *) g_dgettext ("marco", "Coordinate expression had an operand where an operator was expected"
))
);
2452 return FALSE(0);
2453 }
2454
2455 if (i == (*n_exprs - 1))
2456 {
2457 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2458 META_THEME_ERROR_FAILED,
2459 _("Coordinate expression ended with an operator instead of an operand")((char *) g_dgettext ("marco", "Coordinate expression ended with an operator instead of an operand"
))
);
2460 return FALSE(0);
2461 }
2462
2463 g_assert ((i+1) < *n_exprs)do { if ((i+1) < *n_exprs) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2463, ((const char*) (__func__)), "(i+1) < *n_exprs"
); } while (0)
;
2464
2465 if (exprs[i+1].type == POS_EXPR_OPERATOR)
2466 {
2467 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2468 META_THEME_ERROR_FAILED,
2469 _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between")((char *) g_dgettext ("marco", "Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"
))
,
2470 exprs[i+1].d.operator,
2471 exprs[i].d.operator);
2472 return FALSE(0);
2473 }
2474
2475 compress = FALSE(0);
2476
2477 switch (precedence)
2478 {
2479 case 2:
2480 switch (exprs[i].d.operator)
2481 {
2482 case POS_OP_DIVIDE:
2483 case POS_OP_MOD:
2484 case POS_OP_MULTIPLY:
2485 compress = TRUE(!(0));
2486 if (!do_operation (&exprs[i-1], &exprs[i+1],
2487 exprs[i].d.operator,
2488 err))
2489 return FALSE(0);
2490 break;
2491 }
2492 break;
2493 case 1:
2494 switch (exprs[i].d.operator)
2495 {
2496 case POS_OP_ADD:
2497 case POS_OP_SUBTRACT:
2498 compress = TRUE(!(0));
2499 if (!do_operation (&exprs[i-1], &exprs[i+1],
2500 exprs[i].d.operator,
2501 err))
2502 return FALSE(0);
2503 break;
2504 }
2505 break;
2506 /* I have no rationale at all for making these low-precedence */
2507 case 0:
2508 switch (exprs[i].d.operator)
2509 {
2510 case POS_OP_MAX:
2511 case POS_OP_MIN:
2512 compress = TRUE(!(0));
2513 if (!do_operation (&exprs[i-1], &exprs[i+1],
2514 exprs[i].d.operator,
2515 err))
2516 return FALSE(0);
2517 break;
2518 }
2519 break;
2520 }
2521
2522 if (compress)
2523 {
2524 /* exprs[i-1] first operand (now result)
2525 * exprs[i] operator
2526 * exprs[i+1] second operand
2527 * exprs[i+2] new operator
2528 *
2529 * we move new operator just after first operand
2530 */
2531 if ((i+2) < *n_exprs)
2532 {
2533 memmove (&exprs[i], &exprs[i+2],
2534 sizeof (PosExpr) * (*n_exprs - i - 2));
2535 }
2536
2537 *n_exprs -= 2;
2538 }
2539 else
2540 {
2541 /* Skip operator and next operand */
2542 i += 2;
2543 }
2544 }
2545
2546 return TRUE(!(0));
2547}
2548
2549/**
2550 * There is a predefined set of variables which can appear in an expression.
2551 * Here we take a token representing a variable, and return the current value
2552 * of that variable in a particular environment.
2553 * (The value is always an integer.)
2554 *
2555 * There are supposedly some circumstances in which this function can be
2556 * called from outside Marco, in which case env->theme will be NULL, and
2557 * therefore we can't use it to find out quark values, so we do the comparison
2558 * using strcmp, which is slower.
2559 *
2560 * \param t The token representing a variable
2561 * \param[out] result The value of that variable; not set if the token did
2562 * not represent a known variable
2563 * \param env The environment within which t should be evaluated
2564 * \param[out] err set to the problem if there was a problem
2565 *
2566 * \return true if we found the variable asked for, false if we didn't
2567 *
2568 * \bug shouldn't t be const?
2569 * \bug we should perhaps consider some sort of lookup arrangement into an
2570 * array; also, the duplication of code is unlovely; perhaps using glib
2571 * string hashes instead of quarks would fix both problems?
2572 * \ingroup parser
2573 */
2574static gboolean
2575pos_eval_get_variable (PosToken *t,
2576 int *result,
2577 const MetaPositionExprEnv *env,
2578 GError **err)
2579{
2580 if (env->theme)
2581 {
2582 if (t->d.v.name_quark == env->theme->quark_width)
2583 *result = env->rect.width;
2584 else if (t->d.v.name_quark == env->theme->quark_height)
2585 *result = env->rect.height;
2586 else if (env->object_width >= 0 &&
2587 t->d.v.name_quark == env->theme->quark_object_width)
2588 *result = env->object_width;
2589 else if (env->object_height >= 0 &&
2590 t->d.v.name_quark == env->theme->quark_object_height)
2591 *result = env->object_height;
2592 else if (t->d.v.name_quark == env->theme->quark_left_width)
2593 *result = env->left_width;
2594 else if (t->d.v.name_quark == env->theme->quark_right_width)
2595 *result = env->right_width;
2596 else if (t->d.v.name_quark == env->theme->quark_top_height)
2597 *result = env->top_height;
2598 else if (t->d.v.name_quark == env->theme->quark_bottom_height)
2599 *result = env->bottom_height;
2600 else if (t->d.v.name_quark == env->theme->quark_mini_icon_width)
2601 *result = env->mini_icon_width;
2602 else if (t->d.v.name_quark == env->theme->quark_mini_icon_height)
2603 *result = env->mini_icon_height;
2604 else if (t->d.v.name_quark == env->theme->quark_icon_width)
2605 *result = env->icon_width;
2606 else if (t->d.v.name_quark == env->theme->quark_icon_height)
2607 *result = env->icon_height;
2608 else if (t->d.v.name_quark == env->theme->quark_title_width)
2609 *result = env->title_width;
2610 else if (t->d.v.name_quark == env->theme->quark_title_height)
2611 *result = env->title_height;
2612 else if (t->d.v.name_quark == env->theme->quark_frame_x_center)
2613 *result = env->frame_x_center;
2614 else if (t->d.v.name_quark == env->theme->quark_frame_y_center)
2615 *result = env->frame_y_center;
2616 else
2617 {
2618 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2619 META_THEME_ERROR_UNKNOWN_VARIABLE,
2620 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2621 t->d.v.name);
2622 return FALSE(0);
2623 }
2624 }
2625 else
2626 {
2627 if (strcmp (t->d.v.name, "width") == 0)
2628 *result = env->rect.width;
2629 else if (strcmp (t->d.v.name, "height") == 0)
2630 *result = env->rect.height;
2631 else if (env->object_width >= 0 &&
2632 strcmp (t->d.v.name, "object_width") == 0)
2633 *result = env->object_width;
2634 else if (env->object_height >= 0 &&
2635 strcmp (t->d.v.name, "object_height") == 0)
2636 *result = env->object_height;
2637 else if (strcmp (t->d.v.name, "left_width") == 0)
2638 *result = env->left_width;
2639 else if (strcmp (t->d.v.name, "right_width") == 0)
2640 *result = env->right_width;
2641 else if (strcmp (t->d.v.name, "top_height") == 0)
2642 *result = env->top_height;
2643 else if (strcmp (t->d.v.name, "bottom_height") == 0)
2644 *result = env->bottom_height;
2645 else if (strcmp (t->d.v.name, "mini_icon_width") == 0)
2646 *result = env->mini_icon_width;
2647 else if (strcmp (t->d.v.name, "mini_icon_height") == 0)
2648 *result = env->mini_icon_height;
2649 else if (strcmp (t->d.v.name, "icon_width") == 0)
2650 *result = env->icon_width;
2651 else if (strcmp (t->d.v.name, "icon_height") == 0)
2652 *result = env->icon_height;
2653 else if (strcmp (t->d.v.name, "title_width") == 0)
2654 *result = env->title_width;
2655 else if (strcmp (t->d.v.name, "title_height") == 0)
2656 *result = env->title_height;
2657 else if (strcmp (t->d.v.name, "frame_x_center") == 0)
2658 *result = env->frame_x_center;
2659 else if (strcmp (t->d.v.name, "frame_y_center") == 0)
2660 *result = env->frame_y_center;
2661 else
2662 {
2663 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2664 META_THEME_ERROR_UNKNOWN_VARIABLE,
2665 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2666 t->d.v.name);
2667 return FALSE(0);
2668 }
2669 }
2670
2671 return TRUE(!(0));
2672}
2673
2674/**
2675 * Evaluates a sequence of tokens within a particular environment context,
2676 * and returns the current value. May recur if parantheses are found.
2677 *
2678 * \param tokens A list of tokens to evaluate.
2679 * \param n_tokens How many tokens are in the list.
2680 * \param env The environment context in which to evaluate the expression.
2681 * \param[out] result The current value of the expression
2682 *
2683 * \bug Yes, we really do reparse the expression every time it's evaluated.
2684 * We should keep the parse tree around all the time and just
2685 * run the new values through it.
2686 * \ingroup parser
2687 */
2688static gboolean
2689pos_eval_helper (PosToken *tokens,
2690 int n_tokens,
2691 const MetaPositionExprEnv *env,
2692 PosExpr *result,
2693 GError **err)
2694{
2695 /* Lazy-ass hardcoded limit on number of terms in expression */
2696#define MAX_EXPRS32 32
2697 int paren_level;
2698 int first_paren;
2699 int i;
2700 PosExpr exprs[MAX_EXPRS32];
2701 int n_exprs;
2702 int precedence;
2703
2704 /* Our first goal is to get a list of PosExpr, essentially
2705 * substituting variables and handling parentheses.
2706 */
2707
2708 first_paren = 0;
2709 paren_level = 0;
2710 n_exprs = 0;
2711 for (i = 0; i < n_tokens; i++)
2712 {
2713 PosToken *t = &tokens[i];
2714
2715 if (n_exprs >= MAX_EXPRS32)
2716 {
2717 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2718 META_THEME_ERROR_FAILED,
2719 _("Coordinate expression parser overflowed its buffer.")((char *) g_dgettext ("marco", "Coordinate expression parser overflowed its buffer."
))
);
2720 return FALSE(0);
2721 }
2722
2723 if (paren_level == 0)
2724 {
2725 switch (t->type)
2726 {
2727 case POS_TOKEN_INT:
2728 exprs[n_exprs].type = POS_EXPR_INT;
2729 exprs[n_exprs].d.int_val = t->d.i.val;
2730 ++n_exprs;
2731 break;
2732
2733 case POS_TOKEN_DOUBLE:
2734 exprs[n_exprs].type = POS_EXPR_DOUBLE;
2735 exprs[n_exprs].d.double_val = t->d.d.val;
2736 ++n_exprs;
2737 break;
2738
2739 case POS_TOKEN_OPEN_PAREN:
2740 ++paren_level;
2741 if (paren_level == 1)
2742 first_paren = i;
2743 break;
2744
2745 case POS_TOKEN_CLOSE_PAREN:
2746 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2747 META_THEME_ERROR_BAD_PARENS,
2748 _("Coordinate expression had a close parenthesis with no open parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had a close parenthesis with no open parenthesis"
))
);
2749 return FALSE(0);
2750
2751 case POS_TOKEN_VARIABLE:
2752 exprs[n_exprs].type = POS_EXPR_INT;
2753
2754 /* FIXME we should just dump all this crap
2755 * in a hash, maybe keep width/height out
2756 * for optimization purposes
2757 */
2758 if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err))
2759 return FALSE(0);
2760
2761 ++n_exprs;
2762 break;
2763
2764 case POS_TOKEN_OPERATOR:
2765 exprs[n_exprs].type = POS_EXPR_OPERATOR;
2766 exprs[n_exprs].d.operator = t->d.o.op;
2767 ++n_exprs;
2768 break;
2769 }
2770 }
2771 else
2772 {
2773 g_assert (paren_level > 0)do { if (paren_level > 0) ; else g_assertion_message_expr (
"marco", "ui/theme.c", 2773, ((const char*) (__func__)), "paren_level > 0"
); } while (0)
;
2774
2775 switch (t->type)
2776 {
2777 case POS_TOKEN_INT:
2778 case POS_TOKEN_DOUBLE:
2779 case POS_TOKEN_VARIABLE:
2780 case POS_TOKEN_OPERATOR:
2781 break;
2782
2783 case POS_TOKEN_OPEN_PAREN:
2784 ++paren_level;
2785 break;
2786
2787 case POS_TOKEN_CLOSE_PAREN:
2788 if (paren_level == 1)
2789 {
2790 /* We closed a toplevel paren group, so recurse */
2791 if (!pos_eval_helper (&tokens[first_paren+1],
2792 i - first_paren - 1,
2793 env,
2794 &exprs[n_exprs],
2795 err))
2796 return FALSE(0);
2797
2798 ++n_exprs;
2799 }
2800
2801 --paren_level;
2802 break;
2803
2804 }
2805 }
2806 }
2807
2808 if (paren_level > 0)
2809 {
2810 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2811 META_THEME_ERROR_BAD_PARENS,
2812 _("Coordinate expression had an open parenthesis with no close parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had an open parenthesis with no close parenthesis"
))
);
2813 return FALSE(0);
2814 }
2815
2816 /* Now we have no parens and no vars; so we just do all the multiplies
2817 * and divides, then all the add and subtract.
2818 */
2819 if (n_exprs == 0)
2820 {
2821 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2822 META_THEME_ERROR_FAILED,
2823 _("Coordinate expression doesn't seem to have any operators or operands")((char *) g_dgettext ("marco", "Coordinate expression doesn't seem to have any operators or operands"
))
);
2824 return FALSE(0);
2825 }
2826
2827 /* precedence 1 ops */
2828 precedence = 2;
2829 while (precedence >= 0)
2830 {
2831 if (!do_operations (exprs, &n_exprs, precedence, err))
2832 return FALSE(0);
2833 --precedence;
2834 }
2835
2836 g_assert (n_exprs == 1)do { if (n_exprs == 1) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2836, ((const char*) (__func__)), "n_exprs == 1"
); } while (0)
;
2837
2838 *result = *exprs;
2839
2840 return TRUE(!(0));
2841}
2842
2843/*
2844 * expr = int | double | expr * expr | expr / expr |
2845 * expr + expr | expr - expr | (expr)
2846 *
2847 * so very not worth fooling with bison, yet so very painful by hand.
2848 */
2849/**
2850 * Evaluates an expression.
2851 *
2852 * \param spec The expression to evaluate.
2853 * \param env The environment context to evaluate the expression in.
2854 * \param[out] val_p The integer value of the expression; if the expression
2855 * is of type float, this will be rounded. If we return
2856 * FALSE because the expression is invalid, this will be
2857 * zero.
2858 * \param[out] err The error, if anything went wrong.
2859 *
2860 * \return True if we evaluated the expression successfully; false otherwise.
2861 *
2862 * \bug Shouldn't spec be const?
2863 * \ingroup parser
2864 */
2865static gboolean
2866pos_eval (MetaDrawSpec *spec,
2867 const MetaPositionExprEnv *env,
2868 int *val_p,
2869 GError **err)
2870{
2871 PosExpr expr;
2872
2873 *val_p = 0;
2874
2875 if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err))
2876 {
2877 switch (expr.type)
2878 {
2879 case POS_EXPR_INT:
2880 *val_p = expr.d.int_val;
2881 break;
2882 case POS_EXPR_DOUBLE:
2883 *val_p = (int) expr.d.double_val;
2884 break;
2885 case POS_EXPR_OPERATOR:
2886 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2886, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2887 break;
2888 }
2889 return TRUE(!(0));
2890 }
2891 else
2892 {
2893 return FALSE(0);
2894 }
2895}
2896
2897/* We always return both X and Y, but only one will be meaningful in
2898 * most contexts.
2899 */
2900
2901gboolean
2902meta_parse_position_expression (MetaDrawSpec *spec,
2903 const MetaPositionExprEnv *env,
2904 int *x_return,
2905 int *y_return,
2906 GError **err)
2907{
2908 /* All positions are in a coordinate system with x, y at the origin.
2909 * The expression can have -, +, *, / as operators, floating point
2910 * or integer constants, and the variables "width" and "height" and
2911 * optionally "object_width" and object_height". Negative numbers
2912 * aren't allowed.
2913 */
2914 int val;
2915
2916 if (spec->constant)
2917 val = spec->value;
2918 else
2919 {
2920 if (!pos_eval (spec, env, &spec->value, err))
2921 {
2922 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2922, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2923 return FALSE(0);
2924 }
2925
2926 val = spec->value;
2927 }
2928
2929 if (x_return)
2930 *x_return = env->rect.x + val;
2931 if (y_return)
2932 *y_return = env->rect.y + val;
2933
2934 return TRUE(!(0));
2935}
2936
2937gboolean
2938meta_parse_size_expression (MetaDrawSpec *spec,
2939 const MetaPositionExprEnv *env,
2940 int *val_return,
2941 GError **err)
2942{
2943 int val;
2944
2945 if (spec->constant)
2946 val = spec->value;
2947 else
2948 {
2949 if (!pos_eval (spec, env, &spec->value, err))
2950 {
2951 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2951, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2952 return FALSE(0);
2953 }
2954
2955 val = spec->value;
2956 }
2957
2958 if (val_return)
2959 *val_return = MAX (val, 1)(((val) > (1)) ? (val) : (1)); /* require that sizes be at least 1x1 */
2960
2961 return TRUE(!(0));
2962}
2963
2964/* To do this we tokenize, replace variable tokens
2965 * that are constants, then reassemble. The purpose
2966 * here is to optimize expressions so we don't do hash
2967 * lookups to eval them. Obviously it's a tradeoff that
2968 * slows down theme load times.
2969 */
2970gboolean
2971meta_theme_replace_constants (MetaTheme *theme,
2972 PosToken *tokens,
2973 int n_tokens,
2974 GError **err)
2975{
2976 int i;
2977 double dval;
2978 int ival;
2979 gboolean is_constant = TRUE(!(0));
2980
2981 /* Loop through tokenized string looking for variables to replace */
2982 for (i = 0; i < n_tokens; i++)
2983 {
2984 PosToken *t = &tokens[i];
2985
2986 if (t->type == POS_TOKEN_VARIABLE)
2987 {
2988 if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival))
2989 {
2990 g_free (t->d.v.name);
2991 t->type = POS_TOKEN_INT;
2992 t->d.i.val = ival;
2993 }
2994 else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval))
2995 {
2996 g_free (t->d.v.name);
2997 t->type = POS_TOKEN_DOUBLE;
2998 t->d.d.val = dval;
2999 }
3000 else
3001 {
3002 /* If we've found a variable that cannot be replaced then the
3003 expression is not a constant expression and we want to
3004 replace it with a GQuark */
3005
3006 t->d.v.name_quark = g_quark_from_string (t->d.v.name);
3007 is_constant = FALSE(0);
3008 }
3009 }
3010 }
3011
3012 return is_constant;
3013}
3014
3015static int
3016parse_x_position_unchecked (MetaDrawSpec *spec,
3017 const MetaPositionExprEnv *env)
3018{
3019 int retval;
3020 GError *error;
3021
3022 retval = 0;
3023 error = NULL((void*)0);
3024 if (!meta_parse_position_expression (spec, env, &retval, NULL((void*)0), &error))
3025 {
3026 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3027 error->message);
3028
3029 g_error_free (error);
3030 }
3031
3032 return retval;
3033}
3034
3035static int
3036parse_y_position_unchecked (MetaDrawSpec *spec,
3037 const MetaPositionExprEnv *env)
3038{
3039 int retval;
3040 GError *error;
3041
3042 retval = 0;
3043 error = NULL((void*)0);
3044 if (!meta_parse_position_expression (spec, env, NULL((void*)0), &retval, &error))
3045 {
3046 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3047 error->message);
3048
3049 g_error_free (error);
3050 }
3051
3052 return retval;
3053}
3054
3055static int
3056parse_size_unchecked (MetaDrawSpec *spec,
3057 MetaPositionExprEnv *env)
3058{
3059 int retval;
3060 GError *error;
3061
3062 retval = 0;
3063 error = NULL((void*)0);
3064 if (!meta_parse_size_expression (spec, env, &retval, &error))
3065 {
3066 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3067 error->message);
3068
3069 g_error_free (error);
3070 }
3071
3072 return retval;
3073}
3074
3075void
3076meta_draw_spec_free (MetaDrawSpec *spec)
3077{
3078 if (!spec) return;
3079 free_tokens (spec->tokens, spec->n_tokens);
3080 g_slice_free (MetaDrawSpec, spec)do { if (1) g_slice_free1 (sizeof (MetaDrawSpec), (spec)); else
(void) ((MetaDrawSpec*) 0 == (spec)); } while (0)
;
3081}
3082
3083MetaDrawSpec *
3084meta_draw_spec_new (MetaTheme *theme,
3085 const char *expr,
3086 GError **error)
3087{
3088 MetaDrawSpec *spec;
3089
3090 spec = g_slice_new0 (MetaDrawSpec)((MetaDrawSpec*) g_slice_alloc0 (sizeof (MetaDrawSpec)));
3091
3092 pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL((void*)0));
3093
3094 spec->constant = meta_theme_replace_constants (theme, spec->tokens,
3095 spec->n_tokens, NULL((void*)0));
3096 if (spec->constant)
3097 {
3098 if (!pos_eval (spec, NULL((void*)0), &spec->value, error))
3099 {
3100 meta_draw_spec_free (spec);
3101 return NULL((void*)0);
3102 }
3103 }
3104
3105 return spec;
3106}
3107
3108MetaDrawOp*
3109meta_draw_op_new (MetaDrawType type)
3110{
3111 MetaDrawOp *op;
3112 MetaDrawOp dummy;
3113 int size;
3114
3115 size = G_STRUCT_OFFSET (MetaDrawOp, data)((glong) __builtin_offsetof(MetaDrawOp, data));
3116
3117 switch (type)
1
Control jumps to 'case META_DRAW_TILE:' at line 3169
3118 {
3119 case META_DRAW_LINE:
3120 size += sizeof (dummy.data.line);
3121 break;
3122
3123 case META_DRAW_RECTANGLE:
3124 size += sizeof (dummy.data.rectangle);
3125 break;
3126
3127 case META_DRAW_ARC:
3128 size += sizeof (dummy.data.arc);
3129 break;
3130
3131 case META_DRAW_CLIP:
3132 size += sizeof (dummy.data.clip);
3133 break;
3134
3135 case META_DRAW_TINT:
3136 size += sizeof (dummy.data.tint);
3137 break;
3138
3139 case META_DRAW_GRADIENT:
3140 size += sizeof (dummy.data.gradient);
3141 break;
3142
3143 case META_DRAW_IMAGE:
3144 size += sizeof (dummy.data.image);
3145 break;
3146
3147 case META_DRAW_GTK_ARROW:
3148 size += sizeof (dummy.data.gtk_arrow);
3149 break;
3150
3151 case META_DRAW_GTK_BOX:
3152 size += sizeof (dummy.data.gtk_box);
3153 break;
3154
3155 case META_DRAW_GTK_VLINE:
3156 size += sizeof (dummy.data.gtk_vline);
3157 break;
3158
3159 case META_DRAW_ICON:
3160 size += sizeof (dummy.data.icon);
3161 break;
3162
3163 case META_DRAW_TITLE:
3164 size += sizeof (dummy.data.title);
3165 break;
3166 case META_DRAW_OP_LIST:
3167 size += sizeof (dummy.data.op_list);
3168 break;
3169 case META_DRAW_TILE:
3170 size += sizeof (dummy.data.tile);
3171 break;
3172 }
3173
3174 op = g_malloc0 (size);
2
Execution continues on line 3174
3
Cast a region whose size is not a multiple of the destination type size
3175
3176 op->type = type;
3177
3178 return op;
3179}
3180
3181void
3182meta_draw_op_free (MetaDrawOp *op)
3183{
3184 g_return_if_fail (op != NULL)do { if ((op != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op != NULL"); return;
} } while (0)
;
3185
3186 switch (op->type)
3187 {
3188 case META_DRAW_LINE:
3189 if (op->data.line.color_spec)
3190 meta_color_spec_free (op->data.line.color_spec);
3191
3192 meta_draw_spec_free (op->data.line.x1);
3193 meta_draw_spec_free (op->data.line.y1);
3194 meta_draw_spec_free (op->data.line.x2);
3195 meta_draw_spec_free (op->data.line.y2);
3196 break;
3197
3198 case META_DRAW_RECTANGLE:
3199 if (op->data.rectangle.color_spec)
3200 g_free (op->data.rectangle.color_spec);
3201
3202 meta_draw_spec_free (op->data.rectangle.x);
3203 meta_draw_spec_free (op->data.rectangle.y);
3204 meta_draw_spec_free (op->data.rectangle.width);
3205 meta_draw_spec_free (op->data.rectangle.height);
3206 break;
3207
3208 case META_DRAW_ARC:
3209 if (op->data.arc.color_spec)
3210 g_free (op->data.arc.color_spec);
3211
3212 meta_draw_spec_free (op->data.arc.x);
3213 meta_draw_spec_free (op->data.arc.y);
3214 meta_draw_spec_free (op->data.arc.width);
3215 meta_draw_spec_free (op->data.arc.height);
3216 break;
3217
3218 case META_DRAW_CLIP:
3219 meta_draw_spec_free (op->data.clip.x);
3220 meta_draw_spec_free (op->data.clip.y);
3221 meta_draw_spec_free (op->data.clip.width);
3222 meta_draw_spec_free (op->data.clip.height);
3223 break;
3224
3225 case META_DRAW_TINT:
3226 if (op->data.tint.color_spec)
3227 meta_color_spec_free (op->data.tint.color_spec);
3228
3229 if (op->data.tint.alpha_spec)
3230 meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
3231
3232 meta_draw_spec_free (op->data.tint.x);
3233 meta_draw_spec_free (op->data.tint.y);
3234 meta_draw_spec_free (op->data.tint.width);
3235 meta_draw_spec_free (op->data.tint.height);
3236 break;
3237
3238 case META_DRAW_GRADIENT:
3239 if (op->data.gradient.gradient_spec)
3240 meta_gradient_spec_free (op->data.gradient.gradient_spec);
3241
3242 if (op->data.gradient.alpha_spec)
3243 meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
3244
3245 meta_draw_spec_free (op->data.gradient.x);
3246 meta_draw_spec_free (op->data.gradient.y);
3247 meta_draw_spec_free (op->data.gradient.width);
3248 meta_draw_spec_free (op->data.gradient.height);
3249 break;
3250
3251 case META_DRAW_IMAGE:
3252 if (op->data.image.alpha_spec)
3253 meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
3254
3255 if (op->data.image.pixbuf)
3256 g_object_unref (G_OBJECT (op->data.image.pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.pixbuf)), (((GType) ((20) << (2)
)))))))
);
3257
3258 if (op->data.image.colorize_spec)
3259 meta_color_spec_free (op->data.image.colorize_spec);
3260
3261 if (op->data.image.colorize_cache_pixbuf)
3262 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3263
3264 meta_draw_spec_free (op->data.image.x);
3265 meta_draw_spec_free (op->data.image.y);
3266 meta_draw_spec_free (op->data.image.width);
3267 meta_draw_spec_free (op->data.image.height);
3268 break;
3269
3270 case META_DRAW_GTK_ARROW:
3271 meta_draw_spec_free (op->data.gtk_arrow.x);
3272 meta_draw_spec_free (op->data.gtk_arrow.y);
3273 meta_draw_spec_free (op->data.gtk_arrow.width);
3274 meta_draw_spec_free (op->data.gtk_arrow.height);
3275 break;
3276
3277 case META_DRAW_GTK_BOX:
3278 meta_draw_spec_free (op->data.gtk_box.x);
3279 meta_draw_spec_free (op->data.gtk_box.y);
3280 meta_draw_spec_free (op->data.gtk_box.width);
3281 meta_draw_spec_free (op->data.gtk_box.height);
3282 break;
3283
3284 case META_DRAW_GTK_VLINE:
3285 meta_draw_spec_free (op->data.gtk_vline.x);
3286 meta_draw_spec_free (op->data.gtk_vline.y1);
3287 meta_draw_spec_free (op->data.gtk_vline.y2);
3288 break;
3289
3290 case META_DRAW_ICON:
3291 if (op->data.icon.alpha_spec)
3292 meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
3293
3294 meta_draw_spec_free (op->data.icon.x);
3295 meta_draw_spec_free (op->data.icon.y);
3296 meta_draw_spec_free (op->data.icon.width);
3297 meta_draw_spec_free (op->data.icon.height);
3298 break;
3299
3300 case META_DRAW_TITLE:
3301 if (op->data.title.color_spec)
3302 meta_color_spec_free (op->data.title.color_spec);
3303
3304 meta_draw_spec_free (op->data.title.x);
3305 meta_draw_spec_free (op->data.title.y);
3306 if (op->data.title.ellipsize_width)
3307 meta_draw_spec_free (op->data.title.ellipsize_width);
3308 break;
3309
3310 case META_DRAW_OP_LIST:
3311 if (op->data.op_list.op_list)
3312 meta_draw_op_list_unref (op->data.op_list.op_list);
3313
3314 meta_draw_spec_free (op->data.op_list.x);
3315 meta_draw_spec_free (op->data.op_list.y);
3316 meta_draw_spec_free (op->data.op_list.width);
3317 meta_draw_spec_free (op->data.op_list.height);
3318 break;
3319
3320 case META_DRAW_TILE:
3321 if (op->data.tile.op_list)
3322 meta_draw_op_list_unref (op->data.tile.op_list);
3323
3324 meta_draw_spec_free (op->data.tile.x);
3325 meta_draw_spec_free (op->data.tile.y);
3326 meta_draw_spec_free (op->data.tile.width);
3327 meta_draw_spec_free (op->data.tile.height);
3328 meta_draw_spec_free (op->data.tile.tile_xoffset);
3329 meta_draw_spec_free (op->data.tile.tile_yoffset);
3330 meta_draw_spec_free (op->data.tile.tile_width);
3331 meta_draw_spec_free (op->data.tile.tile_height);
3332 break;
3333 }
3334
3335 g_free (op);
3336}
3337
3338static GdkPixbuf*
3339apply_alpha (GdkPixbuf *pixbuf,
3340 MetaAlphaGradientSpec *spec,
3341 gboolean force_copy)
3342{
3343 GdkPixbuf *new_pixbuf;
3344 gboolean needs_alpha;
3345
3346 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return (((void*)0)); } } while
(0)
;
3347
3348 needs_alpha = spec && (spec->n_alphas > 1 ||
3349 spec->alphas[0] != 0xff);
3350
3351 if (!needs_alpha)
3352 return pixbuf;
3353
3354 if (!gdk_pixbuf_get_has_alpha (pixbuf))
3355 {
3356 new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE(0), 0, 0, 0);
3357 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3358 pixbuf = new_pixbuf;
3359 }
3360 else if (force_copy)
3361 {
3362 new_pixbuf = gdk_pixbuf_copy (pixbuf);
3363 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3364 pixbuf = new_pixbuf;
3365 }
3366
3367 g_assert (gdk_pixbuf_get_has_alpha (pixbuf))do { if (gdk_pixbuf_get_has_alpha (pixbuf)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 3367, ((const char*) (__func__)), "gdk_pixbuf_get_has_alpha (pixbuf)"
); } while (0)
;
3368
3369 meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
3370
3371 return pixbuf;
3372}
3373
3374static GdkPixbuf*
3375pixbuf_tile (GdkPixbuf *tile,
3376 int width,
3377 int height)
3378{
3379 GdkPixbuf *pixbuf;
3380 int tile_width;
3381 int tile_height;
3382 int i, j;
3383
3384 tile_width = gdk_pixbuf_get_width (tile);
3385 tile_height = gdk_pixbuf_get_height (tile);
3386
3387 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3388 gdk_pixbuf_get_has_alpha (tile),
3389 8, width, height);
3390
3391 i = 0;
3392 while (i < width)
3393 {
3394 j = 0;
3395 while (j < height)
3396 {
3397 int w, h;
3398
3399 w = MIN (tile_width, width - i)(((tile_width) < (width - i)) ? (tile_width) : (width - i)
)
;
3400 h = MIN (tile_height, height - j)(((tile_height) < (height - j)) ? (tile_height) : (height -
j))
;
3401
3402 gdk_pixbuf_copy_area (tile,
3403 0, 0,
3404 w, h,
3405 pixbuf,
3406 i, j);
3407
3408 j += tile_height;
3409 }
3410
3411 i += tile_width;
3412 }
3413
3414 return pixbuf;
3415}
3416
3417static GdkPixbuf *
3418replicate_rows (GdkPixbuf *src,
3419 int src_x,
3420 int src_y,
3421 int width,
3422 int height)
3423{
3424 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3425 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3426 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3427 * n_channels);
3428 unsigned char *dest_pixels;
3429 GdkPixbuf *result;
3430 unsigned int dest_rowstride;
3431 int i;
3432
3433 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3434 width, height);
3435 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3436 dest_pixels = gdk_pixbuf_get_pixels (result);
3437
3438 for (i = 0; i < height; i++)
3439 memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
3440
3441 return result;
3442}
3443
3444static GdkPixbuf *
3445replicate_cols (GdkPixbuf *src,
3446 int src_x,
3447 int src_y,
3448 int width,
3449 int height)
3450{
3451 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3452 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3453 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3454 * n_channels);
3455 unsigned char *dest_pixels;
3456 GdkPixbuf *result;
3457 unsigned int dest_rowstride;
3458 int i, j;
3459
3460 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3461 width, height);
3462 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3463 dest_pixels = gdk_pixbuf_get_pixels (result);
3464
3465 for (i = 0; i < height; i++)
3466 {
3467 unsigned char *p = dest_pixels + dest_rowstride * i;
3468 unsigned char *q = pixels + src_rowstride * i;
3469
3470 unsigned char r = *(q++);
3471 unsigned char g = *(q++);
3472 unsigned char b = *(q++);
3473
3474 if (n_channels == 4)
3475 {
3476 unsigned char a;
3477
3478 a = *(q++);
3479
3480 for (j = 0; j < width; j++)
3481 {
3482 *(p++) = r;
3483 *(p++) = g;
3484 *(p++) = b;
3485 *(p++) = a;
3486 }
3487 }
3488 else
3489 {
3490 for (j = 0; j < width; j++)
3491 {
3492 *(p++) = r;
3493 *(p++) = g;
3494 *(p++) = b;
3495 }
3496 }
3497 }
3498
3499 return result;
3500}
3501
3502static GdkPixbuf*
3503scale_and_alpha_pixbuf (GdkPixbuf *src,
3504 MetaAlphaGradientSpec *alpha_spec,
3505 MetaImageFillType fill_type,
3506 int width,
3507 int height,
3508 gboolean vertical_stripes,
3509 gboolean horizontal_stripes)
3510{
3511 GdkPixbuf *pixbuf;
3512 GdkPixbuf *temp_pixbuf;
3513
3514 pixbuf = NULL((void*)0);
3515
3516 pixbuf = src;
3517
3518 if (gdk_pixbuf_get_width (pixbuf) == width &&
3519 gdk_pixbuf_get_height (pixbuf) == height)
3520 {
3521 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
3522 }
3523 else
3524 {
3525 if (fill_type == META_IMAGE_FILL_TILE)
3526 {
3527 pixbuf = pixbuf_tile (pixbuf, width, height);
3528 }
3529 else
3530 {
3531 int src_h, src_w, dest_h, dest_w;
3532 src_h = gdk_pixbuf_get_height (src);
3533 src_w = gdk_pixbuf_get_width (src);
3534
3535 /* prefer to replicate_cols if possible, as that
3536 * is faster (no memory reads)
3537 */
3538 if (horizontal_stripes)
3539 {
3540 dest_w = gdk_pixbuf_get_width (src);
3541 dest_h = height;
3542 }
3543 else if (vertical_stripes)
3544 {
3545 dest_w = width;
3546 dest_h = gdk_pixbuf_get_height (src);
3547 }
3548
3549 else
3550 {
3551 dest_w = width;
3552 dest_h = height;
3553 }
3554
3555 if (dest_w == src_w && dest_h == src_h)
3556 {
3557 temp_pixbuf = src;
3558 g_object_ref (G_OBJECT (temp_pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2)))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2))))))))))
;
3559 }
3560 else
3561 {
3562 temp_pixbuf = gdk_pixbuf_scale_simple (src,
3563 dest_w, dest_h,
3564 GDK_INTERP_BILINEAR);
3565 }
3566
3567 /* prefer to replicate_cols if possible, as that
3568 * is faster (no memory reads)
3569 */
3570 if (horizontal_stripes)
3571 {
3572 pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
3573 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3574 }
3575 else if (vertical_stripes)
3576 {
3577 pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
3578 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3579 }
3580 else
3581 {
3582 pixbuf = temp_pixbuf;
3583 }
3584 }
3585 }
3586
3587 if (pixbuf)
3588 pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
3589
3590 return pixbuf;
3591}
3592
3593static GdkPixbuf*
3594draw_op_as_pixbuf (const MetaDrawOp *op,
3595 GtkStyleContext *style,
3596 const MetaDrawInfo *info,
3597 int width,
3598 int height)
3599{
3600 /* Try to get the op as a pixbuf, assuming w/h in the op
3601 * matches the width/height passed in. return NULL
3602 * if the op can't be converted to an equivalent pixbuf.
3603 */
3604 GdkPixbuf *pixbuf;
3605
3606 pixbuf = NULL((void*)0);
3607
3608 switch (op->type)
3609 {
3610 case META_DRAW_LINE:
3611 break;
3612
3613 case META_DRAW_RECTANGLE:
3614 if (op->data.rectangle.filled)
3615 {
3616 GdkRGBA color;
3617
3618 meta_color_spec_render (op->data.rectangle.color_spec,
3619 style,
3620 &color);
3621
3622 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3623 FALSE(0),
3624 8, width, height);
3625
3626 gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
);
3627 }
3628 break;
3629
3630 case META_DRAW_ARC:
3631 break;
3632
3633 case META_DRAW_CLIP:
3634 break;
3635
3636 case META_DRAW_TINT:
3637 {
3638 GdkRGBA color;
3639 guint32 rgba;
3640 gboolean has_alpha;
3641
3642 meta_color_spec_render (op->data.rectangle.color_spec,
3643 style,
3644 &color);
3645
3646 has_alpha =
3647 op->data.tint.alpha_spec &&
3648 (op->data.tint.alpha_spec->n_alphas > 1 ||
3649 op->data.tint.alpha_spec->alphas[0] != 0xff);
3650
3651 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3652 has_alpha,
3653 8, width, height);
3654
3655 if (!has_alpha)
3656 {
3657 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3658
3659 gdk_pixbuf_fill (pixbuf, rgba);
3660 }
3661 else if (op->data.tint.alpha_spec->n_alphas == 1)
3662 {
3663 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3664 rgba &= ~0xff;
3665 rgba |= op->data.tint.alpha_spec->alphas[0];
3666
3667 gdk_pixbuf_fill (pixbuf, rgba);
3668 }
3669 else
3670 {
3671 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3672
3673 gdk_pixbuf_fill (pixbuf, rgba);
3674
3675 meta_gradient_add_alpha (pixbuf,
3676 op->data.tint.alpha_spec->alphas,
3677 op->data.tint.alpha_spec->n_alphas,
3678 op->data.tint.alpha_spec->type);
3679 }
3680 }
3681 break;
3682
3683 case META_DRAW_IMAGE:
3684 {
3685 if (op->data.image.colorize_spec)
3686 {
3687 GdkRGBA color;
3688
3689 meta_color_spec_render (op->data.image.colorize_spec,
3690 style, &color);
3691
3692 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3693 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3694 {
3695 if (op->data.image.colorize_cache_pixbuf)
3696 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3697
3698 /* const cast here */
3699 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3700 colorize_pixbuf (op->data.image.pixbuf,
3701 &color);
3702 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3703 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3704 }
3705
3706 if (op->data.image.colorize_cache_pixbuf)
3707 {
3708 pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
3709 op->data.image.alpha_spec,
3710 op->data.image.fill_type,
3711 width, height,
3712 op->data.image.vertical_stripes,
3713 op->data.image.horizontal_stripes);
3714 }
3715 }
3716 else
3717 {
3718 pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
3719 op->data.image.alpha_spec,
3720 op->data.image.fill_type,
3721 width, height,
3722 op->data.image.vertical_stripes,
3723 op->data.image.horizontal_stripes);
3724 }
3725 break;
3726 }
3727
3728 case META_DRAW_GRADIENT:
3729 case META_DRAW_GTK_ARROW:
3730 case META_DRAW_GTK_BOX:
3731 case META_DRAW_GTK_VLINE:
3732 break;
3733
3734 case META_DRAW_ICON:
3735 if (info->mini_icon &&
3736 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3737 height <= gdk_pixbuf_get_height (info->mini_icon))
3738 pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
3739 op->data.icon.alpha_spec,
3740 op->data.icon.fill_type,
3741 width, height,
3742 FALSE(0), FALSE(0));
3743 else if (info->icon)
3744 pixbuf = scale_and_alpha_pixbuf (info->icon,
3745 op->data.icon.alpha_spec,
3746 op->data.icon.fill_type,
3747 width, height,
3748 FALSE(0), FALSE(0));
3749 break;
3750
3751 case META_DRAW_TITLE:
3752 break;
3753
3754 case META_DRAW_OP_LIST:
3755 break;
3756
3757 case META_DRAW_TILE:
3758 break;
3759 }
3760
3761 return pixbuf;
3762}
3763
3764static cairo_surface_t *
3765draw_op_as_surface (const MetaDrawOp *op,
3766 GtkStyleContext *style,
3767 const MetaDrawInfo *info,
3768 gdouble width,
3769 gdouble height)
3770{
3771 cairo_surface_t *surface;
3772
3773 surface = NULL((void*)0);
3774
3775 switch (op->type)
3776 {
3777 case META_DRAW_IMAGE:
3778 {
3779 if (op->data.image.colorize_spec)
3780 {
3781 GdkRGBA color;
3782
3783 meta_color_spec_render (op->data.image.colorize_spec,
3784 style, &color);
3785
3786 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3787 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3788 {
3789 if (op->data.image.colorize_cache_pixbuf)
3790 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3791
3792 /* const cast here */
3793 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3794 colorize_pixbuf (op->data.image.pixbuf,
3795 &color);
3796 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3797 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3798 }
3799
3800 if (op->data.image.colorize_cache_pixbuf)
3801 {
3802 surface = get_surface_from_pixbuf (op->data.image.colorize_cache_pixbuf,
3803 op->data.image.fill_type,
3804 width, height,
3805 op->data.image.vertical_stripes,
3806 op->data.image.horizontal_stripes);
3807 }
3808 }
3809 else
3810 {
3811 surface = get_surface_from_pixbuf (op->data.image.pixbuf,
3812 op->data.image.fill_type,
3813 width, height,
3814 op->data.image.vertical_stripes,
3815 op->data.image.horizontal_stripes);
3816 }
3817 break;
3818 }
3819
3820 case META_DRAW_ICON:
3821 if (info->mini_icon &&
3822 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3823 height <= gdk_pixbuf_get_height (info->mini_icon))
3824 surface = get_surface_from_pixbuf (info->mini_icon, op->data.icon.fill_type,
3825 width, height, FALSE(0), FALSE(0));
3826 else if (info->icon)
3827 surface = get_surface_from_pixbuf (info->icon, op->data.icon.fill_type,
3828 width, height, FALSE(0), FALSE(0));
3829 break;
3830
3831 case META_DRAW_TINT:
3832 case META_DRAW_LINE:
3833 case META_DRAW_RECTANGLE:
3834 case META_DRAW_ARC:
3835 case META_DRAW_CLIP:
3836 case META_DRAW_GRADIENT:
3837 case META_DRAW_GTK_ARROW:
3838 case META_DRAW_GTK_BOX:
3839 case META_DRAW_GTK_VLINE:
3840 case META_DRAW_TITLE:
3841 case META_DRAW_OP_LIST:
3842 case META_DRAW_TILE:
3843 break;
3844
3845 default:
3846 break;
3847 }
3848
3849 return surface;
3850}
3851
3852static void
3853fill_env (MetaPositionExprEnv *env,
3854 const MetaDrawInfo *info,
3855 MetaRectangle logical_region)
3856{
3857 /* FIXME this stuff could be raised into draw_op_list_draw() probably
3858 */
3859 env->rect = logical_region;
3860 env->object_width = -1;
3861 env->object_height = -1;
3862 if (info->fgeom)
3863 {
3864 env->left_width = info->fgeom->borders.visible.left;
3865 env->right_width = info->fgeom->borders.visible.right;
3866 env->top_height = info->fgeom->borders.visible.top;
3867 env->bottom_height = info->fgeom->borders.visible.bottom;
3868 env->frame_x_center = info->fgeom->width / 2 - logical_region.x;
3869 env->frame_y_center = info->fgeom->height / 2 - logical_region.y;
3870 }
3871 else
3872 {
3873 env->left_width = 0;
3874 env->right_width = 0;
3875 env->top_height = 0;
3876 env->bottom_height = 0;
3877 env->frame_x_center = 0;
3878 env->frame_y_center = 0;
3879 }
3880
3881 env->mini_icon_width = info->mini_icon ? gdk_pixbuf_get_width (info->mini_icon) : 0;
3882 env->mini_icon_height = info->mini_icon ? gdk_pixbuf_get_height (info->mini_icon) : 0;
3883 env->icon_width = info->icon ? gdk_pixbuf_get_width (info->icon) : 0;
3884 env->icon_height = info->icon ? gdk_pixbuf_get_height (info->icon) : 0;
3885
3886 env->title_width = info->title_layout_width;
3887 env->title_height = info->title_layout_height;
3888 env->theme = meta_current_theme;
3889}
3890
3891/* This code was originally rendering anti-aliased using X primitives, and
3892 * now has been switched to draw anti-aliased using cairo. In general, the
3893 * closest correspondence between X rendering and cairo rendering is given
3894 * by offsetting the geometry by 0.5 pixels in both directions before rendering
3895 * with cairo. This is because X samples at the upper left corner of the
3896 * pixel while cairo averages over the entire pixel. However, in the cases
3897 * where the X rendering was an exact rectangle with no "jaggies"
3898 * we need to be a bit careful about applying the offset. We want to produce
3899 * the exact same pixel-aligned rectangle, rather than a rectangle with
3900 * fuzz around the edges.
3901 */
3902static void
3903meta_draw_op_draw_with_env (const MetaDrawOp *op,
3904 GtkStyleContext *style_gtk,
3905 cairo_t *cr,
3906 const MetaDrawInfo *info,
3907 MetaRectangle rect,
3908 MetaPositionExprEnv *env)
3909{
3910 GdkRGBA color;
3911
3912 cairo_save (cr);
3913 gtk_style_context_save (style_gtk);
3914
3915 cairo_set_line_width (cr, 1.0);
3916
3917 switch (op->type)
3918 {
3919 case META_DRAW_LINE:
3920 {
3921 int x1, x2, y1, y2;
3922
3923 meta_color_spec_render (op->data.line.color_spec, style_gtk, &color);
3924 gdk_cairo_set_source_rgba (cr, &color);
3925
3926 if (op->data.line.width > 0)
3927 cairo_set_line_width (cr, op->data.line.width);
3928
3929 if (op->data.line.dash_on_length > 0 &&
3930 op->data.line.dash_off_length > 0)
3931 {
3932 double dash_list[2];
3933 dash_list[0] = op->data.line.dash_on_length;
3934 dash_list[1] = op->data.line.dash_off_length;
3935 cairo_set_dash (cr, dash_list, 2, 0);
3936 }
3937
3938 x1 = parse_x_position_unchecked (op->data.line.x1, env);
3939 y1 = parse_y_position_unchecked (op->data.line.y1, env);
3940
3941 if (!op->data.line.x2 &&
3942 !op->data.line.y2 &&
3943 op->data.line.width==0)
3944 {
3945 cairo_rectangle (cr, x1, y1, 1, 1);
3946 cairo_fill (cr);
3947 }
3948 else
3949 {
3950 if (op->data.line.x2)
3951 x2 = parse_x_position_unchecked (op->data.line.x2, env);
3952 else
3953 x2 = x1;
3954
3955 if (op->data.line.y2)
3956 y2 = parse_y_position_unchecked (op->data.line.y2, env);
3957 else
3958 y2 = y1;
3959
3960 /* This is one of the cases where we are matching the exact
3961 * pixel aligned rectangle produced by X; for zero-width lines
3962 * the generic algorithm produces the right result so we don't
3963 * need to handle them here.
3964 */
3965 if ((y1 == y2 || x1 == x2) && op->data.line.width != 0)
3966 {
3967 double offset = op->data.line.width % 2 ? .5 : 0;
3968
3969 if (y1 == y2)
3970 {
3971 cairo_move_to (cr, x1, y1 + offset);
3972 cairo_line_to (cr, x2, y2 + offset);
3973 }
3974 else
3975 {
3976 cairo_move_to (cr, x1 + offset, y1);
3977 cairo_line_to (cr, x2 + offset, y2);
3978 }
3979 }
3980 else
3981 {
3982 /* zero-width lines include both end-points in X, unlike wide lines */
3983 if (op->data.line.width == 0)
3984 cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
3985
3986 cairo_move_to (cr, x1 + .5, y1 + .5);
3987 cairo_line_to (cr, x2 + .5, y2 + .5);
3988 }
3989 cairo_stroke (cr);
3990 }
3991 }
3992 break;
3993
3994 case META_DRAW_RECTANGLE:
3995 {
3996 int rx, ry, rwidth, rheight;
3997
3998 meta_color_spec_render (op->data.rectangle.color_spec, style_gtk, &color);
3999 gdk_cairo_set_source_rgba (cr, &color);
4000
4001 rx = parse_x_position_unchecked (op->data.rectangle.x, env);
4002 ry = parse_y_position_unchecked (op->data.rectangle.y, env);
4003 rwidth = parse_size_unchecked (op->data.rectangle.width, env);
4004 rheight = parse_size_unchecked (op->data.rectangle.height, env);
4005
4006 /* Filled and stroked rectangles are the other cases
4007 * we pixel-align to X rasterization
4008 */
4009 if (op->data.rectangle.filled)
4010 {
4011 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4012 cairo_fill (cr);
4013 }
4014 else
4015 {
4016 cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight);
4017 cairo_stroke (cr);
4018 }
4019 }
4020 break;
4021
4022 case META_DRAW_ARC:
4023 {
4024 int rx, ry, rwidth, rheight;
4025 double start_angle, end_angle;
4026 double center_x, center_y;
4027
4028 meta_color_spec_render (op->data.arc.color_spec, style_gtk, &color);
4029 gdk_cairo_set_source_rgba (cr, &color);
4030
4031 rx = parse_x_position_unchecked (op->data.arc.x, env);
4032 ry = parse_y_position_unchecked (op->data.arc.y, env);
4033 rwidth = parse_size_unchecked (op->data.arc.width, env);
4034 rheight = parse_size_unchecked (op->data.arc.height, env);
4035
4036 start_angle = op->data.arc.start_angle * (M_PI3.14159265358979323846 / 180.)
4037 - (.5 * M_PI3.14159265358979323846); /* start at 12 instead of 3 oclock */
4038 end_angle = start_angle + op->data.arc.extent_angle * (M_PI3.14159265358979323846 / 180.);
4039 center_x = rx + (double)rwidth / 2. + .5;
4040 center_y = ry + (double)rheight / 2. + .5;
4041
4042 cairo_save (cr);
4043
4044 cairo_translate (cr, center_x, center_y);
4045 cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.);
4046
4047 if (op->data.arc.extent_angle >= 0)
4048 cairo_arc (cr, 0, 0, 1, start_angle, end_angle);
4049 else
4050 cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle);
4051
4052 cairo_restore (cr);
4053
4054 if (op->data.arc.filled)
4055 {
4056 cairo_line_to (cr, center_x, center_y);
4057 cairo_fill (cr);
4058 }
4059 else
4060 cairo_stroke (cr);
4061 }
4062 break;
4063
4064 case META_DRAW_CLIP:
4065 break;
4066
4067 case META_DRAW_TINT:
4068 {
4069 int rx, ry, rwidth, rheight;
4070 gboolean needs_alpha;
4071
4072 needs_alpha = op->data.tint.alpha_spec &&
4073 (op->data.tint.alpha_spec->n_alphas > 1 ||
4074 op->data.tint.alpha_spec->alphas[0] != 0xff);
4075
4076 rx = parse_x_position_unchecked (op->data.tint.x, env);
4077 ry = parse_y_position_unchecked (op->data.tint.y, env);
4078 rwidth = parse_size_unchecked (op->data.tint.width, env);
4079 rheight = parse_size_unchecked (op->data.tint.height, env);
4080
4081 if (!needs_alpha)
4082 {
4083 meta_color_spec_render (op->data.tint.color_spec, style_gtk, &color);
4084 gdk_cairo_set_source_rgba (cr, &color);
4085
4086 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4087 cairo_fill (cr);
4088 }
4089 else
4090 {
4091 GdkPixbuf *pixbuf;
4092
4093 pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
4094 rwidth, rheight);
4095
4096 if (pixbuf)
4097 {
4098 gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
4099 cairo_paint (cr);
4100
4101 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
4102 }
4103 }
4104 }
4105 break;
4106
4107 case META_DRAW_GRADIENT:
4108 {
4109 int rx, ry, rwidth, rheight;
4110
4111 rx = parse_x_position_unchecked (op->data.gradient.x, env);
4112 ry = parse_y_position_unchecked (op->data.gradient.y, env);
4113 rwidth = parse_size_unchecked (op->data.gradient.width, env);
4114 rheight = parse_size_unchecked (op->data.gradient.height, env);
4115
4116 meta_gradient_spec_render (op->data.gradient.gradient_spec,
4117 op->data.gradient.alpha_spec,
4118 cr, style_gtk, rx, ry, rwidth, rheight);
4119 }
4120 break;
4121
4122 case META_DRAW_IMAGE:
4123 {
4124 gint scale;
4125 gdouble rx, ry, rwidth, rheight;
4126 cairo_surface_t *surface;
4127
4128 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4129 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4130
4131 if (op->data.image.pixbuf)
4132 {
4133 env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf) / scale;
4134 env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf) / scale;
4135 }
4136
4137 rwidth = parse_size_unchecked (op->data.image.width, env) * scale;
4138 rheight = parse_size_unchecked (op->data.image.height, env) * scale;
4139
4140 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4141
4142 if (surface)
4143 {
4144 rx = parse_x_position_unchecked (op->data.image.x, env) * scale;
4145 ry = parse_y_position_unchecked (op->data.image.y, env) * scale;
4146
4147 cairo_set_source_surface (cr, surface, rx, ry);
4148
4149 if (op->data.image.alpha_spec)
4150 {
4151 cairo_pattern_t *pattern;
4152
4153 cairo_translate (cr, rx, ry);
4154 cairo_scale (cr, rwidth, rheight);
4155
4156 pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec);
4157 cairo_mask (cr, pattern);
4158
4159 cairo_pattern_destroy (pattern);
4160 }
4161 else
4162 {
4163 cairo_paint (cr);
4164 }
4165
4166 cairo_surface_destroy (surface);
4167 }
4168 }
4169 break;
4170
4171 case META_DRAW_GTK_ARROW:
4172 {
4173 int rx, ry, rwidth, rheight;
4174
4175 rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
4176 ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
4177 rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
4178 rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
4179
4180 double size = MAX(rwidth, rheight)(((rwidth) > (rheight)) ? (rwidth) : (rheight)), angle = 0;
4181
4182 switch (op->data.gtk_arrow.arrow)
4183 {
4184 case GTK_ARROW_UP:
4185 angle = 0;
4186 break;
4187 case GTK_ARROW_RIGHT:
4188 angle = M_PI3.14159265358979323846 / 2;
4189 break;
4190 case GTK_ARROW_DOWN:
4191 angle = M_PI3.14159265358979323846;
4192 break;
4193 case GTK_ARROW_LEFT:
4194 angle = 3 * M_PI3.14159265358979323846 / 2;
4195 break;
4196 case GTK_ARROW_NONE:
4197 return;
4198 }
4199
4200 gtk_style_context_set_state (style_gtk, op->data.gtk_arrow.state);
4201 gtk_render_arrow (style_gtk, cr, angle, rx, ry, size);
4202 }
4203 break;
4204
4205 case META_DRAW_GTK_BOX:
4206 {
4207 int rx, ry, rwidth, rheight;
4208
4209 rx = parse_x_position_unchecked (op->data.gtk_box.x, env);
4210 ry = parse_y_position_unchecked (op->data.gtk_box.y, env);
4211 rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
4212 rheight = parse_size_unchecked (op->data.gtk_box.height, env);
4213
4214 gtk_style_context_set_state (style_gtk, op->data.gtk_box.state);
4215 gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight);
4216 gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight);
4217 }
4218 break;
4219
4220 case META_DRAW_GTK_VLINE:
4221 {
4222 int rx, ry1, ry2;
4223
4224 rx = parse_x_position_unchecked (op->data.gtk_vline.x, env);
4225 ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
4226 ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
4227
4228 gtk_style_context_set_state (style_gtk, op->data.gtk_vline.state);
4229 gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2);
4230 }
4231 break;
4232
4233 case META_DRAW_ICON:
4234 {
4235 gint scale;
4236 gdouble rx, ry, rwidth, rheight;
4237 cairo_surface_t *surface;
4238
4239 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4240 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4241
4242 rwidth = parse_size_unchecked (op->data.icon.width, env) * scale;
4243 rheight = parse_size_unchecked (op->data.icon.height, env) * scale;
4244
4245 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4246
4247 if (surface)
4248 {
4249 rx = parse_x_position_unchecked (op->data.icon.x, env) * scale;
4250 ry = parse_y_position_unchecked (op->data.icon.y, env) * scale;
4251
4252 cairo_set_source_surface (cr, surface, rx, ry);
4253
4254 if (op->data.icon.alpha_spec)
4255 {
4256 cairo_pattern_t *pattern;
4257
4258 cairo_translate (cr, rx, ry);
4259 cairo_scale (cr, rwidth, rheight);
4260
4261 pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec);
4262 cairo_mask (cr, pattern);
4263
4264 cairo_pattern_destroy (pattern);
4265 }
4266 else
4267 {
4268 cairo_paint (cr);
4269 }
4270
4271 cairo_surface_destroy (surface);
4272 }
4273 }
4274 break;
4275
4276 case META_DRAW_TITLE:
4277 if (info->title_layout)
4278 {
4279 int rx, ry;
4280 PangoRectangle ink_rect, logical_rect;
4281
4282 meta_color_spec_render (op->data.title.color_spec, style_gtk, &color);
4283 gdk_cairo_set_source_rgba (cr, &color);
4284
4285 rx = parse_x_position_unchecked (op->data.title.x, env);
4286 ry = parse_y_position_unchecked (op->data.title.y, env);
4287
4288 if (op->data.title.ellipsize_width)
4289 {
4290 int ellipsize_width;
4291 int right_bearing;
4292
4293 ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env);
4294 /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */
4295 ellipsize_width -= env->rect.x;
4296
4297 pango_layout_set_width (info->title_layout, -1);
4298 pango_layout_get_pixel_extents (info->title_layout,
4299 &ink_rect, &logical_rect);
4300
4301 /* Pango's idea of ellipsization is with respect to the logical rect.
4302 * correct for this, by reducing the ellipsization width by the overflow
4303 * of the un-ellipsized text on the right... it's always the visual
4304 * right we want regardless of bidi, since since the X we pass in to
4305 * cairo_move_to() is always the left edge of the line.
4306 */
4307 right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width);
4308 right_bearing = MAX (right_bearing, 0)(((right_bearing) > (0)) ? (right_bearing) : (0));
4309
4310 ellipsize_width -= right_bearing;
4311 ellipsize_width = MAX (ellipsize_width, 0)(((ellipsize_width) > (0)) ? (ellipsize_width) : (0));
4312
4313 /* Only ellipsizing when necessary is a performance optimization -
4314 * pango_layout_set_width() will force a relayout if it isn't the
4315 * same as the current width of -1.
4316 */
4317 if (ellipsize_width < logical_rect.width)
4318 pango_layout_set_width (info->title_layout, PANGO_SCALE1024 * ellipsize_width);
4319 }
4320 else if (rx - env->rect.x + env->title_width >= env->rect.width)
4321 {
4322 const double alpha_margin = 30.0;
4323 int text_space = env->rect.x + env->rect.width -
4324 (rx - env->rect.x) - env->right_width;
4325
4326 double startalpha = 1.0 - (alpha_margin/((double)text_space));
4327
4328 cairo_pattern_t *linpat;
4329 linpat = cairo_pattern_create_linear (rx, ry, text_space,
4330 env->title_height);
4331 cairo_pattern_add_color_stop_rgba (linpat, 0, color.red,
4332 color.green,
4333 color.blue,
4334 color.alpha);
4335 cairo_pattern_add_color_stop_rgba (linpat, startalpha,
4336 color.red,
4337 color.green,
4338 color.blue,
4339 color.alpha);
4340 cairo_pattern_add_color_stop_rgba (linpat, 1, color.red,
4341 color.green,
4342 color.blue, 0);
4343 cairo_set_source(cr, linpat);
4344 cairo_pattern_destroy(linpat);
4345 }
4346
4347 cairo_move_to (cr, rx, ry);
4348 pango_cairo_show_layout (cr, info->title_layout);
4349
4350 /* Remove any ellipsization we might have set; will short-circuit
4351 * if the width is already -1 */
4352 pango_layout_set_width (info->title_layout, -1);
4353 }
4354 break;
4355
4356 case META_DRAW_OP_LIST:
4357 {
4358 MetaRectangle d_rect;
4359
4360 d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env);
4361 d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env);
4362 d_rect.width = parse_size_unchecked (op->data.op_list.width, env);
4363 d_rect.height = parse_size_unchecked (op->data.op_list.height, env);
4364
4365 meta_draw_op_list_draw_with_style (op->data.op_list.op_list,
4366 style_gtk,
4367 cr,
4368 info, d_rect);
4369 }
4370 break;
4371
4372 case META_DRAW_TILE:
4373 {
4374 int rx, ry, rwidth, rheight;
4375 int tile_xoffset, tile_yoffset;
4376 MetaRectangle tile;
4377
4378 rx = parse_x_position_unchecked (op->data.tile.x, env);
4379 ry = parse_y_position_unchecked (op->data.tile.y, env);
4380 rwidth = parse_size_unchecked (op->data.tile.width, env);
4381 rheight = parse_size_unchecked (op->data.tile.height, env);
4382
4383 cairo_save (cr);
4384
4385 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4386 cairo_clip (cr);
4387
4388 tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env);
4389 tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env);
4390 /* tile offset should not include x/y */
4391 tile_xoffset -= rect.x;
4392 tile_yoffset -= rect.y;
4393
4394 tile.width = parse_size_unchecked (op->data.tile.tile_width, env);
4395 tile.height = parse_size_unchecked (op->data.tile.tile_height, env);
4396
4397 tile.x = rx - tile_xoffset;
4398
4399 while (tile.x < (rx + rwidth))
4400 {
4401 tile.y = ry - tile_yoffset;
4402 while (tile.y < (ry + rheight))
4403 {
4404 meta_draw_op_list_draw_with_style (op->data.tile.op_list,
4405 style_gtk, cr, info,
4406 tile);
4407
4408 tile.y += tile.height;
4409 }
4410
4411 tile.x += tile.width;
4412 }
4413 cairo_restore (cr);
4414 }
4415 break;
4416 }
4417
4418 cairo_restore (cr);
4419 gtk_style_context_restore (style_gtk);
4420}
4421
4422void
4423meta_draw_op_draw_with_style (const MetaDrawOp *op,
4424 GtkStyleContext *style_gtk,
4425 cairo_t *cr,
4426 const MetaDrawInfo *info,
4427 MetaRectangle logical_region)
4428{
4429 MetaPositionExprEnv env;
4430
4431 fill_env (&env, info, logical_region);
4432
4433 meta_draw_op_draw_with_env (op,
4434 style_gtk,
4435 cr,
4436 info, logical_region,
4437 &env);
4438
4439}
4440
4441void
4442meta_draw_op_draw (const MetaDrawOp *op,
4443 GtkWidget *widget,
4444 cairo_t *cr,
4445 const MetaDrawInfo *info,
4446 MetaRectangle logical_region)
4447{
4448 meta_draw_op_draw_with_style (op,
4449 gtk_widget_get_style_context (widget),
4450 cr,
4451 info, logical_region);
4452}
4453
4454MetaDrawOpList*
4455meta_draw_op_list_new (int n_preallocs)
4456{
4457 MetaDrawOpList *op_list;
4458
4459 g_return_val_if_fail (n_preallocs >= 0, NULL)do { if ((n_preallocs >= 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_preallocs >= 0")
; return (((void*)0)); } } while (0)
;
4460
4461 op_list = g_new (MetaDrawOpList, 1)((MetaDrawOpList *) g_malloc_n ((1), sizeof (MetaDrawOpList))
)
;
4462
4463 op_list->refcount = 1;
4464 op_list->n_allocated = n_preallocs;
4465 op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated)((MetaDrawOp* *) g_malloc_n ((op_list->n_allocated), sizeof
(MetaDrawOp*)))
;
4466 op_list->n_ops = 0;
4467
4468 return op_list;
4469}
4470
4471void
4472meta_draw_op_list_ref (MetaDrawOpList *op_list)
4473{
4474 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4475
4476 op_list->refcount += 1;
4477}
4478
4479void
4480meta_draw_op_list_unref (MetaDrawOpList *op_list)
4481{
4482 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4483 g_return_if_fail (op_list->refcount > 0)do { if ((op_list->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list->refcount > 0"
); return; } } while (0)
;
4484
4485 op_list->refcount -= 1;
4486
4487 if (op_list->refcount == 0)
4488 {
4489 int i;
4490
4491 for (i = 0; i < op_list->n_ops; i++)
4492 meta_draw_op_free (op_list->ops[i]);
4493
4494 g_free (op_list->ops);
4495
4496 DEBUG_FILL_STRUCT (op_list)memset ((op_list), 0xef, sizeof (*(op_list)));
4497 g_free (op_list);
4498 }
4499}
4500
4501void
4502meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
4503 GtkStyleContext *style_gtk,
4504 cairo_t *cr,
4505 const MetaDrawInfo *info,
4506 MetaRectangle rect)
4507{
4508 /* BOOKMARK */
4509
4510 int i;
4511 MetaPositionExprEnv env;
4512
4513 if (op_list->n_ops == 0)
4514 return;
4515
4516 fill_env (&env, info, rect);
4517
4518 /* FIXME this can be optimized, potentially a lot, by
4519 * compressing multiple ops when possible. For example,
4520 * anything convertible to a pixbuf can be composited
4521 * client-side, and putting a color tint over a pixbuf
4522 * can be done without creating the solid-color pixbuf.
4523 *
4524 * To implement this my plan is to have the idea of a
4525 * compiled draw op (with the string expressions already
4526 * evaluated), we make an array of those, and then fold
4527 * adjacent items when possible.
4528 */
4529
4530 cairo_save (cr);
4531
4532 for (i = 0; i < op_list->n_ops; i++)
4533 {
4534 MetaDrawOp *op = op_list->ops[i];
4535
4536 if (op->type == META_DRAW_CLIP)
4537 {
4538 cairo_restore (cr);
4539
4540 cairo_rectangle (cr,
4541 parse_x_position_unchecked (op->data.clip.x, &env),
4542 parse_y_position_unchecked (op->data.clip.y, &env),
4543 parse_size_unchecked (op->data.clip.width, &env),
4544 parse_size_unchecked (op->data.clip.height, &env));
4545 cairo_clip (cr);
4546
4547 cairo_save (cr);
4548 }
4549 else if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
4550 {
4551 meta_draw_op_draw_with_env (op, style_gtk, cr, info, rect, &env);
4552 }
4553 }
4554
4555 cairo_restore (cr);
4556}
4557
4558void
4559meta_draw_op_list_draw (const MetaDrawOpList *op_list,
4560 GtkWidget *widget,
4561 cairo_t *cr,
4562 const MetaDrawInfo *info,
4563 MetaRectangle rect)
4564
4565{
4566 meta_draw_op_list_draw_with_style (op_list,
4567 gtk_widget_get_style_context (widget),
4568 cr,
4569 info, rect);
4570}
4571
4572void
4573meta_draw_op_list_append (MetaDrawOpList *op_list,
4574 MetaDrawOp *op)
4575{
4576 if (op_list->n_ops == op_list->n_allocated)
4577 {
4578 op_list->n_allocated *= 2;
4579 op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated)((MetaDrawOp* *) g_realloc_n (op_list->ops, (op_list->n_allocated
), sizeof (MetaDrawOp*)))
;
4580 }
4581
4582 op_list->ops[op_list->n_ops] = op;
4583 op_list->n_ops += 1;
4584}
4585
4586gboolean
4587meta_draw_op_list_validate (MetaDrawOpList *op_list,
4588 GError **error)
4589{
4590 g_return_val_if_fail (op_list != NULL, FALSE)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
((0)); } } while (0)
;
4591
4592 /* empty lists are OK, nothing else to check really */
4593
4594 return TRUE(!(0));
4595}
4596
4597/* This is not done in validate, since we wouldn't know the name
4598 * of the list to report the error. It might be nice to
4599 * store names inside the list sometime.
4600 */
4601gboolean
4602meta_draw_op_list_contains (MetaDrawOpList *op_list,
4603 MetaDrawOpList *child)
4604{
4605 int i;
4606
4607 /* mmm, huge tree recursion */
4608
4609 for (i = 0; i < op_list->n_ops; i++)
4610 {
4611 if (op_list->ops[i]->type == META_DRAW_OP_LIST)
4612 {
4613 if (op_list->ops[i]->data.op_list.op_list == child)
4614 return TRUE(!(0));
4615
4616 if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list,
4617 child))
4618 return TRUE(!(0));
4619 }
4620 else if (op_list->ops[i]->type == META_DRAW_TILE)
4621 {
4622 if (op_list->ops[i]->data.tile.op_list == child)
4623 return TRUE(!(0));
4624
4625 if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list,
4626 child))
4627 return TRUE(!(0));
4628 }
4629 }
4630
4631 return FALSE(0);
4632}
4633
4634/**
4635 * Constructor for a MetaFrameStyle.
4636 *
4637 * \param parent The parent style. Data not filled in here will be
4638 * looked for in the parent style, and in its parent
4639 * style, and so on.
4640 *
4641 * \return The newly-constructed style.
4642 */
4643MetaFrameStyle*
4644meta_frame_style_new (MetaFrameStyle *parent)
4645{
4646 MetaFrameStyle *style;
4647
4648 style = g_new0 (MetaFrameStyle, 1)((MetaFrameStyle *) g_malloc0_n ((1), sizeof (MetaFrameStyle)
))
;
4649
4650 style->refcount = 1;
4651
4652 /* Default alpha is fully opaque */
4653 style->window_background_alpha = 255;
4654
4655 style->parent = parent;
4656 if (parent)
4657 meta_frame_style_ref (parent);
4658
4659 return style;
4660}
4661
4662/**
4663 * Increases the reference count of a frame style.
4664 * If the style is NULL, this is a no-op.
4665 *
4666 * \param style The style.
4667 */
4668void
4669meta_frame_style_ref (MetaFrameStyle *style)
4670{
4671 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4672
4673 style->refcount += 1;
4674}
4675
4676static void
4677free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
4678{
4679 int i, j;
4680
4681 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4682 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4683 if (op_lists[i][j])
4684 meta_draw_op_list_unref (op_lists[i][j]);
4685}
4686
4687void
4688meta_frame_style_unref (MetaFrameStyle *style)
4689{
4690 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4691 g_return_if_fail (style->refcount > 0)do { if ((style->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->refcount > 0"
); return; } } while (0)
;
4692
4693 style->refcount -= 1;
4694
4695 if (style->refcount == 0)
4696 {
4697 int i;
4698
4699 free_button_ops (style->buttons);
4700
4701 for (i = 0; i < META_FRAME_PIECE_LAST; i++)
4702 if (style->pieces[i])
4703 meta_draw_op_list_unref (style->pieces[i]);
4704
4705 if (style->layout)
4706 meta_frame_layout_unref (style->layout);
4707
4708 if (style->window_background_color)
4709 meta_color_spec_free (style->window_background_color);
4710
4711 /* we hold a reference to any parent style */
4712 if (style->parent)
4713 meta_frame_style_unref (style->parent);
4714
4715 DEBUG_FILL_STRUCT (style)memset ((style), 0xef, sizeof (*(style)));
4716 g_free (style);
4717 }
4718}
4719
4720static MetaButtonState
4721map_button_state (MetaButtonType button_type,
4722 const MetaFrameGeometry *fgeom,
4723 int middle_bg_offset,
4724 MetaButtonState button_states[META_BUTTON_TYPE_LAST])
4725{
4726 MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
4727
4728 switch (button_type)
4729 {
4730 /* First handle functions, which map directly */
4731 case META_BUTTON_TYPE_SHADE:
4732 case META_BUTTON_TYPE_ABOVE:
4733 case META_BUTTON_TYPE_STICK:
4734 case META_BUTTON_TYPE_UNSHADE:
4735 case META_BUTTON_TYPE_UNABOVE:
4736 case META_BUTTON_TYPE_UNSTICK:
4737 case META_BUTTON_TYPE_MENU:
4738 case META_BUTTON_TYPE_APPMENU:
4739 case META_BUTTON_TYPE_MINIMIZE:
4740 case META_BUTTON_TYPE_MAXIMIZE:
4741 case META_BUTTON_TYPE_CLOSE:
4742 return button_states[button_type];
4743
4744 /* Map position buttons to the corresponding function */
4745 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4746 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4747 if (fgeom->n_right_buttons > 0)
4748 function = fgeom->button_layout.right_buttons[0];
4749 break;
4750 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4751 if (fgeom->n_right_buttons > 0)
4752 function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
4753 break;
4754 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4755 if (middle_bg_offset + 1 < fgeom->n_right_buttons)
4756 function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
4757 break;
4758 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4759 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4760 if (fgeom->n_left_buttons > 0)
4761 function = fgeom->button_layout.left_buttons[0];
4762 break;
4763 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4764 if (fgeom->n_left_buttons > 0)
4765 function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
4766 break;
4767 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4768 if (middle_bg_offset + 1 < fgeom->n_left_buttons)
4769 function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
4770 break;
4771 case META_BUTTON_TYPE_LAST:
4772 break;
4773 }
4774
4775 if (function != META_BUTTON_FUNCTION_LAST)
4776 return button_states[map_button_function_to_type (function)];
4777
4778 return META_BUTTON_STATE_LAST;
4779}
4780
4781static MetaDrawOpList*
4782get_button (MetaFrameStyle *style,
4783 MetaButtonType type,
4784 MetaButtonState state)
4785{
4786 MetaDrawOpList *op_list;
4787 MetaFrameStyle *parent;
4788
4789 parent = style;
4790 op_list = NULL((void*)0);
4791 while (parent && op_list == NULL((void*)0))
4792 {
4793 op_list = parent->buttons[type][state];
4794 parent = parent->parent;
4795 }
4796
4797 /* We fall back to the side buttons if we don't have
4798 * single button backgrounds, and to middle button
4799 * backgrounds if we don't have the ones on the sides
4800 */
4801
4802 if (op_list == NULL((void*)0) &&
4803 type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND)
4804 return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state);
4805
4806 if (op_list == NULL((void*)0) &&
4807 type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND)
4808 return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state);
4809
4810 if (op_list == NULL((void*)0) &&
4811 (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
4812 type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
4813 return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
4814 state);
4815
4816 if (op_list == NULL((void*)0) &&
4817 (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND ||
4818 type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND))
4819 return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
4820 state);
4821
4822 /* We fall back to normal if no prelight */
4823 if (op_list == NULL((void*)0) &&
4824 state == META_BUTTON_STATE_PRELIGHT)
4825 return get_button (style, type, META_BUTTON_STATE_NORMAL);
4826
4827 return op_list;
4828}
4829
4830gboolean
4831meta_frame_style_validate (MetaFrameStyle *style,
4832 guint current_theme_version,
4833 GError **error)
4834{
4835 int i, j;
4836
4837 g_return_val_if_fail (style != NULL, FALSE)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
((0)); } } while (0)
;
4838 g_return_val_if_fail (style->layout != NULL, FALSE)do { if ((style->layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->layout != NULL"
); return ((0)); } } while (0)
;
4839
4840 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4841 {
4842 /* for now the "positional" buttons are optional */
4843 if (i >= META_BUTTON_TYPE_CLOSE)
4844 {
4845 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4846 {
4847 if (get_button (style, i, j) == NULL((void*)0) &&
4848 meta_theme_earliest_version_with_button (i) <= current_theme_version
4849 )
4850 {
4851 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
4852 META_THEME_ERROR_FAILED,
4853 _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style")((char *) g_dgettext ("marco", "<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"
))
,
4854 meta_button_type_to_string (i),
4855 meta_button_state_to_string (j));
4856 return FALSE(0);
4857 }
4858 }
4859 }
4860 }
4861
4862 return TRUE(!(0));
4863}
4864
4865static void
4866get_button_rect (MetaButtonType type,
4867 const MetaFrameGeometry *fgeom,
4868 int middle_background_offset,
4869 GdkRectangle *rect)
4870{
4871 switch (type)
4872 {
4873 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4874 *rect = fgeom->left_left_background;
4875 break;
4876
4877 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4878 *rect = fgeom->left_middle_backgrounds[middle_background_offset];
4879 break;
4880
4881 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4882 *rect = fgeom->left_right_background;
4883 break;
4884
4885 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4886 *rect = fgeom->left_single_background;
4887 break;
4888
4889 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4890 *rect = fgeom->right_left_background;
4891 break;
4892
4893 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4894 *rect = fgeom->right_middle_backgrounds[middle_background_offset];
4895 break;
4896
4897 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4898 *rect = fgeom->right_right_background;
4899 break;
4900
4901 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4902 *rect = fgeom->right_single_background;
4903 break;
4904
4905 case META_BUTTON_TYPE_CLOSE:
4906 *rect = fgeom->close_rect.visible;
4907 break;
4908
4909 case META_BUTTON_TYPE_SHADE:
4910 *rect = fgeom->shade_rect.visible;
4911 break;
4912
4913 case META_BUTTON_TYPE_UNSHADE:
4914 *rect = fgeom->unshade_rect.visible;
4915 break;
4916
4917 case META_BUTTON_TYPE_ABOVE:
4918 *rect = fgeom->above_rect.visible;
4919 break;
4920
4921 case META_BUTTON_TYPE_UNABOVE:
4922 *rect = fgeom->unabove_rect.visible;
4923 break;
4924
4925 case META_BUTTON_TYPE_STICK:
4926 *rect = fgeom->stick_rect.visible;
4927 break;
4928
4929 case META_BUTTON_TYPE_UNSTICK:
4930 *rect = fgeom->unstick_rect.visible;
4931 break;
4932
4933 case META_BUTTON_TYPE_MAXIMIZE:
4934 *rect = fgeom->max_rect.visible;
4935 break;
4936
4937 case META_BUTTON_TYPE_MINIMIZE:
4938 *rect = fgeom->min_rect.visible;
4939 break;
4940
4941 case META_BUTTON_TYPE_MENU:
4942 *rect = fgeom->menu_rect.visible;
4943 break;
4944
4945 case META_BUTTON_TYPE_APPMENU:
4946 *rect = fgeom->appmenu_rect.visible;
4947 break;
4948
4949 case META_BUTTON_TYPE_LAST:
4950 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 4950, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
4951 break;
4952 }
4953}
4954
4955void
4956meta_frame_style_draw_with_style (MetaFrameStyle *style,
4957 GtkStyleContext *style_gtk,
4958 cairo_t *cr,
4959 const MetaFrameGeometry *fgeom,
4960 int client_width,
4961 int client_height,
4962 PangoLayout *title_layout,
4963 int text_height,
4964 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
4965 GdkPixbuf *mini_icon,
4966 GdkPixbuf *icon)
4967{
4968 /* BOOKMARK */
4969 int i, j;
4970 GdkRectangle visible_rect;
4971 GdkRectangle titlebar_rect;
4972 GdkRectangle left_titlebar_edge;
4973 GdkRectangle right_titlebar_edge;
4974 GdkRectangle bottom_titlebar_edge;
4975 GdkRectangle top_titlebar_edge;
4976 GdkRectangle left_edge, right_edge, bottom_edge;
4977 PangoRectangle extents;
4978 MetaDrawInfo draw_info;
4979 const MetaFrameBorders *borders;
4980
4981 borders = &fgeom->borders;
4982
4983 visible_rect.x = borders->invisible.left;
4984 visible_rect.y = borders->invisible.top;
4985 visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
4986 visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
4987
4988 titlebar_rect.x = visible_rect.x;
4989 titlebar_rect.y = visible_rect.y;
4990 titlebar_rect.width = visible_rect.width;
4991 titlebar_rect.height = borders->visible.top;
4992
4993 left_titlebar_edge.x = titlebar_rect.x;
4994 left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
4995 left_titlebar_edge.width = fgeom->left_titlebar_edge;
4996 left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
4997
4998 right_titlebar_edge.y = left_titlebar_edge.y;
4999 right_titlebar_edge.height = left_titlebar_edge.height;
5000 right_titlebar_edge.width = fgeom->right_titlebar_edge;
5001 right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
5002
5003 top_titlebar_edge.x = titlebar_rect.x;
5004 top_titlebar_edge.y = titlebar_rect.y;
5005 top_titlebar_edge.width = titlebar_rect.width;
5006 top_titlebar_edge.height = fgeom->top_titlebar_edge;
5007
5008 bottom_titlebar_edge.x = titlebar_rect.x;
5009 bottom_titlebar_edge.width = titlebar_rect.width;
5010 bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
5011 bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
5012
5013 left_edge.x = visible_rect.x;
5014 left_edge.y = visible_rect.y + borders->visible.top;
5015 left_edge.width = borders->visible.left;
5016 left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5017
5018 right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
5019 right_edge.y = visible_rect.y + borders->visible.top;
5020 right_edge.width = borders->visible.right;
5021 right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5022
5023 bottom_edge.x = visible_rect.x;
5024 bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
5025 bottom_edge.width = visible_rect.width;
5026 bottom_edge.height = borders->visible.bottom;
5027
5028 if (title_layout)
5029 pango_layout_get_pixel_extents (title_layout,
5030 NULL((void*)0), &extents);
5031
5032 draw_info.mini_icon = mini_icon;
5033 draw_info.icon = icon;
5034 draw_info.title_layout = title_layout;
5035 draw_info.title_layout_width = title_layout ? extents.width : 0;
5036 draw_info.title_layout_height = title_layout ? extents.height : 0;
5037 draw_info.fgeom = fgeom;
5038
5039 /* The enum is in the order the pieces should be rendered. */
5040 i = 0;
5041 while (i < META_FRAME_PIECE_LAST)
5042 {
5043 GdkRectangle rect;
5044
5045 switch ((MetaFramePiece) i)
5046 {
5047 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
5048 rect = visible_rect;
5049 break;
5050
5051 case META_FRAME_PIECE_TITLEBAR:
5052 rect = titlebar_rect;
5053 break;
5054
5055 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
5056 rect = left_titlebar_edge;
5057 break;
5058
5059 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
5060 rect = right_titlebar_edge;
5061 break;
5062
5063 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
5064 rect = top_titlebar_edge;
5065 break;
5066
5067 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
5068 rect = bottom_titlebar_edge;
5069 break;
5070
5071 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
5072 rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
5073 rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
5074 rect.width = titlebar_rect.width - left_titlebar_edge.width -
5075 right_titlebar_edge.width;
5076 rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
5077 break;
5078
5079 case META_FRAME_PIECE_TITLE:
5080 rect = fgeom->title_rect;
5081 break;
5082
5083 case META_FRAME_PIECE_LEFT_EDGE:
5084 rect = left_edge;
5085 break;
5086
5087 case META_FRAME_PIECE_RIGHT_EDGE:
5088 rect = right_edge;
5089 break;
5090
5091 case META_FRAME_PIECE_BOTTOM_EDGE:
5092 rect = bottom_edge;
5093 break;
5094
5095 case META_FRAME_PIECE_OVERLAY:
5096 rect = visible_rect;
5097 break;
5098
5099 case META_FRAME_PIECE_LAST:
5100 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5100, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5101 break;
5102 }
5103
5104 cairo_save (cr);
5105
5106 gdk_cairo_rectangle (cr, &rect);
5107 cairo_clip (cr);
5108
5109 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5110 {
5111 MetaDrawOpList *op_list;
5112 MetaFrameStyle *parent;
5113
5114 parent = style;
5115 op_list = NULL((void*)0);
5116 while (parent && op_list == NULL((void*)0))
5117 {
5118 op_list = parent->pieces[i];
5119 parent = parent->parent;
5120 }
5121
5122 if (op_list)
5123 {
5124 MetaRectangle m_rect;
5125 m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
5126 meta_draw_op_list_draw_with_style (op_list,
5127 style_gtk,
5128 cr,
5129 &draw_info,
5130 m_rect);
5131 }
5132 }
5133
5134 cairo_restore (cr);
5135
5136 /* Draw buttons just before overlay */
5137 if ((i + 1) == META_FRAME_PIECE_OVERLAY)
5138 {
5139 MetaDrawOpList *op_list;
5140 int middle_bg_offset;
5141
5142 middle_bg_offset = 0;
5143 j = 0;
5144 while (j < META_BUTTON_TYPE_LAST)
5145 {
5146 MetaButtonState button_state;
5147
5148 get_button_rect (j, fgeom, middle_bg_offset, &rect);
5149
5150 button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
5151 op_list = get_button (style, j, button_state);
5152
5153 if (op_list)
5154 {
5155 cairo_save (cr);
5156 gdk_cairo_rectangle (cr, &rect);
5157 cairo_clip (cr);
5158
5159 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5160 {
5161 MetaRectangle m_rect;
5162
5163 m_rect = meta_rect (rect.x, rect.y,
5164 rect.width, rect.height);
5165
5166 meta_draw_op_list_draw_with_style (op_list,
5167 style_gtk,
5168 cr,
5169 &draw_info,
5170 m_rect);
5171 }
5172
5173 cairo_restore (cr);
5174 }
5175
5176 /* MIDDLE_BACKGROUND type may get drawn more than once */
5177 if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
5178 j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
5179 middle_bg_offset < MAX_MIDDLE_BACKGROUNDS(META_BUTTON_FUNCTION_LAST - 2))
5180 {
5181 ++middle_bg_offset;
5182 }
5183 else
5184 {
5185 middle_bg_offset = 0;
5186 ++j;
5187 }
5188 }
5189 }
5190
5191 ++i;
5192 }
5193}
5194
5195void
5196meta_frame_style_draw (MetaFrameStyle *style,
5197 GtkWidget *widget,
5198 cairo_t *cr,
5199 const MetaFrameGeometry *fgeom,
5200 int client_width,
5201 int client_height,
5202 PangoLayout *title_layout,
5203 int text_height,
5204 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5205 GdkPixbuf *mini_icon,
5206 GdkPixbuf *icon)
5207{
5208 meta_frame_style_draw_with_style (style,
5209 gtk_widget_get_style_context (widget),
5210 cr,
5211 fgeom, client_width, client_height,
5212 title_layout, text_height,
5213 button_states, mini_icon, icon);
5214}
5215
5216MetaFrameStyleSet*
5217meta_frame_style_set_new (MetaFrameStyleSet *parent)
5218{
5219 MetaFrameStyleSet *style_set;
5220
5221 style_set = g_new0 (MetaFrameStyleSet, 1)((MetaFrameStyleSet *) g_malloc0_n ((1), sizeof (MetaFrameStyleSet
)))
;
5222
5223 style_set->parent = parent;
5224 if (parent)
5225 meta_frame_style_set_ref (parent);
5226
5227 style_set->refcount = 1;
5228
5229 return style_set;
5230}
5231
5232static void
5233free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST])
5234{
5235 int i;
5236
5237 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5238 if (focus_styles[i])
5239 meta_frame_style_unref (focus_styles[i]);
5240}
5241
5242void
5243meta_frame_style_set_ref (MetaFrameStyleSet *style_set)
5244{
5245 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5246
5247 style_set->refcount += 1;
5248}
5249
5250void
5251meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
5252{
5253 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5254 g_return_if_fail (style_set->refcount > 0)do { if ((style_set->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set->refcount > 0"
); return; } } while (0)
;
5255
5256 style_set->refcount -= 1;
5257
5258 if (style_set->refcount == 0)
5259 {
5260 int i;
5261
5262 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5263 {
5264 free_focus_styles (style_set->normal_styles[i]);
5265 free_focus_styles (style_set->shaded_styles[i]);
5266 }
5267
5268 free_focus_styles (style_set->maximized_styles);
5269 free_focus_styles (style_set->tiled_left_styles);
5270 free_focus_styles (style_set->tiled_right_styles);
5271 free_focus_styles (style_set->maximized_and_shaded_styles);
5272 free_focus_styles (style_set->tiled_left_and_shaded_styles);
5273 free_focus_styles (style_set->tiled_right_and_shaded_styles);
5274
5275 if (style_set->parent)
5276 meta_frame_style_set_unref (style_set->parent);
5277
5278 DEBUG_FILL_STRUCT (style_set)memset ((style_set), 0xef, sizeof (*(style_set)));
5279 g_free (style_set);
5280 }
5281}
5282
5283static MetaFrameStyle*
5284get_style (MetaFrameStyleSet *style_set,
5285 MetaFrameState state,
5286 MetaFrameResize resize,
5287 MetaFrameFocus focus)
5288{
5289 MetaFrameStyle *style;
5290
5291 style = NULL((void*)0);
5292
5293 switch (state)
5294 {
5295 case META_FRAME_STATE_NORMAL:
5296 case META_FRAME_STATE_SHADED:
5297 {
5298 if (state == META_FRAME_STATE_SHADED)
5299 style = style_set->shaded_styles[resize][focus];
5300 else
5301 style = style_set->normal_styles[resize][focus];
5302
5303 /* Try parent if we failed here */
5304 if (style == NULL((void*)0) && style_set->parent)
5305 style = get_style (style_set->parent, state, resize, focus);
5306
5307 /* Allow people to omit the vert/horz/none resize modes */
5308 if (style == NULL((void*)0) &&
5309 resize != META_FRAME_RESIZE_BOTH)
5310 style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
5311 }
5312 break;
5313 default:
5314 {
5315 MetaFrameStyle **styles;
5316
5317 styles = NULL((void*)0);
5318
5319 switch (state)
5320 {
5321 case META_FRAME_STATE_MAXIMIZED:
5322 styles = style_set->maximized_styles;
5323 break;
5324 case META_FRAME_STATE_TILED_LEFT:
5325 styles = style_set->tiled_left_styles;
5326 break;
5327 case META_FRAME_STATE_TILED_RIGHT:
5328 styles = style_set->tiled_right_styles;
5329 break;
5330 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
5331 styles = style_set->maximized_and_shaded_styles;
5332 break;
5333 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
5334 styles = style_set->tiled_left_and_shaded_styles;
5335 break;
5336 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
5337 styles = style_set->tiled_right_and_shaded_styles;
5338 break;
5339 case META_FRAME_STATE_NORMAL:
5340 case META_FRAME_STATE_SHADED:
5341 case META_FRAME_STATE_LAST:
5342 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5342, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5343 break;
5344 }
5345
5346 style = styles[focus];
5347
5348 /* Tiled states are optional, try falling back to non-tiled states */
5349 if (style == NULL((void*)0))
5350 {
5351 if (state == META_FRAME_STATE_TILED_LEFT ||
5352 state == META_FRAME_STATE_TILED_RIGHT)
5353 style = get_style (style_set, META_FRAME_STATE_NORMAL,
5354 resize, focus);
5355 else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED ||
5356 state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED)
5357 style = get_style (style_set, META_FRAME_STATE_SHADED,
5358 resize, focus);
5359 }
5360
5361 /* Try parent if we failed here */
5362 if (style == NULL((void*)0) && style_set->parent)
5363 style = get_style (style_set->parent, state, resize, focus);
5364 }
5365 }
5366
5367 return style;
5368}
5369
5370static gboolean
5371check_state (MetaFrameStyleSet *style_set,
5372 MetaFrameState state,
5373 GError **error)
5374{
5375 int i;
5376
5377 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5378 {
5379 if (get_style (style_set, state,
5380 META_FRAME_RESIZE_NONE, i) == NULL((void*)0))
5381 {
5382 /* Translators: This error occurs when a <frame> tag is missing
5383 * in theme XML. The "<frame ...>" is intended as a noun phrase,
5384 * and the "missing" qualifies it. You should translate "whatever".
5385 */
5386 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5387 META_THEME_ERROR_FAILED,
5388 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5389 meta_frame_state_to_string (state),
5390 meta_frame_resize_to_string (META_FRAME_RESIZE_NONE),
5391 meta_frame_focus_to_string (i));
5392 return FALSE(0);
5393 }
5394 }
5395
5396 return TRUE(!(0));
5397}
5398
5399gboolean
5400meta_frame_style_set_validate (MetaFrameStyleSet *style_set,
5401 GError **error)
5402{
5403 int i, j;
5404
5405 g_return_val_if_fail (style_set != NULL, FALSE)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
((0)); } } while (0)
;
5406
5407 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5408 for (j = 0; j < META_FRAME_FOCUS_LAST; j++)
5409 if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL((void*)0))
5410 {
5411 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5412 META_THEME_ERROR_FAILED,
5413 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5414 meta_frame_state_to_string (META_FRAME_STATE_NORMAL),
5415 meta_frame_resize_to_string (i),
5416 meta_frame_focus_to_string (j));
5417 return FALSE(0);
5418 }
5419
5420 if (!check_state (style_set, META_FRAME_STATE_SHADED, error))
5421 return FALSE(0);
5422
5423 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error))
5424 return FALSE(0);
5425
5426 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error))
5427 return FALSE(0);
5428
5429 return TRUE(!(0));
5430}
5431
5432MetaTheme*
5433meta_theme_get_current (void)
5434{
5435 return meta_current_theme;
5436}
5437
5438void
5439meta_theme_set_current (const char *name,
5440 gboolean force_reload)
5441{
5442 MetaTheme *new_theme;
5443 GError *err;
5444
5445 meta_topicmeta_topic_real (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name);
5446
5447 if (!force_reload &&
5448 meta_current_theme &&
5449 strcmp (name, meta_current_theme->name) == 0)
5450 return;
5451
5452 err = NULL((void*)0);
5453 new_theme = meta_theme_load (name, &err);
5454
5455 if (new_theme == NULL((void*)0))
5456 {
5457 meta_warning (_("Failed to load theme \"%s\": %s\n")((char *) g_dgettext ("marco", "Failed to load theme \"%s\": %s\n"
))
,
5458 name, err->message);
5459 g_error_free (err);
5460 }
5461 else
5462 {
5463 if (meta_current_theme)
5464 meta_theme_free (meta_current_theme);
5465
5466 meta_current_theme = new_theme;
5467
5468 meta_topicmeta_topic_real (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name);
5469 }
5470}
5471
5472MetaTheme*
5473meta_theme_new (void)
5474{
5475 MetaTheme *theme;
5476
5477 theme = g_new0 (MetaTheme, 1)((MetaTheme *) g_malloc0_n ((1), sizeof (MetaTheme)));
5478
5479 theme->images_by_filename =
5480 g_hash_table_new_full (g_str_hash,
5481 g_str_equal,
5482 g_free,
5483 g_object_unref);
5484
5485 theme->layouts_by_name =
5486 g_hash_table_new_full (g_str_hash,
5487 g_str_equal,
5488 g_free,
5489 (GDestroyNotify) meta_frame_layout_unref);
5490
5491 theme->draw_op_lists_by_name =
5492 g_hash_table_new_full (g_str_hash,
5493 g_str_equal,
5494 g_free,
5495 (GDestroyNotify) meta_draw_op_list_unref);
5496
5497 theme->styles_by_name =
5498 g_hash_table_new_full (g_str_hash,
5499 g_str_equal,
5500 g_free,
5501 (GDestroyNotify) meta_frame_style_unref);
5502
5503 theme->style_sets_by_name =
5504 g_hash_table_new_full (g_str_hash,
5505 g_str_equal,
5506 g_free,
5507 (GDestroyNotify) meta_frame_style_set_unref);
5508
5509 /* Create our variable quarks so we can look up variables without
5510 having to strcmp for the names */
5511 theme->quark_width = g_quark_from_static_string ("width");
5512 theme->quark_height = g_quark_from_static_string ("height");
5513 theme->quark_object_width = g_quark_from_static_string ("object_width");
5514 theme->quark_object_height = g_quark_from_static_string ("object_height");
5515 theme->quark_left_width = g_quark_from_static_string ("left_width");
5516 theme->quark_right_width = g_quark_from_static_string ("right_width");
5517 theme->quark_top_height = g_quark_from_static_string ("top_height");
5518 theme->quark_bottom_height = g_quark_from_static_string ("bottom_height");
5519 theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width");
5520 theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height");
5521 theme->quark_icon_width = g_quark_from_static_string ("icon_width");
5522 theme->quark_icon_height = g_quark_from_static_string ("icon_height");
5523 theme->quark_title_width = g_quark_from_static_string ("title_width");
5524 theme->quark_title_height = g_quark_from_static_string ("title_height");
5525 theme->quark_frame_x_center = g_quark_from_static_string ("frame_x_center");
5526 theme->quark_frame_y_center = g_quark_from_static_string ("frame_y_center");
5527 return theme;
5528}
5529
5530void
5531meta_theme_free (MetaTheme *theme)
5532{
5533 int i;
5534
5535 g_return_if_fail (theme != NULL)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
; } } while (0)
;
5536
5537 g_free (theme->name);
5538 g_free (theme->dirname);
5539 g_free (theme->filename);
5540 g_free (theme->readable_name);
5541 g_free (theme->date);
5542 g_free (theme->description);
5543 g_free (theme->author);
5544 g_free (theme->copyright);
5545
5546 /* be more careful when destroying the theme hash tables,
5547 since they are only constructed as needed, and may be NULL. */
5548 if (theme->integer_constants)
5549 g_hash_table_destroy (theme->integer_constants);
5550 if (theme->images_by_filename)
5551 g_hash_table_destroy (theme->images_by_filename);
5552 if (theme->layouts_by_name)
5553 g_hash_table_destroy (theme->layouts_by_name);
5554 if (theme->draw_op_lists_by_name)
5555 g_hash_table_destroy (theme->draw_op_lists_by_name);
5556 if (theme->styles_by_name)
5557 g_hash_table_destroy (theme->styles_by_name);
5558 if (theme->style_sets_by_name)
5559 g_hash_table_destroy (theme->style_sets_by_name);
5560
5561 for (i = 0; i < META_FRAME_TYPE_LAST; i++)
5562 if (theme->style_sets_by_type[i])
5563 meta_frame_style_set_unref (theme->style_sets_by_type[i]);
5564
5565 DEBUG_FILL_STRUCT (theme)memset ((theme), 0xef, sizeof (*(theme)));
5566 g_free (theme);
5567}
5568
5569gboolean
5570meta_theme_validate (MetaTheme *theme,
5571 GError **error)
5572{
5573 int i;
5574
5575 g_return_val_if_fail (theme != NULL, FALSE)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
((0)); } } while (0)
;
5576
5577 /* FIXME what else should be checked? */
5578
5579 g_assert (theme->name)do { if (theme->name) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 5579, ((const char*) (__func__)), "theme->name"
); } while (0)
;
5580
5581 if (theme->readable_name == NULL((void*)0))
5582 {
5583 /* Translators: This error means that a necessary XML tag (whose name
5584 * is given in angle brackets) was not found in a given theme (whose
5585 * name is given second, in quotation marks).
5586 */
5587 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5588 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "name", theme->name);
5589 return FALSE(0);
5590 }
5591
5592 if (theme->author == NULL((void*)0))
5593 {
5594 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5595 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "author", theme->name);
5596 return FALSE(0);
5597 }
5598
5599 if (theme->date == NULL((void*)0))
5600 {
5601 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5602 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "date", theme->name);
5603 return FALSE(0);
5604 }
5605
5606 if (theme->description == NULL((void*)0))
5607 {
5608 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5609 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "description", theme->name);
5610 return FALSE(0);
5611 }
5612
5613 if (theme->copyright == NULL((void*)0))
5614 {
5615 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5616 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "copyright", theme->name);
5617 return FALSE(0);
5618 }
5619
5620 for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
5621 if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL((void*)0))
5622 {
5623 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5624 _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element")((char *) g_dgettext ("marco", "No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"
))
,
5625 meta_frame_type_to_string (i),
5626 theme->name,
5627 meta_frame_type_to_string (i));
5628
5629 return FALSE(0);
5630 }
5631
5632 return TRUE(!(0));
5633}
5634
5635GdkPixbuf*
5636meta_theme_load_image (MetaTheme *theme,
5637 const char *filename,
5638 guint size_of_theme_icons,
5639 GError **error)
5640{
5641 GdkPixbuf *pixbuf;
5642 int scale;
5643
5644 pixbuf = g_hash_table_lookup (theme->images_by_filename,
5645 filename);
5646
5647 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
5648
5649 if (pixbuf == NULL((void*)0))
5650 {
5651
5652 if (g_str_has_prefix (filename, "theme:")(__builtin_constant_p ("theme:")? __extension__ ({ const char
* const __str = (filename); const char * const __prefix = ("theme:"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (filename, "theme:") )
&&
5653 META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES)(theme->format_version >= 2))
5654 {
5655 pixbuf = gtk_icon_theme_load_icon_for_scale (
5656 gtk_icon_theme_get_default (),
5657 filename+6,
5658 size_of_theme_icons,
5659 scale,
5660 0,
5661 error);
5662 if (pixbuf == NULL((void*)0)) return NULL((void*)0);
5663 }
5664 else
5665 {
5666 char *full_path;
5667 full_path = g_build_filename (theme->dirname, filename, NULL((void*)0));
5668
5669 gint width, height;
5670
5671 if (gdk_pixbuf_get_file_info (full_path, &width, &height) == NULL((void*)0))
5672 {
5673 g_free (full_path);
5674 return NULL((void*)0);
5675 }
5676
5677 width *= scale;
5678 height *= scale;
5679
5680 pixbuf = gdk_pixbuf_new_from_file_at_size (full_path, width, height, error);
5681
5682 if (pixbuf == NULL((void*)0))
5683 {
5684 g_free (full_path);
5685 return NULL((void*)0);
5686 }
5687
5688 g_free (full_path);
5689 }
5690 g_hash_table_replace (theme->images_by_filename,
5691 g_strdup (filename)g_strdup_inline (filename),
5692 pixbuf);
5693 }
5694
5695 g_assert (pixbuf)do { if (pixbuf) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 5695, ((const char*) (__func__)), "pixbuf"); } while (0)
;
5696
5697 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
5698
5699 return pixbuf;
5700}
5701
5702static MetaFrameStyle*
5703theme_get_style (MetaTheme *theme,
5704 MetaFrameType type,
5705 MetaFrameFlags flags)
5706{
5707 MetaFrameState state;
5708 MetaFrameResize resize;
5709 MetaFrameFocus focus;
5710 MetaFrameStyle *style;
5711 MetaFrameStyleSet *style_set;
5712
5713 style_set = theme->style_sets_by_type[type];
5714
5715 if (style_set == NULL((void*)0) && type == META_FRAME_TYPE_ATTACHED)
5716 style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER];
5717
5718 /* Right now the parser forces a style set for all other types,
5719 * but this fallback code is here in case I take that out.
5720 */
5721 if (style_set == NULL((void*)0))
5722 style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL];
5723 if (style_set == NULL((void*)0))
5724 return NULL((void*)0);
5725
5726 switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT))
5727 {
5728 case 0:
5729 state = META_FRAME_STATE_NORMAL;
5730 break;
5731 case META_FRAME_MAXIMIZED:
5732 state = META_FRAME_STATE_MAXIMIZED;
5733 break;
5734 case META_FRAME_TILED_LEFT:
5735 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_LEFT):
5736 state = META_FRAME_STATE_TILED_LEFT;
5737 break;
5738 case META_FRAME_TILED_RIGHT:
5739 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_RIGHT):
5740 state = META_FRAME_STATE_TILED_RIGHT;
5741 break;
5742 case META_FRAME_SHADED:
5743 state = META_FRAME_STATE_SHADED;
5744 break;
5745 case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
5746 state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
5747 break;
5748 case (META_FRAME_TILED_LEFT | META_FRAME_SHADED):
5749 state = META_FRAME_STATE_TILED_LEFT_AND_SHADED;
5750 break;
5751 case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED):
5752 state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
5753 break;
5754 default:
5755 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5755, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5756 state = META_FRAME_STATE_LAST; /* compiler */
5757 break;
5758 }
5759
5760 switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
5761 {
5762 case 0:
5763 resize = META_FRAME_RESIZE_NONE;
5764 break;
5765 case META_FRAME_ALLOWS_VERTICAL_RESIZE:
5766 resize = META_FRAME_RESIZE_VERTICAL;
5767 break;
5768 case META_FRAME_ALLOWS_HORIZONTAL_RESIZE:
5769 resize = META_FRAME_RESIZE_HORIZONTAL;
5770 break;
5771 case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE):
5772 resize = META_FRAME_RESIZE_BOTH;
5773 break;
5774 default:
5775 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5775, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5776 resize = META_FRAME_RESIZE_LAST; /* compiler */
5777 break;
5778 }
5779
5780 /* re invert the styles used for focus/unfocussed while flashing a frame */
5781 if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
5782 || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
5783 focus = META_FRAME_FOCUS_YES;
5784 else
5785 focus = META_FRAME_FOCUS_NO;
5786
5787 style = get_style (style_set, state, resize, focus);
5788
5789 return style;
5790}
5791
5792MetaFrameStyle*
5793meta_theme_get_frame_style (MetaTheme *theme,
5794 MetaFrameType type,
5795 MetaFrameFlags flags)
5796{
5797 MetaFrameStyle *style;
5798
5799 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (((void*)0)); } } while (0)
;
5800
5801 style = theme_get_style (theme, type, flags);
5802
5803 return style;
5804}
5805
5806double
5807meta_theme_get_title_scale (MetaTheme *theme,
5808 MetaFrameType type,
5809 MetaFrameFlags flags)
5810{
5811 MetaFrameStyle *style;
5812
5813 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (1.0); } } while (0)
;
5814
5815 style = theme_get_style (theme, type, flags);
5816
5817 /* Parser is not supposed to allow this currently */
5818 if (style == NULL((void*)0))
5819 return 1.0;
5820
5821 return style->layout->title_scale;
5822}
5823
5824void
5825meta_theme_draw_frame (MetaTheme *theme,
5826 GtkStyleContext *style_gtk,
5827 cairo_t *cr,
5828 MetaFrameType type,
5829 MetaFrameFlags flags,
5830 int client_width,
5831 int client_height,
5832 PangoLayout *title_layout,
5833 int text_height,
5834 const MetaButtonLayout *button_layout,
5835 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5836 GdkPixbuf *mini_icon,
5837 GdkPixbuf *icon)
5838{
5839 MetaFrameGeometry fgeom;
5840 MetaFrameStyle *style;
5841
5842 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5843
5844 style = theme_get_style (theme, type, flags);
5845
5846 /* Parser is not supposed to allow this currently */
5847 if (style == NULL((void*)0))
5848 return;
5849
5850 meta_frame_layout_calc_geometry (style->layout,
5851 text_height,
5852 flags,
5853 client_width, client_height,
5854 button_layout,
5855 &fgeom,
5856 theme);
5857
5858 meta_frame_style_draw_with_style (style,
5859 style_gtk,
5860 cr,
5861 &fgeom,
5862 client_width, client_height,
5863 title_layout,
5864 text_height,
5865 button_states,
5866 mini_icon, icon);
5867}
5868
5869void
5870meta_theme_draw_frame_by_name (MetaTheme *theme,
5871 GtkWidget *widget,
5872 cairo_t *cr,
5873 const gchar *style_name,
5874 MetaFrameFlags flags,
5875 int client_width,
5876 int client_height,
5877 PangoLayout *title_layout,
5878 int text_height,
5879 const MetaButtonLayout *button_layout,
5880 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5881 GdkPixbuf *mini_icon,
5882 GdkPixbuf *icon)
5883{
5884 MetaFrameGeometry fgeom;
5885 MetaFrameStyle *style;
5886
5887 style = meta_theme_lookup_style (theme, style_name);
5888
5889 /* Parser is not supposed to allow this currently */
5890 if (style == NULL((void*)0))
5891 return;
5892
5893 meta_frame_layout_calc_geometry (style->layout,
5894 text_height,
5895 flags,
5896 client_width, client_height,
5897 button_layout,
5898 &fgeom,
5899 theme);
5900
5901 meta_frame_style_draw (style,
5902 widget,
5903 cr,
5904 &fgeom,
5905 client_width, client_height,
5906 title_layout,
5907 text_height,
5908 button_states,
5909 mini_icon, icon);
5910}
5911
5912void
5913meta_theme_get_frame_borders (MetaTheme *theme,
5914 MetaFrameType type,
5915 int text_height,
5916 MetaFrameFlags flags,
5917 MetaFrameBorders *borders)
5918{
5919 MetaFrameStyle *style;
5920
5921 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5922
5923 style = theme_get_style (theme, type, flags);
5924
5925 meta_frame_borders_clear (borders);
5926
5927 /* Parser is not supposed to allow this currently */
5928 if (style == NULL((void*)0))
5929 return;
5930
5931 meta_frame_layout_get_borders (style->layout,
5932 text_height,
5933 flags,
5934 borders);
5935}
5936
5937void
5938meta_theme_calc_geometry (MetaTheme *theme,
5939 MetaFrameType type,
5940 int text_height,
5941 MetaFrameFlags flags,
5942 int client_width,
5943 int client_height,
5944 const MetaButtonLayout *button_layout,
5945 MetaFrameGeometry *fgeom)
5946{
5947 MetaFrameStyle *style;
5948
5949 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5950
5951 style = theme_get_style (theme, type, flags);
5952
5953 /* Parser is not supposed to allow this currently */
5954 if (style == NULL((void*)0))
5955 return;
5956
5957 meta_frame_layout_calc_geometry (style->layout,
5958 text_height,
5959 flags,
5960 client_width, client_height,
5961 button_layout,
5962 fgeom,
5963 theme);
5964}
5965
5966MetaFrameLayout*
5967meta_theme_lookup_layout (MetaTheme *theme,
5968 const char *name)
5969{
5970 return g_hash_table_lookup (theme->layouts_by_name, name);
5971}
5972
5973void
5974meta_theme_insert_layout (MetaTheme *theme,
5975 const char *name,
5976 MetaFrameLayout *layout)
5977{
5978 meta_frame_layout_ref (layout);
5979 g_hash_table_replace (theme->layouts_by_name, g_strdup (name)g_strdup_inline (name), layout);
5980}
5981
5982MetaDrawOpList*
5983meta_theme_lookup_draw_op_list (MetaTheme *theme,
5984 const char *name)
5985{
5986 return g_hash_table_lookup (theme->draw_op_lists_by_name, name);
5987}
5988
5989void
5990meta_theme_insert_draw_op_list (MetaTheme *theme,
5991 const char *name,
5992 MetaDrawOpList *op_list)
5993{
5994 meta_draw_op_list_ref (op_list);
5995 g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name)g_strdup_inline (name), op_list);
5996}
5997
5998MetaFrameStyle*
5999meta_theme_lookup_style (MetaTheme *theme,
6000 const char *name)
6001{
6002 return g_hash_table_lookup (theme->styles_by_name, name);
6003}
6004
6005void
6006meta_theme_insert_style (MetaTheme *theme,
6007 const char *name,
6008 MetaFrameStyle *style)
6009{
6010 meta_frame_style_ref (style);
6011 g_hash_table_replace (theme->styles_by_name, g_strdup (name)g_strdup_inline (name), style);
6012}
6013
6014MetaFrameStyleSet*
6015meta_theme_lookup_style_set (MetaTheme *theme,
6016 const char *name)
6017{
6018 return g_hash_table_lookup (theme->style_sets_by_name, name);
6019}
6020
6021void
6022meta_theme_insert_style_set (MetaTheme *theme,
6023 const char *name,
6024 MetaFrameStyleSet *style_set)
6025{
6026 meta_frame_style_set_ref (style_set);
6027 g_hash_table_replace (theme->style_sets_by_name, g_strdup (name)g_strdup_inline (name), style_set);
6028}
6029
6030static gboolean
6031first_uppercase (const char *str)
6032{
6033 return g_ascii_isupper (*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_UPPER) != 0);
6034}
6035
6036gboolean
6037meta_theme_define_int_constant (MetaTheme *theme,
6038 const char *name,
6039 int value,
6040 GError **error)
6041{
6042 if (theme->integer_constants == NULL((void*)0))
6043 theme->integer_constants = g_hash_table_new_full (g_str_hash,
6044 g_str_equal,
6045 g_free,
6046 NULL((void*)0));
6047
6048 if (!first_uppercase (name))
6049 {
6050 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6051 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6052 name);
6053 return FALSE(0);
6054 }
6055
6056 if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL((void*)0), NULL((void*)0)))
6057 {
6058 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6059 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6060 name);
6061
6062 return FALSE(0);
6063 }
6064
6065 g_hash_table_insert (theme->integer_constants,
6066 g_strdup (name)g_strdup_inline (name),
6067 GINT_TO_POINTER (value)((gpointer) (glong) (value)));
6068
6069 return TRUE(!(0));
6070}
6071
6072gboolean
6073meta_theme_lookup_int_constant (MetaTheme *theme,
6074 const char *name,
6075 int *value)
6076{
6077 gpointer old_value;
6078
6079 *value = 0;
6080
6081 if (theme->integer_constants == NULL((void*)0))
6082 return FALSE(0);
6083
6084 if (g_hash_table_lookup_extended (theme->integer_constants,
6085 name, NULL((void*)0), &old_value))
6086 {
6087 *value = GPOINTER_TO_INT (old_value)((gint) (glong) (old_value));
6088 return TRUE(!(0));
6089 }
6090 else
6091 {
6092 return FALSE(0);
6093 }
6094}
6095
6096gboolean
6097meta_theme_define_float_constant (MetaTheme *theme,
6098 const char *name,
6099 double value,
6100 GError **error)
6101{
6102 double *d;
6103
6104 if (theme->float_constants == NULL((void*)0))
6105 theme->float_constants = g_hash_table_new_full (g_str_hash,
6106 g_str_equal,
6107 g_free,
6108 g_free);
6109
6110 if (!first_uppercase (name))
6111 {
6112 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6113 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6114 name);
6115 return FALSE(0);
6116 }
6117
6118 if (g_hash_table_lookup_extended (theme->float_constants, name, NULL((void*)0), NULL((void*)0)))
6119 {
6120 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6121 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6122 name);
6123
6124 return FALSE(0);
6125 }
6126
6127 d = g_new (double, 1)((double *) g_malloc_n ((1), sizeof (double)));
6128 *d = value;
6129
6130 g_hash_table_insert (theme->float_constants,
6131 g_strdup (name)g_strdup_inline (name), d);
6132
6133 return TRUE(!(0));
6134}
6135
6136gboolean
6137meta_theme_lookup_float_constant (MetaTheme *theme,
6138 const char *name,
6139 double *value)
6140{
6141 double *d;
6142
6143 *value = 0.0;
6144
6145 if (theme->float_constants == NULL((void*)0))
6146 return FALSE(0);
6147
6148 d = g_hash_table_lookup (theme->float_constants, name);
6149
6150 if (d)
6151 {
6152 *value = *d;
6153 return TRUE(!(0));
6154 }
6155 else
6156 {
6157 return FALSE(0);
6158 }
6159}
6160
6161gboolean
6162meta_theme_define_color_constant (MetaTheme *theme,
6163 const char *name,
6164 const char *value,
6165 GError **error)
6166{
6167 if (theme->color_constants == NULL((void*)0))
6168 theme->color_constants = g_hash_table_new_full (g_str_hash,
6169 g_str_equal,
6170 g_free,
6171 NULL((void*)0));
6172
6173 if (!first_uppercase (name))
6174 {
6175 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6176 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6177 name);
6178 return FALSE(0);
6179 }
6180
6181 if (g_hash_table_lookup_extended (theme->color_constants, name, NULL((void*)0), NULL((void*)0)))
6182 {
6183 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6184 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6185 name);
6186
6187 return FALSE(0);
6188 }
6189
6190 g_hash_table_insert (theme->color_constants,
6191 g_strdup (name)g_strdup_inline (name),
6192 g_strdup (value)g_strdup_inline (value));
6193
6194 return TRUE(!(0));
6195}
6196
6197/**
6198 * Looks up a colour constant.
6199 *
6200 * \param theme the theme containing the constant
6201 * \param name the name of the constant
6202 * \param value [out] the string representation of the colour, or NULL if it
6203 * doesn't exist
6204 * \return TRUE if it exists, FALSE otherwise
6205 */
6206gboolean
6207meta_theme_lookup_color_constant (MetaTheme *theme,
6208 const char *name,
6209 char **value)
6210{
6211 char *result;
6212
6213 *value = NULL((void*)0);
6214
6215 if (theme->color_constants == NULL((void*)0))
6216 return FALSE(0);
6217
6218 result = g_hash_table_lookup (theme->color_constants, name);
6219
6220 if (result)
6221 {
6222 *value = result;
6223 return TRUE(!(0));
6224 }
6225 else
6226 {
6227 return FALSE(0);
6228 }
6229}
6230
6231PangoFontDescription*
6232meta_gtk_widget_get_font_desc (GtkWidget *widget,
6233 double scale,
6234 const PangoFontDescription *override)
6235{
6236 PangoFontDescription *font_desc;
6237 gint font_size;
6238
6239 GtkStyleContext *style = gtk_widget_get_style_context (widget);
6240 GtkStateFlags state = gtk_widget_get_state_flags (widget);
6241 gtk_style_context_get(style, state, GTK_STYLE_PROPERTY_FONT"font", &font_desc, NULL((void*)0));
6242
6243 if (override)
6244 pango_font_description_merge (font_desc, override, TRUE(!(0)));
6245
6246 font_size = pango_font_description_get_size (font_desc);
6247 pango_font_description_set_size (font_desc,
6248 MAX ((gint) (scale * (double) font_size), 1)((((gint) (scale * (double) font_size)) > (1)) ? ((gint) (
scale * (double) font_size)) : (1))
);
6249
6250 return font_desc;
6251}
6252
6253/**
6254 * Returns the height of the letters in a particular font.
6255 *
6256 * \param font_desc the font
6257 * \param context the context of the font
6258 * \return the height of the letters
6259 */
6260int
6261meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
6262 PangoContext *context)
6263{
6264 PangoFontMetrics *metrics;
6265 PangoLanguage *lang;
6266 int retval;
6267
6268 lang = pango_context_get_language (context);
6269 metrics = pango_context_get_metrics (context, font_desc, lang);
6270
6271 retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
6272 pango_font_metrics_get_descent (metrics))(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
;
6273
6274 pango_font_metrics_unref (metrics);
6275
6276 return retval;
6277}
6278
6279MetaGtkColorComponent
6280meta_color_component_from_string (const char *str)
6281{
6282 if (strcmp ("fg", str) == 0)
6283 return META_GTK_COLOR_FG;
6284 else if (strcmp ("bg", str) == 0)
6285 return META_GTK_COLOR_BG;
6286 else if (strcmp ("light", str) == 0)
6287 return META_GTK_COLOR_LIGHT;
6288 else if (strcmp ("dark", str) == 0)
6289 return META_GTK_COLOR_DARK;
6290 else if (strcmp ("mid", str) == 0)
6291 return META_GTK_COLOR_MID;
6292 else if (strcmp ("text", str) == 0)
6293 return META_GTK_COLOR_TEXT;
6294 else if (strcmp ("base", str) == 0)
6295 return META_GTK_COLOR_BASE;
6296 else if (strcmp ("text_aa", str) == 0)
6297 return META_GTK_COLOR_TEXT_AA;
6298 else
6299 return META_GTK_COLOR_LAST;
6300}
6301
6302const char*
6303meta_color_component_to_string (MetaGtkColorComponent component)
6304{
6305 switch (component)
6306 {
6307 case META_GTK_COLOR_FG:
6308 return "fg";
6309 case META_GTK_COLOR_BG:
6310 return "bg";
6311 case META_GTK_COLOR_LIGHT:
6312 return "light";
6313 case META_GTK_COLOR_DARK:
6314 return "dark";
6315 case META_GTK_COLOR_MID:
6316 return "mid";
6317 case META_GTK_COLOR_TEXT:
6318 return "text";
6319 case META_GTK_COLOR_BASE:
6320 return "base";
6321 case META_GTK_COLOR_TEXT_AA:
6322 return "text_aa";
6323 case META_GTK_COLOR_LAST:
6324 break;
6325 }
6326
6327 return "<unknown>";
6328}
6329
6330MetaButtonState
6331meta_button_state_from_string (const char *str)
6332{
6333 if (strcmp ("normal", str) == 0)
6334 return META_BUTTON_STATE_NORMAL;
6335 else if (strcmp ("pressed", str) == 0)
6336 return META_BUTTON_STATE_PRESSED;
6337 else if (strcmp ("prelight", str) == 0)
6338 return META_BUTTON_STATE_PRELIGHT;
6339 else
6340 return META_BUTTON_STATE_LAST;
6341}
6342
6343const char*
6344meta_button_state_to_string (MetaButtonState state)
6345{
6346 switch (state)
6347 {
6348 case META_BUTTON_STATE_NORMAL:
6349 return "normal";
6350 case META_BUTTON_STATE_PRESSED:
6351 return "pressed";
6352 case META_BUTTON_STATE_PRELIGHT:
6353 return "prelight";
6354 case META_BUTTON_STATE_LAST:
6355 break;
6356 }
6357
6358 return "<unknown>";
6359}
6360
6361MetaButtonType
6362meta_button_type_from_string (const char *str, MetaTheme *theme)
6363{
6364 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
6365 {
6366 if (strcmp ("shade", str) == 0)
6367 return META_BUTTON_TYPE_SHADE;
6368 else if (strcmp ("above", str) == 0)
6369 return META_BUTTON_TYPE_ABOVE;
6370 else if (strcmp ("stick", str) == 0)
6371 return META_BUTTON_TYPE_STICK;
6372 else if (strcmp ("unshade", str) == 0)
6373 return META_BUTTON_TYPE_UNSHADE;
6374 else if (strcmp ("unabove", str) == 0)
6375 return META_BUTTON_TYPE_UNABOVE;
6376 else if (strcmp ("unstick", str) == 0)
6377 return META_BUTTON_TYPE_UNSTICK;
6378 }
6379
6380 if (strcmp ("close", str) == 0)
6381 return META_BUTTON_TYPE_CLOSE;
6382 else if (strcmp ("maximize", str) == 0)
6383 return META_BUTTON_TYPE_MAXIMIZE;
6384 else if (strcmp ("minimize", str) == 0)
6385 return META_BUTTON_TYPE_MINIMIZE;
6386 else if (strcmp ("menu", str) == 0)
6387 return META_BUTTON_TYPE_MENU;
6388 else if (strcmp ("appmenu", str) == 0)
6389 return META_BUTTON_TYPE_APPMENU;
6390 else if (strcmp ("left_left_background", str) == 0)
6391 return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
6392 else if (strcmp ("left_middle_background", str) == 0)
6393 return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
6394 else if (strcmp ("left_right_background", str) == 0)
6395 return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
6396 else if (strcmp ("left_single_background", str) == 0)
6397 return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND;
6398 else if (strcmp ("right_left_background", str) == 0)
6399 return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
6400 else if (strcmp ("right_middle_background", str) == 0)
6401 return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
6402 else if (strcmp ("right_right_background", str) == 0)
6403 return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
6404 else if (strcmp ("right_single_background", str) == 0)
6405 return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND;
6406 else
6407 return META_BUTTON_TYPE_LAST;
6408}
6409
6410const char*
6411meta_button_type_to_string (MetaButtonType type)
6412{
6413 switch (type)
6414 {
6415 case META_BUTTON_TYPE_CLOSE:
6416 return "close";
6417 case META_BUTTON_TYPE_MAXIMIZE:
6418 return "maximize";
6419 case META_BUTTON_TYPE_MINIMIZE:
6420 return "minimize";
6421 case META_BUTTON_TYPE_SHADE:
6422 return "shade";
6423 case META_BUTTON_TYPE_ABOVE:
6424 return "above";
6425 case META_BUTTON_TYPE_STICK:
6426 return "stick";
6427 case META_BUTTON_TYPE_UNSHADE:
6428 return "unshade";
6429 case META_BUTTON_TYPE_UNABOVE:
6430 return "unabove";
6431 case META_BUTTON_TYPE_UNSTICK:
6432 return "unstick";
6433 case META_BUTTON_TYPE_MENU:
6434 return "menu";
6435 case META_BUTTON_TYPE_APPMENU:
6436 return "appmenu";
6437 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
6438 return "left_left_background";
6439 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
6440 return "left_middle_background";
6441 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
6442 return "left_right_background";
6443 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
6444 return "left_single_background";
6445 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
6446 return "right_left_background";
6447 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
6448 return "right_middle_background";
6449 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
6450 return "right_right_background";
6451 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
6452 return "right_single_background";
6453 case META_BUTTON_TYPE_LAST:
6454 break;
6455 }
6456
6457 return "<unknown>";
6458}
6459
6460MetaFramePiece
6461meta_frame_piece_from_string (const char *str)
6462{
6463 if (strcmp ("entire_background", str) == 0)
6464 return META_FRAME_PIECE_ENTIRE_BACKGROUND;
6465 else if (strcmp ("titlebar", str) == 0)
6466 return META_FRAME_PIECE_TITLEBAR;
6467 else if (strcmp ("titlebar_middle", str) == 0)
6468 return META_FRAME_PIECE_TITLEBAR_MIDDLE;
6469 else if (strcmp ("left_titlebar_edge", str) == 0)
6470 return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE;
6471 else if (strcmp ("right_titlebar_edge", str) == 0)
6472 return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE;
6473 else if (strcmp ("top_titlebar_edge", str) == 0)
6474 return META_FRAME_PIECE_TOP_TITLEBAR_EDGE;
6475 else if (strcmp ("bottom_titlebar_edge", str) == 0)
6476 return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE;
6477 else if (strcmp ("title", str) == 0)
6478 return META_FRAME_PIECE_TITLE;
6479 else if (strcmp ("left_edge", str) == 0)
6480 return META_FRAME_PIECE_LEFT_EDGE;
6481 else if (strcmp ("right_edge", str) == 0)
6482 return META_FRAME_PIECE_RIGHT_EDGE;
6483 else if (strcmp ("bottom_edge", str) == 0)
6484 return META_FRAME_PIECE_BOTTOM_EDGE;
6485 else if (strcmp ("overlay", str) == 0)
6486 return META_FRAME_PIECE_OVERLAY;
6487 else
6488 return META_FRAME_PIECE_LAST;
6489}
6490
6491const char*
6492meta_frame_piece_to_string (MetaFramePiece piece)
6493{
6494 switch (piece)
6495 {
6496 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
6497 return "entire_background";
6498 case META_FRAME_PIECE_TITLEBAR:
6499 return "titlebar";
6500 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
6501 return "titlebar_middle";
6502 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
6503 return "left_titlebar_edge";
6504 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
6505 return "right_titlebar_edge";
6506 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
6507 return "top_titlebar_edge";
6508 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
6509 return "bottom_titlebar_edge";
6510 case META_FRAME_PIECE_TITLE:
6511 return "title";
6512 case META_FRAME_PIECE_LEFT_EDGE:
6513 return "left_edge";
6514 case META_FRAME_PIECE_RIGHT_EDGE:
6515 return "right_edge";
6516 case META_FRAME_PIECE_BOTTOM_EDGE:
6517 return "bottom_edge";
6518 case META_FRAME_PIECE_OVERLAY:
6519 return "overlay";
6520 case META_FRAME_PIECE_LAST:
6521 break;
6522 }
6523
6524 return "<unknown>";
6525}
6526
6527MetaFrameState
6528meta_frame_state_from_string (const char *str)
6529{
6530 if (strcmp ("normal", str) == 0)
6531 return META_FRAME_STATE_NORMAL;
6532 else if (strcmp ("maximized", str) == 0)
6533 return META_FRAME_STATE_MAXIMIZED;
6534 else if (strcmp ("tiled_left", str) == 0)
6535 return META_FRAME_STATE_TILED_LEFT;
6536 else if (strcmp ("tiled_right", str) == 0)
6537 return META_FRAME_STATE_TILED_RIGHT;
6538 else if (strcmp ("shaded", str) == 0)
6539 return META_FRAME_STATE_SHADED;
6540 else if (strcmp ("maximized_and_shaded", str) == 0)
6541 return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
6542 else if (strcmp ("tiled_left_and_shaded", str) == 0)
6543 return META_FRAME_STATE_TILED_LEFT_AND_SHADED;
6544 else if (strcmp ("tiled_right_and_shaded", str) == 0)
6545 return META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
6546 else
6547 return META_FRAME_STATE_LAST;
6548}
6549
6550const char*
6551meta_frame_state_to_string (MetaFrameState state)
6552{
6553 switch (state)
6554 {
6555 case META_FRAME_STATE_NORMAL:
6556 return "normal";
6557 case META_FRAME_STATE_MAXIMIZED:
6558 return "maximized";
6559 case META_FRAME_STATE_TILED_LEFT:
6560 return "tiled_left";
6561 case META_FRAME_STATE_TILED_RIGHT:
6562 return "tiled_right";
6563 case META_FRAME_STATE_SHADED:
6564 return "shaded";
6565 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
6566 return "maximized_and_shaded";
6567 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
6568 return "tiled_left_and_shaded";
6569 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
6570 return "tiled_right_and_shaded";
6571 case META_FRAME_STATE_LAST:
6572 break;
6573 }
6574
6575 return "<unknown>";
6576}
6577
6578MetaFrameResize
6579meta_frame_resize_from_string (const char *str)
6580{
6581 if (strcmp ("none", str) == 0)
6582 return META_FRAME_RESIZE_NONE;
6583 else if (strcmp ("vertical", str) == 0)
6584 return META_FRAME_RESIZE_VERTICAL;
6585 else if (strcmp ("horizontal", str) == 0)
6586 return META_FRAME_RESIZE_HORIZONTAL;
6587 else if (strcmp ("both", str) == 0)
6588 return META_FRAME_RESIZE_BOTH;
6589 else
6590 return META_FRAME_RESIZE_LAST;
6591}
6592
6593const char*
6594meta_frame_resize_to_string (MetaFrameResize resize)
6595{
6596 switch (resize)
6597 {
6598 case META_FRAME_RESIZE_NONE:
6599 return "none";
6600 case META_FRAME_RESIZE_VERTICAL:
6601 return "vertical";
6602 case META_FRAME_RESIZE_HORIZONTAL:
6603 return "horizontal";
6604 case META_FRAME_RESIZE_BOTH:
6605 return "both";
6606 case META_FRAME_RESIZE_LAST:
6607 break;
6608 }
6609
6610 return "<unknown>";
6611}
6612
6613MetaFrameFocus
6614meta_frame_focus_from_string (const char *str)
6615{
6616 if (strcmp ("no", str) == 0)
6617 return META_FRAME_FOCUS_NO;
6618 else if (strcmp ("yes", str) == 0)
6619 return META_FRAME_FOCUS_YES;
6620 else
6621 return META_FRAME_FOCUS_LAST;
6622}
6623
6624const char*
6625meta_frame_focus_to_string (MetaFrameFocus focus)
6626{
6627 switch (focus)
6628 {
6629 case META_FRAME_FOCUS_NO:
6630 return "no";
6631 case META_FRAME_FOCUS_YES:
6632 return "yes";
6633 case META_FRAME_FOCUS_LAST:
6634 break;
6635 }
6636
6637 return "<unknown>";
6638}
6639
6640MetaFrameType
6641meta_frame_type_from_string (const char *str)
6642{
6643 if (strcmp ("normal", str) == 0)
6644 return META_FRAME_TYPE_NORMAL;
6645 else if (strcmp ("dialog", str) == 0)
6646 return META_FRAME_TYPE_DIALOG;
6647 else if (strcmp ("modal_dialog", str) == 0)
6648 return META_FRAME_TYPE_MODAL_DIALOG;
6649 else if (strcmp ("utility", str) == 0)
6650 return META_FRAME_TYPE_UTILITY;
6651 else if (strcmp ("menu", str) == 0)
6652 return META_FRAME_TYPE_MENU;
6653 else if (strcmp ("border", str) == 0)
6654 return META_FRAME_TYPE_BORDER;
6655 else if (strcmp ("attached", str) == 0)
6656 return META_FRAME_TYPE_ATTACHED;
6657#if 0
6658 else if (strcmp ("toolbar", str) == 0)
6659 return META_FRAME_TYPE_TOOLBAR;
6660#endif
6661 else
6662 return META_FRAME_TYPE_LAST;
6663}
6664
6665const char*
6666meta_frame_type_to_string (MetaFrameType type)
6667{
6668 switch (type)
6669 {
6670 case META_FRAME_TYPE_NORMAL:
6671 return "normal";
6672 case META_FRAME_TYPE_DIALOG:
6673 return "dialog";
6674 case META_FRAME_TYPE_MODAL_DIALOG:
6675 return "modal_dialog";
6676 case META_FRAME_TYPE_UTILITY:
6677 return "utility";
6678 case META_FRAME_TYPE_MENU:
6679 return "menu";
6680 case META_FRAME_TYPE_BORDER:
6681 return "border";
6682 case META_FRAME_TYPE_ATTACHED:
6683 return "attached";
6684#if 0
6685 case META_FRAME_TYPE_TOOLBAR:
6686 return "toolbar";
6687#endif
6688 case META_FRAME_TYPE_LAST:
6689 break;
6690 }
6691
6692 return "<unknown>";
6693}
6694
6695MetaGradientType
6696meta_gradient_type_from_string (const char *str)
6697{
6698 if (strcmp ("vertical", str) == 0)
6699 return META_GRADIENT_VERTICAL;
6700 else if (strcmp ("horizontal", str) == 0)
6701 return META_GRADIENT_HORIZONTAL;
6702 else if (strcmp ("diagonal", str) == 0)
6703 return META_GRADIENT_DIAGONAL;
6704 else
6705 return META_GRADIENT_LAST;
6706}
6707
6708const char*
6709meta_gradient_type_to_string (MetaGradientType type)
6710{
6711 switch (type)
6712 {
6713 case META_GRADIENT_VERTICAL:
6714 return "vertical";
6715 case META_GRADIENT_HORIZONTAL:
6716 return "horizontal";
6717 case META_GRADIENT_DIAGONAL:
6718 return "diagonal";
6719 case META_GRADIENT_LAST:
6720 break;
6721 }
6722
6723 return "<unknown>";
6724}
6725
6726GtkStateFlags
6727meta_gtk_state_from_string (const char *str)
6728{
6729 if (g_ascii_strcasecmp ("normal", str) == 0)
6730 return GTK_STATE_FLAG_NORMAL;
6731 else if (g_ascii_strcasecmp ("prelight", str) == 0)
6732 return GTK_STATE_FLAG_PRELIGHT;
6733 else if (g_ascii_strcasecmp ("active", str) == 0)
6734 return GTK_STATE_FLAG_ACTIVE;
6735 else if (g_ascii_strcasecmp ("selected", str) == 0)
6736 return GTK_STATE_FLAG_SELECTED;
6737 else if (g_ascii_strcasecmp ("insensitive", str) == 0)
6738 return GTK_STATE_FLAG_INSENSITIVE;
6739 else if (g_ascii_strcasecmp ("inconsistent", str) == 0)
6740 return GTK_STATE_FLAG_INCONSISTENT;
6741 else if (g_ascii_strcasecmp ("focused", str) == 0)
6742 return GTK_STATE_FLAG_FOCUSED;
6743 else if (g_ascii_strcasecmp ("backdrop", str) == 0)
6744 return GTK_STATE_FLAG_BACKDROP;
6745 else
6746 return -1; /* hack */
6747}
6748
6749GtkShadowType
6750meta_gtk_shadow_from_string (const char *str)
6751{
6752 if (strcmp ("none", str) == 0)
6753 return GTK_SHADOW_NONE;
6754 else if (strcmp ("in", str) == 0)
6755 return GTK_SHADOW_IN;
6756 else if (strcmp ("out", str) == 0)
6757 return GTK_SHADOW_OUT;
6758 else if (strcmp ("etched_in", str) == 0)
6759 return GTK_SHADOW_ETCHED_IN;
6760 else if (strcmp ("etched_out", str) == 0)
6761 return GTK_SHADOW_ETCHED_OUT;
6762 else
6763 return -1;
6764}
6765
6766const char*
6767meta_gtk_shadow_to_string (GtkShadowType shadow)
6768{
6769 switch (shadow)
6770 {
6771 case GTK_SHADOW_NONE:
6772 return "none";
6773 case GTK_SHADOW_IN:
6774 return "in";
6775 case GTK_SHADOW_OUT:
6776 return "out";
6777 case GTK_SHADOW_ETCHED_IN:
6778 return "etched_in";
6779 case GTK_SHADOW_ETCHED_OUT:
6780 return "etched_out";
6781 }
6782
6783 return "<unknown>";
6784}
6785
6786GtkArrowType
6787meta_gtk_arrow_from_string (const char *str)
6788{
6789 if (strcmp ("up", str) == 0)
6790 return GTK_ARROW_UP;
6791 else if (strcmp ("down", str) == 0)
6792 return GTK_ARROW_DOWN;
6793 else if (strcmp ("left", str) == 0)
6794 return GTK_ARROW_LEFT;
6795 else if (strcmp ("right", str) == 0)
6796 return GTK_ARROW_RIGHT;
6797 else if (strcmp ("none", str) == 0)
6798 return GTK_ARROW_NONE;
6799 else
6800 return -1;
6801}
6802
6803const char*
6804meta_gtk_arrow_to_string (GtkArrowType arrow)
6805{
6806 switch (arrow)
6807 {
6808 case GTK_ARROW_UP:
6809 return "up";
6810 case GTK_ARROW_DOWN:
6811 return "down";
6812 case GTK_ARROW_LEFT:
6813 return "left";
6814 case GTK_ARROW_RIGHT:
6815 return "right";
6816 case GTK_ARROW_NONE:
6817 return "none";
6818 }
6819
6820 return "<unknown>";
6821}
6822
6823/**
6824 * Returns a fill_type from a string. The inverse of
6825 * meta_image_fill_type_to_string().
6826 *
6827 * \param str a string representing a fill_type
6828 * \result the fill_type, or -1 if it represents no fill_type.
6829 */
6830MetaImageFillType
6831meta_image_fill_type_from_string (const char *str)
6832{
6833 if (strcmp ("tile", str) == 0)
6834 return META_IMAGE_FILL_TILE;
6835 else if (strcmp ("scale", str) == 0)
6836 return META_IMAGE_FILL_SCALE;
6837 else
6838 return -1;
6839}
6840
6841/**
6842 * Returns a string representation of a fill_type. The inverse of
6843 * meta_image_fill_type_from_string().
6844 *
6845 * \param fill_type the fill type
6846 * \result a string representing that type
6847 */
6848const char*
6849meta_image_fill_type_to_string (MetaImageFillType fill_type)
6850{
6851 switch (fill_type)
6852 {
6853 case META_IMAGE_FILL_TILE:
6854 return "tile";
6855 case META_IMAGE_FILL_SCALE:
6856 return "scale";
6857 }
6858
6859 return "<unknown>";
6860}
6861
6862/**
6863 * Takes a colour "a", scales the lightness and saturation by a certain amount,
6864 * and sets "b" to the resulting colour.
6865 * gtkstyle.c cut-and-pastage.
6866 *
6867 * \param a the starting colour
6868 * \param b [out] the resulting colour
6869 * \param k amount to scale lightness and saturation by
6870 */
6871static void
6872gtk_style_shade (GdkRGBA *a,
6873 GdkRGBA *b,
6874 gdouble k)
6875{
6876 gdouble red;
6877 gdouble green;
6878 gdouble blue;
6879
6880 red = a->red;
6881 green = a->green;
6882 blue = a->blue;
6883
6884 rgb_to_hls (&red, &green, &blue);
6885
6886 green *= k;
6887 if (green > 1.0)
6888 green = 1.0;
6889 else if (green < 0.0)
6890 green = 0.0;
6891
6892 blue *= k;
6893 if (blue > 1.0)
6894 blue = 1.0;
6895 else if (blue < 0.0)
6896 blue = 0.0;
6897
6898 hls_to_rgb (&red, &green, &blue);
6899
6900 b->red = red;
6901 b->green = green;
6902 b->blue = blue;
6903}
6904
6905/**
6906 * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
6907 *
6908 * \param r on input, red; on output, hue
6909 * \param g on input, green; on output, lightness
6910 * \param b on input, blue; on output, saturation
6911 */
6912static void
6913rgb_to_hls (gdouble *r,
6914 gdouble *g,
6915 gdouble *b)
6916{
6917 gdouble min;
6918 gdouble max;
6919 gdouble red;
6920 gdouble green;
6921 gdouble blue;
6922 gdouble h, l, s;
6923 gdouble delta;
6924
6925 red = *r;
6926 green = *g;
6927 blue = *b;
6928
6929 if (red > green)
6930 {
6931 if (red > blue)
6932 max = red;
6933 else
6934 max = blue;
6935
6936 if (green < blue)
6937 min = green;
6938 else
6939 min = blue;
6940 }
6941 else
6942 {
6943 if (green > blue)
6944 max = green;
6945 else
6946 max = blue;
6947
6948 if (red < blue)
6949 min = red;
6950 else
6951 min = blue;
6952 }
6953
6954 l = (max + min) / 2;
6955 s = 0;
6956 h = 0;
6957
6958 if (max != min)
6959 {
6960 if (l <= 0.5)
6961 s = (max - min) / (max + min);
6962 else
6963 s = (max - min) / (2 - max - min);
6964
6965 delta = max -min;
6966 if (red == max)
6967 h = (green - blue) / delta;
6968 else if (green == max)
6969 h = 2 + (blue - red) / delta;
6970 else if (blue == max)
6971 h = 4 + (red - green) / delta;
6972
6973 h *= 60;
6974 if (h < 0.0)
6975 h += 360;
6976 }
6977
6978 *r = h;
6979 *g = l;
6980 *b = s;
6981}
6982
6983/**
6984 * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
6985 *
6986 * \param h on input, hue; on output, red
6987 * \param l on input, lightness; on output, green
6988 * \param s on input, saturation; on output, blue
6989 */
6990static void
6991hls_to_rgb (gdouble *h,
6992 gdouble *l,
6993 gdouble *s)
6994{
6995 gdouble hue;
6996 gdouble lightness;
6997 gdouble saturation;
6998 gdouble m1, m2;
6999 gdouble r, g, b;
7000
7001 lightness = *l;
7002 saturation = *s;
7003
7004 if (lightness <= 0.5)
7005 m2 = lightness * (1 + saturation);
7006 else
7007 m2 = lightness + saturation - lightness * saturation;
7008 m1 = 2 * lightness - m2;
7009
7010 if (saturation == 0)
7011 {
7012 *h = lightness;
7013 *l = lightness;
7014 *s = lightness;
7015 }
7016 else
7017 {
7018 hue = *h + 120;
7019 while (hue > 360)
7020 hue -= 360;
7021 while (hue < 0)
7022 hue += 360;
7023
7024 if (hue < 60)
7025 r = m1 + (m2 - m1) * hue / 60;
7026 else if (hue < 180)
7027 r = m2;
7028 else if (hue < 240)
7029 r = m1 + (m2 - m1) * (240 - hue) / 60;
7030 else
7031 r = m1;
7032
7033 hue = *h;
7034 while (hue > 360)
7035 hue -= 360;
7036 while (hue < 0)
7037 hue += 360;
7038
7039 if (hue < 60)
7040 g = m1 + (m2 - m1) * hue / 60;
7041 else if (hue < 180)
7042 g = m2;
7043 else if (hue < 240)
7044 g = m1 + (m2 - m1) * (240 - hue) / 60;
7045 else
7046 g = m1;
7047
7048 hue = *h - 120;
7049 while (hue > 360)
7050 hue -= 360;
7051 while (hue < 0)
7052 hue += 360;
7053
7054 if (hue < 60)
7055 b = m1 + (m2 - m1) * hue / 60;
7056 else if (hue < 180)
7057 b = m2;
7058 else if (hue < 240)
7059 b = m1 + (m2 - m1) * (240 - hue) / 60;
7060 else
7061 b = m1;
7062
7063 *h = r;
7064 *l = g;
7065 *s = b;
7066 }
7067}
7068
7069#if 0
7070/* These are some functions I'm saving to use in optimizing
7071 * MetaDrawOpList, namely to pre-composite pixbufs on client side
7072 * prior to rendering to the server
7073 */
7074static void
7075draw_bg_solid_composite (const MetaTextureSpec *bg,
7076 const MetaTextureSpec *fg,
7077 double alpha,
7078 GtkWidget *widget,
7079 GdkDrawable *drawable,
7080 const GdkRectangle *clip,
7081 MetaTextureDrawMode mode,
7082 double xalign,
7083 double yalign,
7084 int x,
7085 int y,
7086 int width,
7087 int height)
7088{
7089 GdkColor bg_color;
7090
7091 g_assert (bg->type == META_TEXTURE_SOLID)do { if (bg->type == META_TEXTURE_SOLID) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7091, ((const char*) (__func__)), "bg->type == META_TEXTURE_SOLID"
); } while (0)
;
7092 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7092, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7093 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7093, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7094
7095 meta_color_spec_render (bg->data.solid.color_spec,
7096 widget,
7097 &bg_color);
7098
7099 switch (fg->type)
7100 {
7101 case META_TEXTURE_SOLID:
7102 {
7103 GdkColor fg_color;
7104
7105 meta_color_spec_render (fg->data.solid.color_spec,
7106 widget,
7107 &fg_color);
7108
7109 color_composite (&bg_color, &fg_color,
7110 alpha, &fg_color);
7111
7112 draw_color_rectangle (widget, drawable, &fg_color, clip,
7113 x, y, width, height);
7114 }
7115 break;
7116
7117 case META_TEXTURE_GRADIENT:
7118 /* FIXME I think we could just composite all the colors in
7119 * the gradient prior to generating the gradient?
7120 */
7121 /* FALL THRU */
7122 case META_TEXTURE_IMAGE:
7123 {
7124 GdkPixbuf *pixbuf;
7125 GdkPixbuf *composited;
7126
7127 pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7128 width, height);
7129
7130 if (pixbuf == NULL((void*)0))
7131 return;
7132
7133 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7134 gdk_pixbuf_get_has_alpha (pixbuf), 8,
7135 gdk_pixbuf_get_width (pixbuf),
7136 gdk_pixbuf_get_height (pixbuf));
7137
7138 if (composited == NULL((void*)0))
7139 {
7140 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7141 return;
7142 }
7143
7144 gdk_pixbuf_composite_color (pixbuf,
7145 composited,
7146 0, 0,
7147 gdk_pixbuf_get_width (pixbuf),
7148 gdk_pixbuf_get_height (pixbuf),
7149 0.0, 0.0, /* offsets */
7150 1.0, 1.0, /* scale */
7151 GDK_INTERP_BILINEAR,
7152 255 * alpha,
7153 0, 0, /* check offsets */
7154 0, /* check size */
7155 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
,
7156 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
);
7157
7158 /* Need to draw background since pixbuf is not
7159 * necessarily covering the whole thing
7160 */
7161 draw_color_rectangle (widget, drawable, &bg_color, clip,
7162 x, y, width, height);
7163
7164 render_pixbuf_aligned (drawable, clip, composited,
7165 xalign, yalign,
7166 x, y, width, height);
7167
7168 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7169 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7170 }
7171 break;
7172
7173 case META_TEXTURE_BLANK:
7174 case META_TEXTURE_COMPOSITE:
7175 case META_TEXTURE_SHAPE_LIST:
7176 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7176, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7177 break;
7178 }
7179}
7180
7181static void
7182draw_bg_gradient_composite (const MetaTextureSpec *bg,
7183 const MetaTextureSpec *fg,
7184 double alpha,
7185 GtkWidget *widget,
7186 GdkDrawable *drawable,
7187 const GdkRectangle *clip,
7188 MetaTextureDrawMode mode,
7189 double xalign,
7190 double yalign,
7191 int x,
7192 int y,
7193 int width,
7194 int height)
7195{
7196 g_assert (bg->type == META_TEXTURE_GRADIENT)do { if (bg->type == META_TEXTURE_GRADIENT) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7196, ((const char*) (__func__)), "bg->type == META_TEXTURE_GRADIENT"
); } while (0)
;
7197 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7197, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7198 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7198, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7199
7200 switch (fg->type)
7201 {
7202 case META_TEXTURE_SOLID:
7203 case META_TEXTURE_GRADIENT:
7204 case META_TEXTURE_IMAGE:
7205 {
7206 GdkPixbuf *bg_pixbuf;
7207 GdkPixbuf *fg_pixbuf;
7208 GdkPixbuf *composited;
7209 int fg_width, fg_height;
7210
7211 bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255,
7212 width, height);
7213
7214 if (bg_pixbuf == NULL((void*)0))
7215 return;
7216
7217 fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7218 width, height);
7219
7220 if (fg_pixbuf == NULL((void*)0))
7221 {
7222 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7223 return;
7224 }
7225
7226 /* gradients always fill the entire target area */
7227 g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width)do { if (gdk_pixbuf_get_width (bg_pixbuf) == width) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7227, ((const char*) (__func__)), "gdk_pixbuf_get_width (bg_pixbuf) == width"
); } while (0)
;
7228 g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height)do { if (gdk_pixbuf_get_height (bg_pixbuf) == height) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7228, ((const char*) (__func__)), "gdk_pixbuf_get_height (bg_pixbuf) == height"
); } while (0)
;
7229
7230 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7231 gdk_pixbuf_get_has_alpha (bg_pixbuf), 8,
7232 gdk_pixbuf_get_width (bg_pixbuf),
7233 gdk_pixbuf_get_height (bg_pixbuf));
7234
7235 if (composited == NULL((void*)0))
7236 {
7237 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7238 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7239 return;
7240 }
7241
7242 fg_width = gdk_pixbuf_get_width (fg_pixbuf);
7243 fg_height = gdk_pixbuf_get_height (fg_pixbuf);
7244
7245 /* If we wanted to be all cool we could deal with the
7246 * offsets and try to composite only in the clip rectangle,
7247 * but I just don't care enough to figure it out.
7248 */
7249
7250 gdk_pixbuf_composite (fg_pixbuf,
7251 composited,
7252 x + (width - fg_width) * xalign,
7253 y + (height - fg_height) * yalign,
7254 gdk_pixbuf_get_width (fg_pixbuf),
7255 gdk_pixbuf_get_height (fg_pixbuf),
7256 0.0, 0.0, /* offsets */
7257 1.0, 1.0, /* scale */
7258 GDK_INTERP_BILINEAR,
7259 255 * alpha);
7260
7261 gdk_cairo_set_source_pixbuf (cr, composited, x, y);
7262 cairo_paint (cr);
7263
7264 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7265 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7266 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7267 }
7268 break;
7269
7270 case META_TEXTURE_BLANK:
7271 case META_TEXTURE_SHAPE_LIST:
7272 case META_TEXTURE_COMPOSITE:
7273 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7273, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7274 break;
7275 }
7276}
7277#endif
7278
7279/**
7280 * Returns the earliest version of the theme format which required support
7281 * for a particular button. (For example, "shade" first appeared in v2, and
7282 * "close" in v1.)
7283 *
7284 * \param type the button type
7285 * \return the number of the theme format
7286 */
7287guint
7288meta_theme_earliest_version_with_button (MetaButtonType type)
7289{
7290 switch (type)
7291 {
7292 case META_BUTTON_TYPE_CLOSE:
7293 case META_BUTTON_TYPE_MAXIMIZE:
7294 case META_BUTTON_TYPE_MINIMIZE:
7295 case META_BUTTON_TYPE_MENU:
7296 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
7297 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
7298 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
7299 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
7300 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
7301 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
7302 return 1000;
7303
7304 case META_BUTTON_TYPE_SHADE:
7305 case META_BUTTON_TYPE_ABOVE:
7306 case META_BUTTON_TYPE_STICK:
7307 case META_BUTTON_TYPE_UNSHADE:
7308 case META_BUTTON_TYPE_UNABOVE:
7309 case META_BUTTON_TYPE_UNSTICK:
7310 return 2000;
7311
7312 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
7313 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
7314 return 3003;
7315
7316 case META_BUTTON_TYPE_APPMENU:
7317 return 3005;
7318
7319 default:
7320 meta_warning("Unknown button %d\n", type);
7321 return 1000;
7322 }
7323}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-894891.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-894891.html new file mode 100644 index 00000000..b51a04db --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-894891.html @@ -0,0 +1,3187 @@ + + + +core/prefs.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/prefs.c
Warning:line 1521, column 44
The left operand of '!=' is a garbage value
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name prefs.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/prefs.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco preferences */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7 * Copyright (C) 2006 Elijah Newren
8 * Copyright (C) 2008 Thomas Thurman
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26#include <config.h>
27#include <glib/gi18n-lib.h>
28
29#include "prefs.h"
30#include "ui.h"
31#include "util.h"
32#include <gdk/gdk.h>
33#include <gio/gio.h>
34#include <string.h>
35#include <stdlib.h>
36
37#define MAX_REASONABLE_WORKSPACES36 36
38
39#define MAX_COMMANDS(32 + 2) (32 + NUM_EXTRA_COMMANDS2)
40#define NUM_EXTRA_COMMANDS2 2
41#define SCREENSHOT_COMMAND_IDX((32 + 2) - 2) (MAX_COMMANDS(32 + 2) - 2)
42#define WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1) (MAX_COMMANDS(32 + 2) - 1)
43
44/* If you add a key, it needs updating in init() and in the GSettings
45 * notify listener and of course in the .gschema file.
46 *
47 * Keys which are handled by one of the unified handlers below are
48 * not given a name here, because the purpose of the unified handlers
49 * is that keys should be referred to exactly once.
50 */
51#define KEY_GENERAL_SCHEMA"org.mate.Marco.general" "org.mate.Marco.general"
52#define KEY_GENERAL_TITLEBAR_FONT"titlebar-font" "titlebar-font"
53#define KEY_GENERAL_NUM_WORKSPACES"num-workspaces" "num-workspaces"
54#define KEY_GENERAL_COMPOSITOR"compositing-manager" "compositing-manager"
55#define KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB"compositing-fast-alt-tab" "compositing-fast-alt-tab"
56#define KEY_GENERAL_CENTER_NEW_WINDOWS"center-new-windows" "center-new-windows"
57#define KEY_GENERAL_ICON_SIZE"icon-size" "icon-size"
58#define KEY_GENERAL_ALT_TAB_MAX_COLUMNS"alt-tab-max-columns" "alt-tab-max-columns"
59#define KEY_GENERAL_ALT_TAB_RAISE_WINDOWS"alt-tab-raise-windows" "alt-tab-raise-windows"
60#define KEY_GENERAL_ALT_TAB_EXPAND_TO_FIT_TITLE"alt-tab-expand-to-fit-title" "alt-tab-expand-to-fit-title"
61
62#define KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands" "org.mate.Marco.keybinding-commands"
63#define KEY_COMMAND_PREFIX"command-" "command-"
64
65#define KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings" "org.mate.Marco.global-keybindings"
66
67#define KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings" "org.mate.Marco.window-keybindings"
68
69#define KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names" "org.mate.Marco.workspace-names"
70#define KEY_WORKSPACE_NAME_PREFIX"name-" "name-"
71
72#define KEY_MATE_INTERFACE_SCHEMA"org.mate.interface" "org.mate.interface"
73#define KEY_MATE_INTERFACE_ACCESSIBILITY"accessibility" "accessibility"
74#define KEY_MATE_INTERFACE_ENABLE_ANIMATIONS"enable-animations" "enable-animations"
75
76#define KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal" "org.mate.applications-terminal"
77#define KEY_MATE_TERMINAL_COMMAND"exec" "exec"
78
79#define KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse" "org.mate.peripherals-mouse"
80#define KEY_MATE_MOUSE_CURSOR_THEME"cursor-theme" "cursor-theme"
81#define KEY_MATE_MOUSE_CURSOR_SIZE"cursor-size" "cursor-size"
82
83#define SETTINGS(s)g_hash_table_lookup (settings_schemas, (s)) g_hash_table_lookup (settings_schemas, (s))
84
85static GSettings *settings_general;
86static GSettings *settings_command;
87static GSettings *settings_screen_bindings;
88static GSettings *settings_window_bindings;
89static GSettings *settings_workspace_names;
90static GSettings *settings_mate_interface;
91static GSettings *settings_mate_terminal;
92static GSettings *settings_mate_mouse;
93static GHashTable *settings_schemas;
94
95static GList *changes = NULL((void*)0);
96static guint changed_idle;
97static GList *listeners = NULL((void*)0);
98
99static gboolean use_system_font = FALSE(0);
100static PangoFontDescription *titlebar_font = NULL((void*)0);
101static MetaVirtualModifier mouse_button_mods = Mod1Mask(1<<3);
102static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
103static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
104static gboolean raise_on_click = TRUE(!(0));
105static gboolean attach_modal_dialogs = FALSE(0);
106static char* current_theme = NULL((void*)0);
107static int num_workspaces = 4;
108static MetaWrapStyle wrap_style = META_WRAP_NONE;
109static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
110static MetaActionTitlebar action_middle_click_titlebar = META_ACTION_TITLEBAR_LOWER;
111static MetaActionTitlebar action_right_click_titlebar = META_ACTION_TITLEBAR_MENU;
112static gboolean application_based = FALSE(0);
113static gboolean disable_workarounds = FALSE(0);
114static gboolean auto_raise = FALSE(0);
115static gboolean auto_raise_delay = 500;
116static gboolean provide_visual_bell = FALSE(0);
117static gboolean bell_is_audible = TRUE(!(0));
118static gboolean reduced_resources = FALSE(0);
119static gboolean mate_accessibility = FALSE(0);
120static gboolean mate_animations = TRUE(!(0));
121static char *cursor_theme = NULL((void*)0);
122static int cursor_size = 24;
123static int icon_size = META_DEFAULT_ICON_SIZE48;
124static int alt_tab_max_columns = META_DEFAULT_ALT_TAB_MAX_COLUMNS5;
125static gboolean alt_tab_raise_windows = META_DEFAULT_ALT_TAB_RAISE_WINDOWS(0);
126static gboolean alt_tab_expand_to_fit_title = META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE(0);
127static gboolean use_force_compositor_manager = FALSE(0);
128static gboolean force_compositor_manager = FALSE(0);
129static gboolean compositing_manager = FALSE(0);
130static gboolean compositing_fast_alt_tab = FALSE(0);
131static gboolean resize_with_right_button = FALSE(0);
132static gboolean show_tab_border = FALSE(0);
133static gboolean center_new_windows = FALSE(0);
134static gboolean force_fullscreen = TRUE(!(0));
135static gboolean allow_tiling = FALSE(0);
136static gboolean allow_top_tiling = TRUE(!(0));
137static gboolean allow_tile_cycling = TRUE(!(0));
138static GList *show_desktop_skip_list = NULL((void*)0);
139
140static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
141static MetaButtonLayout button_layout;
142
143/* The screenshot commands are at the end */
144static char *commands[MAX_COMMANDS(32 + 2)] = { NULL((void*)0), };
145
146static char *terminal_command = NULL((void*)0);
147
148static char *workspace_names[MAX_REASONABLE_WORKSPACES36] = { NULL((void*)0), };
149
150static gboolean handle_preference_update_enum (const gchar *key, GSettings *settings);
151
152static gboolean update_key_binding (const char *name,
153 gchar *value);
154static gboolean update_command (const char *name,
155 const char *value);
156static gboolean update_workspace_name (const char *name,
157 const char *value);
158
159static void change_notify (GSettings *settings,
160 gchar *key,
161 gpointer user_data);
162
163static char* settings_key_for_workspace_name (int i);
164
165static void queue_changed (MetaPreference pref);
166
167#if 0
168static void cleanup_error (GError **error);
169#endif
170
171static void maybe_give_disable_workarounds_warning (void);
172
173static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
174static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
175static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
176static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
177static void show_desktop_skip_list_handler (MetaPreference, const gchar*, gboolean*);
178
179static gboolean update_binding (MetaKeyPref *binding,
180 gchar *value);
181
182static void init_bindings (GSettings *);
183static void init_screen_bindings (void);
184static void init_window_bindings (void);
185static void init_commands (void);
186static void init_workspace_names (void);
187
188static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_AUTOMATIC;
189
190typedef struct
191{
192 MetaPrefsChangedFunc func;
193 gpointer data;
194} MetaPrefsListener;
195
196/**
197 * The details of one preference which is constrained to be
198 * one of a small number of string values-- in other words,
199 * an enumeration.
200 *
201 * We could have done this other ways. One particularly attractive
202 * possibility would have been to represent the entire symbol table
203 * as a space-separated string literal in the list of symtabs, so
204 * the focus mode enums could have been represented simply by
205 * "click sloppy mouse". However, the simplicity gained would have
206 * been outweighed by the bugs caused when the ordering of the enum
207 * strings got out of sync with the actual enum statement. Also,
208 * there is existing library code to use this kind of symbol tables.
209 *
210 * Other things we might consider doing to clean this up in the
211 * future include:
212 *
213 * - most of the keys begin with the same prefix, and perhaps we
214 * could assume it if they don't start with a slash
215 *
216 * - there are several cases where a single identifier could be used
217 * to generate an entire entry, and perhaps this could be done
218 * with a macro. (This would reduce clarity, however, and is
219 * probably a bad thing.)
220 *
221 * - these types all begin with a gchar* (and contain a MetaPreference)
222 * and we can factor out the repeated code in the handlers by taking
223 * advantage of this using some kind of union arrangement.
224 */
225typedef struct
226{
227 gchar *key;
228 gchar *schema;
229 MetaPreference pref;
230 gint *target;
231} MetaEnumPreference;
232
233typedef struct
234{
235 gchar *key;
236 gchar *schema;
237 MetaPreference pref;
238 gboolean *target;
239 gboolean becomes_true_on_destruction;
240} MetaBoolPreference;
241
242typedef struct
243{
244 gchar *key;
245 gchar *schema;
246 MetaPreference pref;
247
248 /**
249 * A handler. Many of the string preferences aren't stored as
250 * strings and need parsing; others of them have default values
251 * which can't be solved in the general case. If you include a
252 * function pointer here, it will be called before the string
253 * value is written out to the target variable.
254 *
255 * The function is passed two arguments: the preference, and
256 * the new string as a gchar*. It returns a gboolean;
257 * only if this is true, the listeners will be informed that
258 * the preference has changed.
259 *
260 * This may be NULL. If it is, see "target", below.
261 */
262 void (*handler) (MetaPreference pref,
263 const gchar *string_value,
264 gboolean *inform_listeners);
265
266 /**
267 * Where to write the incoming string.
268 *
269 * This must be NULL if the handler is non-NULL.
270 * If the incoming string is NULL, no change will be made.
271 */
272 gchar **target;
273
274} MetaStringPreference;
275
276#define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY(-2147483647 -1) G_MININT(-2147483647 -1)
277
278typedef struct
279{
280 gchar *key;
281 gchar *schema;
282 MetaPreference pref;
283 gint *target;
284 /**
285 * Minimum and maximum values of the integer.
286 * If the new value is out of bounds, it will be discarded with a warning.
287 */
288 gint minimum, maximum;
289 /**
290 * Value to use if the key is destroyed.
291 * If this is METAINTPREFERENCE_NO_CHANGE_ON_DESTROY, it will
292 * not be changed when the key is destroyed.
293 */
294 gint value_if_destroyed;
295} MetaIntPreference;
296
297/* FIXMEs: */
298/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
299/* @@@ /apps/marco/general should be assumed if first char is not / */
300/* @@@ Will it ever be possible to merge init and update? If not, why not? */
301
302static MetaEnumPreference preferences_enum[] =
303 {
304 { "focus-new-windows",
305 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
306 META_PREF_FOCUS_NEW_WINDOWS,
307 (gint *) &focus_new_windows,
308 },
309 { "focus-mode",
310 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
311 META_PREF_FOCUS_MODE,
312 (gint *) &focus_mode,
313 },
314 { "wrap-style",
315 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
316 META_PREF_WRAP_STYLE,
317 (gint *) &wrap_style,
318 },
319 { "visual-bell-type",
320 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
321 META_PREF_VISUAL_BELL_TYPE,
322 (gint *) &visual_bell_type,
323 },
324 { "action-double-click-titlebar",
325 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
326 META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
327 (gint *) &action_double_click_titlebar,
328 },
329 { "action-middle-click-titlebar",
330 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
331 META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
332 (gint *) &action_middle_click_titlebar,
333 },
334 { "action-right-click-titlebar",
335 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
336 META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
337 (gint *) &action_right_click_titlebar,
338 },
339 { "placement-mode",
340 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
341 META_PREF_PLACEMENT_MODE,
342 (gint *) &placement_mode,
343 },
344 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0) },
345 };
346
347static MetaBoolPreference preferences_bool[] =
348 {
349 { "raise-on-click",
350 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
351 META_PREF_RAISE_ON_CLICK,
352 &raise_on_click,
353 TRUE(!(0)),
354 },
355 { "titlebar-uses-system-font",
356 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
357 META_PREF_TITLEBAR_FONT, /* note! shares a pref */
358 &use_system_font,
359 TRUE(!(0)),
360 },
361 { "application-based",
362 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
363 META_PREF_APPLICATION_BASED,
364 NULL((void*)0), /* feature is known but disabled */
365 FALSE(0),
366 },
367 { "disable-workarounds",
368 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
369 META_PREF_DISABLE_WORKAROUNDS,
370 &disable_workarounds,
371 FALSE(0),
372 },
373 { "auto-raise",
374 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
375 META_PREF_AUTO_RAISE,
376 &auto_raise,
377 FALSE(0),
378 },
379 { "visual-bell",
380 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
381 META_PREF_VISUAL_BELL,
382 &provide_visual_bell, /* FIXME: change the name: it's confusing */
383 FALSE(0),
384 },
385 { "audible-bell",
386 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
387 META_PREF_AUDIBLE_BELL,
388 &bell_is_audible, /* FIXME: change the name: it's confusing */
389 FALSE(0),
390 },
391 { "reduced-resources",
392 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
393 META_PREF_REDUCED_RESOURCES,
394 &reduced_resources,
395 FALSE(0),
396 },
397 { "accessibility",
398 KEY_MATE_INTERFACE_SCHEMA"org.mate.interface",
399 META_PREF_MATE_ACCESSIBILITY,
400 &mate_accessibility,
401 FALSE(0),
402 },
403 { "enable-animations",
404 KEY_MATE_INTERFACE_SCHEMA"org.mate.interface",
405 META_PREF_MATE_ANIMATIONS,
406 &mate_animations,
407 TRUE(!(0)),
408 },
409 { KEY_GENERAL_COMPOSITOR"compositing-manager",
410 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
411 META_PREF_COMPOSITING_MANAGER,
412 &compositing_manager,
413 FALSE(0),
414 },
415 { "compositing-fast-alt-tab",
416 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
417 META_PREF_COMPOSITING_FAST_ALT_TAB,
418 &compositing_fast_alt_tab,
419 FALSE(0),
420 },
421 { "resize-with-right-button",
422 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
423 META_PREF_RESIZE_WITH_RIGHT_BUTTON,
424 &resize_with_right_button,
425 FALSE(0),
426 },
427 { "show-tab-border",
428 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
429 META_PREF_SHOW_TAB_BORDER,
430 &show_tab_border,
431 FALSE(0),
432 },
433 { "center-new-windows",
434 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
435 META_PREF_CENTER_NEW_WINDOWS,
436 &center_new_windows,
437 FALSE(0),
438 },
439 { "allow-tiling",
440 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
441 META_PREF_ALLOW_TILING,
442 &allow_tiling,
443 FALSE(0),
444 },
445 { "allow-top-tiling",
446 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
447 META_PREF_ALLOW_TOP_TILING,
448 &allow_top_tiling,
449 FALSE(0),
450 },
451 { "allow-tile-cycling",
452 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
453 META_PREF_ALLOW_TILE_CYCLING,
454 &allow_tile_cycling,
455 FALSE(0),
456 },
457 { "alt-tab-expand-to-fit-title",
458 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
459 META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE,
460 &alt_tab_expand_to_fit_title,
461 META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE(0),
462 },
463 { "alt-tab-raise-windows",
464 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
465 META_PREF_ALT_TAB_RAISE_WINDOWS,
466 &alt_tab_raise_windows,
467 META_DEFAULT_ALT_TAB_RAISE_WINDOWS(0),
468 },
469 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), FALSE(0) },
470 };
471
472static MetaStringPreference preferences_string[] =
473 {
474 { "mouse-button-modifier",
475 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
476 META_PREF_MOUSE_BUTTON_MODS,
477 mouse_button_mods_handler,
478 NULL((void*)0),
479 },
480 { "theme",
481 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
482 META_PREF_THEME,
483 theme_name_handler,
484 NULL((void*)0),
485 },
486 { KEY_GENERAL_TITLEBAR_FONT"titlebar-font",
487 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
488 META_PREF_TITLEBAR_FONT,
489 titlebar_handler,
490 NULL((void*)0),
491 },
492 { KEY_MATE_TERMINAL_COMMAND"exec",
493 KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal",
494 META_PREF_TERMINAL_COMMAND,
495 NULL((void*)0),
496 &terminal_command,
497 },
498 { "button-layout",
499 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
500 META_PREF_BUTTON_LAYOUT,
501 button_layout_handler,
502 NULL((void*)0),
503 },
504 { "cursor-theme",
505 KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse",
506 META_PREF_CURSOR_THEME,
507 NULL((void*)0),
508 &cursor_theme,
509 },
510 { "show-desktop-skip-list",
511 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
512 META_PREF_SHOW_DESKTOP_SKIP_LIST,
513 &show_desktop_skip_list_handler,
514 NULL((void*)0),
515 },
516 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), NULL((void*)0) },
517 };
518
519static MetaIntPreference preferences_int[] =
520 {
521 { "num-workspaces",
522 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
523 META_PREF_NUM_WORKSPACES,
524 &num_workspaces,
525 /* I would actually recommend we change the destroy value to 4
526 * and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
527 * -- tthurman
528 */
529 1, MAX_REASONABLE_WORKSPACES36, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY(-2147483647 -1),
530 },
531 { "auto-raise-delay",
532 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
533 META_PREF_AUTO_RAISE_DELAY,
534 &auto_raise_delay,
535 0, 10000, 0,
536 /* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
537 },
538 { "cursor-size",
539 KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse",
540 META_PREF_CURSOR_SIZE,
541 &cursor_size,
542 1, 128, 24,
543 },
544 { "icon-size",
545 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
546 META_PREF_ICON_SIZE,
547 &icon_size,
548 META_MIN_ICON_SIZE8, META_MAX_ICON_SIZE256, META_DEFAULT_ICON_SIZE48,
549 },
550 { "alt-tab-max-columns",
551 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
552 META_PREF_ALT_TAB_MAX_COLUMNS,
553 &alt_tab_max_columns,
554 META_MIN_ALT_TAB_MAX_COLUMNS1,
555 META_MAX_ALT_TAB_MAX_COLUMNS64,
556 META_DEFAULT_ALT_TAB_MAX_COLUMNS5,
557 },
558 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), 0, 0, 0, },
559 };
560
561static void
562handle_preference_init_enum (void)
563{
564 MetaEnumPreference *cursor = preferences_enum;
565
566 while (cursor->key!=NULL((void*)0))
567 {
568 gint value;
569
570 if (cursor->target==NULL((void*)0))
571 {
572 ++cursor;
573 continue;
574 }
575
576 value = g_settings_get_enum (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
577 cursor->key);
578 *cursor->target = value;
579
580 ++cursor;
581 }
582}
583
584static void
585handle_preference_init_bool (void)
586{
587 MetaBoolPreference *cursor = preferences_bool;
588
589 while (cursor->key!=NULL((void*)0))
590 {
591 if (cursor->target!=NULL((void*)0))
592 *cursor->target = g_settings_get_boolean (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)), cursor->key);
593
594 ++cursor;
595 }
596
597 maybe_give_disable_workarounds_warning ();
598}
599
600static void
601handle_preference_init_string (void)
602{
603 MetaStringPreference *cursor = preferences_string;
604
605 while (cursor->key!=NULL((void*)0))
606 {
607 gchar *value;
608 gboolean dummy = TRUE(!(0));
609
610 /* the string "value" will be newly allocated */
611 value = g_settings_get_string (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
612 cursor->key);
613
614 if (cursor->handler)
615 {
616 if (cursor->target)
617 meta_bug ("%s has both a target and a handler\n", cursor->key);
618
619 cursor->handler (cursor->pref, value, &dummy);
620
621 g_free (value);
622 }
623 else if (cursor->target)
624 {
625 if (*(cursor->target))
626 g_free (*(cursor->target));
627
628 *(cursor->target) = value;
629 }
630
631 ++cursor;
632 }
633}
634
635static void
636handle_preference_init_int (void)
637{
638 MetaIntPreference *cursor = preferences_int;
639
640 while (cursor->key!=NULL((void*)0))
641 {
642 gint value;
643
644 value = g_settings_get_int (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
645 cursor->key);
646
647 if (value < cursor->minimum || value > cursor->maximum)
648 {
649 /* FIXME: check if this can be avoided by GSettings */
650 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n")((char *) g_dgettext ("marco", "%d stored in GSettings key %s is out of range %d to %d\n"
))
,
651 value, cursor->key, cursor->minimum, cursor->maximum);
652 /* Former behaviour for out-of-range values was:
653 * - number of workspaces was clamped;
654 * - auto raise delay was always reset to zero even if too high!;
655 * - cursor size was ignored.
656 *
657 * These seem to be meaningless variations. If they did
658 * have meaning we could have put them into MetaIntPreference.
659 * The last of these is the closest to how we behave for
660 * other types, so I think we should standardise on that.
661 */
662 }
663 else if (cursor->target)
664 *cursor->target = value;
665
666 ++cursor;
667 }
668}
669
670static gboolean
671handle_preference_update_enum (const gchar *key, GSettings *settings)
672{
673 MetaEnumPreference *cursor = preferences_enum;
674 gint old_value;
675
676 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
677 ++cursor;
678
679 if (cursor->key==NULL((void*)0))
680 /* Didn't recognise that key. */
681 return FALSE(0);
682
683 /* We need to know whether the value changes, so
684 * store the current value away.
685 */
686
687 old_value = * ((gint *) cursor->target);
688
689 /* Now look it up... */
690 *cursor->target = g_settings_get_enum (settings, key);
691
692 /* Did it change? If so, tell the listeners about it. */
693
694 if (old_value != *((gint *) cursor->target))
695 queue_changed (cursor->pref);
696
697 return TRUE(!(0));
698}
699
700static gboolean
701handle_preference_update_bool (const gchar *key, GSettings *settings)
702{
703 MetaBoolPreference *cursor = preferences_bool;
704 gboolean old_value;
705
706 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
707 ++cursor;
708
709 if (cursor->key==NULL((void*)0))
710 /* Didn't recognise that key. */
711 return FALSE(0);
712
713 if (cursor->target==NULL((void*)0))
714 /* No work for us to do. */
715 return TRUE(!(0));
716
717 /* We need to know whether the value changes, so
718 * store the current value away.
719 */
720
721 old_value = * ((gboolean *) cursor->target);
722
723 /* Now look it up... */
724
725 *((gboolean *) cursor->target) = g_settings_get_boolean (settings, key);
726
727 /* Did it change? If so, tell the listeners about it. */
728
729 if (old_value != *((gboolean *) cursor->target))
730 queue_changed (cursor->pref);
731
732 if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
733 maybe_give_disable_workarounds_warning ();
734
735 return TRUE(!(0));
736}
737
738static gboolean
739handle_preference_update_string (const gchar *key, GSettings *settings)
740{
741 MetaStringPreference *cursor = preferences_string;
742 gchar *value;
743 gboolean inform_listeners = TRUE(!(0));
744
745 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
746 ++cursor;
747
748 if (cursor->key==NULL((void*)0))
749 /* Didn't recognise that key. */
750 return FALSE(0);
751
752 value = g_settings_get_string (settings, key);
753
754 if (cursor->handler)
755 cursor->handler (cursor->pref, value, &inform_listeners);
756 else if (cursor->target)
757 {
758 if (*(cursor->target))
759 g_free(*(cursor->target));
760
761 if (value!=NULL((void*)0))
762 *(cursor->target) = g_strdup (value)g_strdup_inline (value);
763 else
764 *(cursor->target) = NULL((void*)0);
765
766 inform_listeners =
767 (value==NULL((void*)0) && *(cursor->target)==NULL((void*)0)) ||
768 (value!=NULL((void*)0) && *(cursor->target)!=NULL((void*)0) &&
769 strcmp (value, *(cursor->target))==0);
770 }
771
772 if (inform_listeners)
773 queue_changed (cursor->pref);
774
775 g_free (value);
776
777 return TRUE(!(0));
778}
779
780static gboolean
781handle_preference_update_int (const gchar *key, GSettings *settings)
782{
783 MetaIntPreference *cursor = preferences_int;
784 gint value;
785
786 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
787 ++cursor;
788
789 if (cursor->key==NULL((void*)0))
790 /* Didn't recognise that key. */
791 return FALSE(0);
792
793 if (cursor->target==NULL((void*)0))
794 /* No work for us to do. */
795 return TRUE(!(0));
796
797 value = g_settings_get_int (settings, key);
798
799 if (value < cursor->minimum || value > cursor->maximum)
800 {
801 /* FIXME! GSettings, instead of MateConf, has Minimum/Maximun in schema!
802 * But some preferences depends on costants for minimum/maximum values */
803 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n")((char *) g_dgettext ("marco", "%d stored in GSettings key %s is out of range %d to %d\n"
))
,
804 value, cursor->key,
805 cursor->minimum, cursor->maximum);
806 return TRUE(!(0));
807 }
808
809 /* Did it change? If so, tell the listeners about it. */
810
811 if (*cursor->target != value)
812 {
813 *cursor->target = value;
814 queue_changed (cursor->pref);
815 }
816
817 return TRUE(!(0));
818
819}
820
821/****************************************************************************/
822/* Listeners. */
823/****************************************************************************/
824
825void
826meta_prefs_add_listener (MetaPrefsChangedFunc func,
827 gpointer data)
828{
829 MetaPrefsListener *l;
830
831 l = g_new (MetaPrefsListener, 1)((MetaPrefsListener *) g_malloc_n ((1), sizeof (MetaPrefsListener
)))
;
832 l->func = func;
833 l->data = data;
834
835 listeners = g_list_prepend (listeners, l);
836}
837
838void
839meta_prefs_remove_listener (MetaPrefsChangedFunc func,
840 gpointer data)
841{
842 GList *tmp;
843
844 tmp = listeners;
845 while (tmp != NULL((void*)0))
846 {
847 MetaPrefsListener *l = tmp->data;
848
849 if (l->func == func &&
850 l->data == data)
851 {
852 g_free (l);
853 listeners = g_list_delete_link (listeners, tmp);
854
855 return;
856 }
857
858 tmp = tmp->next;
859 }
860
861 meta_bug ("Did not find listener to remove\n");
862}
863
864static void
865emit_changed (MetaPreference pref)
866{
867 GList *tmp;
868 GList *copy;
869
870 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
871 meta_preference_to_string (pref));
872
873 copy = g_list_copy (listeners);
874
875 tmp = copy;
876
877 while (tmp != NULL((void*)0))
878 {
879 MetaPrefsListener *l = tmp->data;
880
881 (* l->func) (pref, l->data);
882
883 tmp = tmp->next;
884 }
885
886 g_list_free (copy);
887}
888
889static gboolean
890changed_idle_handler (gpointer data)
891{
892 GList *tmp;
893 GList *copy;
894
895 changed_idle = 0;
896
897 copy = g_list_copy (changes); /* reentrancy paranoia */
898
899 g_list_free (changes);
900 changes = NULL((void*)0);
901
902 tmp = copy;
903 while (tmp != NULL((void*)0))
904 {
905 MetaPreference pref = GPOINTER_TO_INT (tmp->data)((gint) (glong) (tmp->data));
906
907 emit_changed (pref);
908
909 tmp = tmp->next;
910 }
911
912 g_list_free (copy);
913
914 return FALSE(0);
915}
916
917static void
918queue_changed (MetaPreference pref)
919{
920 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Queueing change of pref %s\n",
921 meta_preference_to_string (pref));
922
923 if (g_list_find (changes, GINT_TO_POINTER (pref)((gpointer) (glong) (pref))) == NULL((void*)0))
924 changes = g_list_prepend (changes, GINT_TO_POINTER (pref)((gpointer) (glong) (pref)));
925 else
926 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
927 meta_preference_to_string (pref));
928
929 /* add idle at priority below the GSettings notify idle */
930 /* FIXME is this needed for GSettings too? */
931 if (changed_idle == 0)
932 changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY(200 + 10),
933 changed_idle_handler, NULL((void*)0), NULL((void*)0));
934}
935
936/****************************************************************************/
937/* Initialisation. */
938/****************************************************************************/
939
940void
941meta_prefs_init (void)
942{
943 if (settings_general != NULL((void*)0))
944 return;
945
946 /* returns references which we hold forever */
947 settings_general = g_settings_new (KEY_GENERAL_SCHEMA"org.mate.Marco.general");
948 settings_command = g_settings_new (KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands");
949 settings_screen_bindings = g_settings_new (KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings");
950 settings_window_bindings = g_settings_new (KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings");
951 settings_workspace_names = g_settings_new (KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names");
952 settings_mate_interface = g_settings_new (KEY_MATE_INTERFACE_SCHEMA"org.mate.interface");
953 settings_mate_terminal = g_settings_new (KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal");
954 settings_mate_mouse = g_settings_new (KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse");
955
956 settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal, NULL((void*)0), g_object_unref);
957 g_hash_table_insert (settings_schemas, KEY_GENERAL_SCHEMA"org.mate.Marco.general", settings_general);
958 g_hash_table_insert (settings_schemas, KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands", settings_command);
959 g_hash_table_insert (settings_schemas, KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings", settings_screen_bindings);
960 g_hash_table_insert (settings_schemas, KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings", settings_window_bindings);
961 g_hash_table_insert (settings_schemas, KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names", settings_workspace_names);
962 g_hash_table_insert (settings_schemas, KEY_MATE_INTERFACE_SCHEMA"org.mate.interface", settings_mate_interface);
963 g_hash_table_insert (settings_schemas, KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal", settings_mate_terminal);
964 g_hash_table_insert (settings_schemas, KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse", settings_mate_mouse);
965
966 g_signal_connect (settings_general, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_general), ("changed"), (((GCallback
) (change_notify))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
967 g_signal_connect (settings_command, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_command), ("changed"), (((GCallback
) (change_notify))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
968 g_signal_connect (settings_screen_bindings, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_screen_bindings), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
969 g_signal_connect (settings_window_bindings, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_window_bindings), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
970 g_signal_connect (settings_workspace_names, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_workspace_names), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
971
972 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ACCESSIBILITY, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_interface), ("changed::"
"accessibility"), (((GCallback) (change_notify))), (((void*)
0)), ((void*)0), (GConnectFlags) 0)
;
973 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ENABLE_ANIMATIONS, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_interface), ("changed::"
"enable-animations"), (((GCallback) (change_notify))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
974 g_signal_connect (settings_mate_terminal, "changed::" KEY_MATE_TERMINAL_COMMAND, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_terminal), ("changed::"
"exec"), (((GCallback) (change_notify))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
975 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_THEME, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_mouse), ("changed::" "cursor-theme"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
976 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_SIZE, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_mouse), ("changed::" "cursor-size"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
977
978 /* Pick up initial values. */
979
980 handle_preference_init_enum ();
981 handle_preference_init_bool ();
982 handle_preference_init_string ();
983 handle_preference_init_int ();
984
985 init_screen_bindings ();
986 init_window_bindings ();
987 init_commands ();
988 init_workspace_names ();
989}
990
991/****************************************************************************/
992/* Updates. */
993/****************************************************************************/
994
995gboolean (*preference_update_handler[]) (const gchar*, GSettings*) = {
996 handle_preference_update_enum,
997 handle_preference_update_bool,
998 handle_preference_update_string,
999 handle_preference_update_int,
1000 NULL((void*)0)
1001};
1002
1003static void
1004change_notify (GSettings *settings,
1005 gchar *key,
1006 gpointer user_data)
1007{
1008 gint i=0;
1009
1010 /* First, search for a handler that might know what to do. */
1011
1012 /* FIXME: When this is all working, since the first item in every
1013 * array is the gchar* of the key, there's no reason we can't
1014 * find the correct record for that key here and save code duplication.
1015 */
1016
1017 while (preference_update_handler[i]!=NULL((void*)0))
1018 {
1019 if (preference_update_handler[i] (key, settings))
1020 return; /* Get rid of this eventually */
1021
1022 i++;
1023 }
1024
1025 gchar *schema_name = NULL((void*)0);
1026 g_object_get (settings, "schema-id", &schema_name, NULL((void*)0));
1027
1028 if (g_strcmp0 (schema_name, KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings") == 0 ||
1029 g_strcmp0 (schema_name, KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings") == 0)
1030 {
1031 gchar *str;
1032 str = g_settings_get_string (settings, key);
1033
1034 if (update_key_binding (key, str))
1035 queue_changed (META_PREF_KEYBINDINGS);
1036
1037 g_free(str);
1038 }
1039 else if (g_strcmp0 (schema_name, KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands") == 0)
1040 {
1041 gchar *str;
1042 str = g_settings_get_string (settings, key);
1043
1044 if (update_command (key, str))
1045 queue_changed (META_PREF_COMMANDS);
1046
1047 g_free(str);
1048 }
1049 else if (g_strcmp0 (schema_name, KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names") == 0)
1050 {
1051 gchar *str;
1052 str = g_settings_get_string (settings, key);
1053
1054 if (update_workspace_name (key, str))
1055 queue_changed (META_PREF_WORKSPACE_NAMES);
1056
1057 g_free(str);
1058 }
1059 else
1060 {
1061 /* Is this possible with GSettings? I dont think so! */
1062 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Key %s doesn't mean anything to Marco\n",
1063 key);
1064 }
1065 g_free (schema_name);
1066}
1067
1068#if 0
1069static void
1070cleanup_error (GError **error)
1071{
1072 if (*error)
1073 {
1074 meta_warning ("%s\n", (*error)->message);
1075
1076 g_error_free (*error);
1077 *error = NULL((void*)0);
1078 }
1079}
1080#endif
1081
1082/**
1083 * Special case: give a warning the first time disable_workarounds
1084 * is turned on.
1085 */
1086static void
1087maybe_give_disable_workarounds_warning (void)
1088{
1089 static gboolean first_disable = TRUE(!(0));
1090
1091 if (first_disable && disable_workarounds)
1092 {
1093 first_disable = FALSE(0);
1094
1095 meta_warning (_("Workarounds for broken applications disabled. "((char *) g_dgettext ("marco", "Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"))
1096 "Some applications may not behave properly.\n")((char *) g_dgettext ("marco", "Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"))
);
1097 }
1098}
1099
1100MetaVirtualModifier
1101meta_prefs_get_mouse_button_mods (void)
1102{
1103 return mouse_button_mods;
1104}
1105
1106MetaFocusMode
1107meta_prefs_get_focus_mode (void)
1108{
1109 return focus_mode;
1110}
1111
1112MetaFocusNewWindows
1113meta_prefs_get_focus_new_windows (void)
1114{
1115 return focus_new_windows;
1116}
1117
1118gboolean
1119meta_prefs_get_attach_modal_dialogs (void)
1120{
1121 return attach_modal_dialogs;
1122}
1123
1124gboolean
1125meta_prefs_get_raise_on_click (void)
1126{
1127 return raise_on_click;
1128}
1129
1130const char*
1131meta_prefs_get_theme (void)
1132{
1133 return current_theme;
1134}
1135
1136const char*
1137meta_prefs_get_cursor_theme (void)
1138{
1139 return cursor_theme;
1140}
1141
1142int
1143meta_prefs_get_cursor_size (void)
1144{
1145 GdkWindow *window = gdk_get_default_root_window ();
1146 gint scale = gdk_window_get_scale_factor (window);
1147
1148 return cursor_size * scale;
1149}
1150
1151int
1152meta_prefs_get_icon_size (void)
1153{
1154 GdkWindow *window = gdk_get_default_root_window ();
1155 gint scale = gdk_window_get_scale_factor (window);
1156
1157 return icon_size * scale;
1158}
1159
1160int
1161meta_prefs_get_alt_tab_max_columns (void)
1162{
1163 return alt_tab_max_columns;
1164}
1165
1166gboolean
1167meta_prefs_get_alt_tab_expand_to_fit_title (void)
1168{
1169 return alt_tab_expand_to_fit_title;
1170}
1171
1172gboolean
1173meta_prefs_get_alt_tab_raise_windows (void)
1174{
1175 return alt_tab_raise_windows;
1176}
1177
1178gboolean
1179meta_prefs_is_in_skip_list (char *class)
1180{
1181 GList *item;
1182
1183 for (item = show_desktop_skip_list; item; item = item->next)
1184 {
1185 if (!g_ascii_strcasecmp (class, item->data))
1186 return TRUE(!(0));
1187 }
1188 return FALSE(0);
1189}
1190
1191/****************************************************************************/
1192/* Handlers for string preferences. */
1193/****************************************************************************/
1194
1195static void
1196titlebar_handler (MetaPreference pref,
1197 const gchar *string_value,
1198 gboolean *inform_listeners)
1199{
1200 PangoFontDescription *new_desc = NULL((void*)0);
1201
1202 if (string_value)
1203 new_desc = pango_font_description_from_string (string_value);
1204
1205 if (new_desc == NULL((void*)0))
1206 {
1207 meta_warning (_("Could not parse font description "((char *) g_dgettext ("marco", "Could not parse font description "
"\"%s\" from GSettings key %s\n"))
1208 "\"%s\" from GSettings key %s\n")((char *) g_dgettext ("marco", "Could not parse font description "
"\"%s\" from GSettings key %s\n"))
,
1209 string_value ? string_value : "(null)",
1210 KEY_GENERAL_TITLEBAR_FONT"titlebar-font");
1211
1212 *inform_listeners = FALSE(0);
1213
1214 return;
1215 }
1216
1217 /* Is the new description the same as the old? */
1218
1219 if (titlebar_font &&
1220 pango_font_description_equal (new_desc, titlebar_font))
1221 {
1222 pango_font_description_free (new_desc);
1223 *inform_listeners = FALSE(0);
1224 return;
1225 }
1226
1227 /* No, so free the old one and put ours in instead. */
1228
1229 if (titlebar_font)
1230 pango_font_description_free (titlebar_font);
1231
1232 titlebar_font = new_desc;
1233
1234}
1235
1236static void
1237theme_name_handler (MetaPreference pref,
1238 const gchar *string_value,
1239 gboolean *inform_listeners)
1240{
1241 g_free (current_theme);
1242
1243 /* Fallback crackrock */
1244 if (string_value == NULL((void*)0))
1245 current_theme = g_strdup ("ClearlooksRe")g_strdup_inline ("ClearlooksRe");
1246 else
1247 current_theme = g_strdup (string_value)g_strdup_inline (string_value);
1248}
1249
1250static void
1251mouse_button_mods_handler (MetaPreference pref,
1252 const gchar *string_value,
1253 gboolean *inform_listeners)
1254{
1255 MetaVirtualModifier mods;
1256
1257 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1258 "Mouse button modifier has new GSettings value \"%s\"\n",
1259 string_value);
1260 if (string_value && meta_ui_parse_modifier (string_value, &mods))
1261 {
1262 mouse_button_mods = mods;
1263 }
1264 else
1265 {
1266 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1267 "Failed to parse new GSettings value\n");
1268
1269 meta_warning (_("\"%s\" found in configuration database is "((char *) g_dgettext ("marco", "\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"))
1270 "not a valid value for mouse button modifier\n")((char *) g_dgettext ("marco", "\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"))
,
1271 string_value);
1272
1273 *inform_listeners = FALSE(0);
1274 }
1275}
1276
1277static void
1278show_desktop_skip_list_handler (MetaPreference pref,
1279 const gchar *string_value,
1280 gboolean *inform_listeners)
1281{
1282 gchar **tokens;
1283 gchar **tok;
1284 GList *item;
1285
1286 if (show_desktop_skip_list)
1287 {
1288 for (item = show_desktop_skip_list; item; item = item->next)
1289 g_free (item->data);
1290 g_list_free (show_desktop_skip_list);
1291 show_desktop_skip_list = NULL((void*)0);
1292 }
1293
1294 if (!(tokens = g_strsplit (string_value, ",", -1)))
1295 return;
1296 for (tok = tokens; tok && *tok; tok++)
1297 {
1298 gchar *stripped = g_strstrip (g_strdup (*tok))g_strchomp (g_strchug (g_strdup_inline (*tok)));
1299 show_desktop_skip_list = g_list_prepend (show_desktop_skip_list, stripped);
1300 }
1301 g_strfreev (tokens);
1302}
1303
1304static gboolean
1305button_layout_equal (const MetaButtonLayout *a,
1306 const MetaButtonLayout *b)
1307{
1308 int i;
1309
1310 i = 0;
1311 while (i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
1312 {
1313 if (a->left_buttons[i] != b->left_buttons[i])
1314 return FALSE(0);
1315 if (a->right_buttons[i] != b->right_buttons[i])
1316 return FALSE(0);
1317 if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1318 return FALSE(0);
1319 if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1320 return FALSE(0);
1321 ++i;
1322 }
1323
1324 return TRUE(!(0));
1325}
1326
1327static MetaButtonFunction
1328button_function_from_string (const char *str)
1329{
1330 /* FIXME: g_settings_get_enum is the obvious way to do this */
1331
1332 if (strcmp (str, "menu") == 0)
1333 return META_BUTTON_FUNCTION_MENU;
1334 else if (strcmp (str, "appmenu") == 0)
1335 return META_BUTTON_FUNCTION_APPMENU;
1336 else if (strcmp (str, "minimize") == 0)
1337 return META_BUTTON_FUNCTION_MINIMIZE;
1338 else if (strcmp (str, "maximize") == 0)
1339 return META_BUTTON_FUNCTION_MAXIMIZE;
1340 else if (strcmp (str, "close") == 0)
1341 return META_BUTTON_FUNCTION_CLOSE;
1342 else if (strcmp (str, "shade") == 0)
1343 return META_BUTTON_FUNCTION_SHADE;
1344 else if (strcmp (str, "above") == 0)
1345 return META_BUTTON_FUNCTION_ABOVE;
1346 else if (strcmp (str, "stick") == 0)
1347 return META_BUTTON_FUNCTION_STICK;
1348 else
1349 /* don't know; give up */
1350 return META_BUTTON_FUNCTION_LAST;
1351}
1352
1353static MetaButtonFunction
1354button_opposite_function (MetaButtonFunction ofwhat)
1355{
1356 switch (ofwhat)
1357 {
1358 case META_BUTTON_FUNCTION_SHADE:
1359 return META_BUTTON_FUNCTION_UNSHADE;
1360 case META_BUTTON_FUNCTION_UNSHADE:
1361 return META_BUTTON_FUNCTION_SHADE;
1362
1363 case META_BUTTON_FUNCTION_ABOVE:
1364 return META_BUTTON_FUNCTION_UNABOVE;
1365 case META_BUTTON_FUNCTION_UNABOVE:
1366 return META_BUTTON_FUNCTION_ABOVE;
1367
1368 case META_BUTTON_FUNCTION_STICK:
1369 return META_BUTTON_FUNCTION_UNSTICK;
1370 case META_BUTTON_FUNCTION_UNSTICK:
1371 return META_BUTTON_FUNCTION_STICK;
1372
1373 default:
1374 return META_BUTTON_FUNCTION_LAST;
1375 }
1376}
1377
1378static void
1379button_layout_handler (MetaPreference pref,
1380 const gchar *string_value,
1381 gboolean *inform_listeners)
1382{
1383 MetaButtonLayout new_layout;
1384 char **sides = NULL((void*)0);
1385 int i;
1386
1387 /* We need to ignore unknown button functions, for
1388 * compat with future versions
1389 */
1390
1391 if (string_value)
1
Assuming 'string_value' is null
1392 sides = g_strsplit (string_value, ":", 2);
1393
1394 if (sides
1.1
'sides' is equal to NULL
!= NULL((void*)0) && sides[0] != NULL((void*)0))
1395 {
1396 char **buttons;
1397 int b;
1398 gboolean used[META_BUTTON_FUNCTION_LAST];
1399
1400 i = 0;
1401 while (i < META_BUTTON_FUNCTION_LAST)
1402 {
1403 used[i] = FALSE(0);
1404 new_layout.left_buttons_has_spacer[i] = FALSE(0);
1405 ++i;
1406 }
1407
1408 buttons = g_strsplit (sides[0], ",", -1);
1409 i = 0;
1410 b = 0;
1411 while (buttons[b] != NULL((void*)0))
1412 {
1413 MetaButtonFunction f = button_function_from_string (buttons[b]);
1414 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1415 {
1416 new_layout.left_buttons_has_spacer[i-1] = TRUE(!(0));
1417 f = button_opposite_function (f);
1418
1419 if (f != META_BUTTON_FUNCTION_LAST)
1420 {
1421 new_layout.left_buttons_has_spacer[i-2] = TRUE(!(0));
1422 }
1423 }
1424 else
1425 {
1426 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1427 {
1428 new_layout.left_buttons[i] = f;
1429 used[f] = TRUE(!(0));
1430 ++i;
1431
1432 f = button_opposite_function (f);
1433
1434 if (f != META_BUTTON_FUNCTION_LAST)
1435 new_layout.left_buttons[i++] = f;
1436
1437 }
1438 else
1439 {
1440 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1441 buttons[b]);
1442 }
1443 }
1444
1445 ++b;
1446 }
1447
1448 new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1449 new_layout.left_buttons_has_spacer[i] = FALSE(0);
1450
1451 g_strfreev (buttons);
1452 }
1453
1454 if (sides
1.2
'sides' is equal to NULL
!= NULL((void*)0) && sides[0] != NULL((void*)0) && sides[1] != NULL((void*)0))
1455 {
1456 char **buttons;
1457 int b;
1458 gboolean used[META_BUTTON_FUNCTION_LAST];
1459
1460 i = 0;
1461 while (i < META_BUTTON_FUNCTION_LAST)
1462 {
1463 used[i] = FALSE(0);
1464 new_layout.right_buttons_has_spacer[i] = FALSE(0);
1465 ++i;
1466 }
1467
1468 buttons = g_strsplit (sides[1], ",", -1);
1469 i = 0;
1470 b = 0;
1471 while (buttons[b] != NULL((void*)0))
1472 {
1473 MetaButtonFunction f = button_function_from_string (buttons[b]);
1474 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1475 {
1476 new_layout.right_buttons_has_spacer[i-1] = TRUE(!(0));
1477 f = button_opposite_function (f);
1478 if (f != META_BUTTON_FUNCTION_LAST)
1479 {
1480 new_layout.right_buttons_has_spacer[i-2] = TRUE(!(0));
1481 }
1482 }
1483 else
1484 {
1485 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1486 {
1487 new_layout.right_buttons[i] = f;
1488 used[f] = TRUE(!(0));
1489 ++i;
1490
1491 f = button_opposite_function (f);
1492
1493 if (f != META_BUTTON_FUNCTION_LAST)
1494 new_layout.right_buttons[i++] = f;
1495
1496 }
1497 else
1498 {
1499 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1500 buttons[b]);
1501 }
1502 }
1503
1504 ++b;
1505 }
1506
1507 new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1508 new_layout.right_buttons_has_spacer[i] = FALSE(0);
1509
1510 g_strfreev (buttons);
1511 }
1512
1513 g_strfreev (sides);
1514
1515 /* Invert the button layout for RTL languages */
1516 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
2
Assuming the condition is true
3
Taking true branch
1517 {
1518 MetaButtonLayout rtl_layout;
1519 int j;
1520
1521 for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
4
The value 0 is assigned to 'i'
5
The left operand of '!=' is a garbage value
1522 for (j = 0; j < i; j++)
1523 {
1524 rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1525 if (j == 0)
1526 rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1527 else
1528 rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1529 }
1530 rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1531 rtl_layout.right_buttons_has_spacer[j] = FALSE(0);
1532
1533 for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1534 for (j = 0; j < i; j++)
1535 {
1536 rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1537 if (j == 0)
1538 rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1539 else
1540 rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1541 }
1542 rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1543 rtl_layout.left_buttons_has_spacer[j] = FALSE(0);
1544
1545 new_layout = rtl_layout;
1546 }
1547
1548 if (button_layout_equal (&button_layout, &new_layout))
1549 {
1550 /* Same as before, so duck out */
1551 *inform_listeners = FALSE(0);
1552 }
1553 else
1554 {
1555 button_layout = new_layout;
1556 }
1557}
1558
1559const PangoFontDescription*
1560meta_prefs_get_titlebar_font (void)
1561{
1562 if (use_system_font)
1563 return NULL((void*)0);
1564 else
1565 return titlebar_font;
1566}
1567
1568int
1569meta_prefs_get_num_workspaces (void)
1570{
1571 return num_workspaces;
1572}
1573
1574MetaWrapStyle
1575meta_prefs_get_wrap_style (void)
1576{
1577 return wrap_style;
1578}
1579
1580gboolean
1581meta_prefs_get_application_based (void)
1582{
1583 return FALSE(0); /* For now, we never want this to do anything */
1584
1585 return application_based;
1586}
1587
1588gboolean
1589meta_prefs_get_disable_workarounds (void)
1590{
1591 return disable_workarounds;
1592}
1593
1594#define MAX_REASONABLE_AUTO_RAISE_DELAY10000 10000
1595
1596#ifdef WITH_VERBOSE_MODE1
1597const char*
1598meta_preference_to_string (MetaPreference pref)
1599{
1600 /* FIXME: another case for g_settings_get_enum */
1601 switch (pref)
1602 {
1603 case META_PREF_MOUSE_BUTTON_MODS:
1604 return "MOUSE_BUTTON_MODS";
1605
1606 case META_PREF_FOCUS_MODE:
1607 return "FOCUS_MODE";
1608
1609 case META_PREF_FOCUS_NEW_WINDOWS:
1610 return "FOCUS_NEW_WINDOWS";
1611
1612 case META_PREF_ATTACH_MODAL_DIALOGS:
1613 return "ATTACH_MODAL_DIALOGS";
1614
1615 case META_PREF_RAISE_ON_CLICK:
1616 return "RAISE_ON_CLICK";
1617
1618 case META_PREF_THEME:
1619 return "THEME";
1620
1621 case META_PREF_TITLEBAR_FONT:
1622 return "TITLEBAR_FONT";
1623
1624 case META_PREF_NUM_WORKSPACES:
1625 return "NUM_WORKSPACES";
1626
1627 case META_PREF_WRAP_STYLE:
1628 return "WRAP_STYLE";
1629
1630 case META_PREF_APPLICATION_BASED:
1631 return "APPLICATION_BASED";
1632
1633 case META_PREF_KEYBINDINGS:
1634 return "KEYBINDINGS";
1635
1636 case META_PREF_DISABLE_WORKAROUNDS:
1637 return "DISABLE_WORKAROUNDS";
1638
1639 case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1640 return "ACTION_DOUBLE_CLICK_TITLEBAR";
1641
1642 case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1643 return "ACTION_MIDDLE_CLICK_TITLEBAR";
1644
1645 case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1646 return "ACTION_RIGHT_CLICK_TITLEBAR";
1647
1648 case META_PREF_AUTO_RAISE:
1649 return "AUTO_RAISE";
1650
1651 case META_PREF_AUTO_RAISE_DELAY:
1652 return "AUTO_RAISE_DELAY";
1653
1654 case META_PREF_COMMANDS:
1655 return "COMMANDS";
1656
1657 case META_PREF_TERMINAL_COMMAND:
1658 return "TERMINAL_COMMAND";
1659
1660 case META_PREF_BUTTON_LAYOUT:
1661 return "BUTTON_LAYOUT";
1662
1663 case META_PREF_WORKSPACE_NAMES:
1664 return "WORKSPACE_NAMES";
1665
1666 case META_PREF_VISUAL_BELL:
1667 return "VISUAL_BELL";
1668
1669 case META_PREF_AUDIBLE_BELL:
1670 return "AUDIBLE_BELL";
1671
1672 case META_PREF_VISUAL_BELL_TYPE:
1673 return "VISUAL_BELL_TYPE";
1674
1675 case META_PREF_REDUCED_RESOURCES:
1676 return "REDUCED_RESOURCES";
1677
1678 case META_PREF_MATE_ACCESSIBILITY:
1679 return "MATE_ACCESSIBILTY";
1680
1681 case META_PREF_MATE_ANIMATIONS:
1682 return "MATE_ANIMATIONS";
1683
1684 case META_PREF_CURSOR_THEME:
1685 return "CURSOR_THEME";
1686
1687 case META_PREF_CURSOR_SIZE:
1688 return "CURSOR_SIZE";
1689
1690 case META_PREF_ICON_SIZE:
1691 return "ICON_SIZE";
1692
1693 case META_PREF_ALT_TAB_MAX_COLUMNS:
1694 return "ALT_TAB_MAX_COLUMNS";
1695
1696 case META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE:
1697 return "ALT_TAB_EXPAND_TO_FIT_TITLE";
1698
1699 case META_PREF_ALT_TAB_RAISE_WINDOWS:
1700 return "ALT_TAB_RAISE_WINDOWS";
1701
1702 case META_PREF_COMPOSITING_MANAGER:
1703 return "COMPOSITING_MANAGER";
1704
1705 case META_PREF_COMPOSITING_FAST_ALT_TAB:
1706 return "COMPOSITING_FAST_ALT_TAB";
1707
1708 case META_PREF_CENTER_NEW_WINDOWS:
1709 return "CENTER_NEW_WINDOWS";
1710
1711 case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1712 return "RESIZE_WITH_RIGHT_BUTTON";
1713
1714 case META_PREF_SHOW_TAB_BORDER:
1715 return "SHOW_TAB_BORDER";
1716
1717 case META_PREF_FORCE_FULLSCREEN:
1718 return "FORCE_FULLSCREEN";
1719
1720 case META_PREF_ALLOW_TILING:
1721 return "ALLOW_TILING";
1722
1723 case META_PREF_ALLOW_TOP_TILING:
1724 return "ALLOW_TOP_TILING";
1725
1726 case META_PREF_ALLOW_TILE_CYCLING:
1727 return "ALLOW_TILE_CYCLING";
1728
1729 case META_PREF_PLACEMENT_MODE:
1730 return "PLACEMENT_MODE";
1731
1732 case META_PREF_SHOW_DESKTOP_SKIP_LIST:
1733 return "SHOW_DESKTOP_SKIP_LIST";
1734 }
1735
1736 return "(unknown)";
1737}
1738#endif /* WITH_VERBOSE_MODE */
1739
1740void
1741meta_prefs_set_num_workspaces (int n_workspaces)
1742{
1743 if (n_workspaces < 1)
1744 n_workspaces = 1;
1745 if (n_workspaces > MAX_REASONABLE_WORKSPACES36)
1746 n_workspaces = MAX_REASONABLE_WORKSPACES36;
1747
1748 g_settings_set_int (settings_general,
1749 KEY_GENERAL_NUM_WORKSPACES"num-workspaces",
1750 n_workspaces);
1751
1752}
1753
1754#define keybind(name, handler, param, flags) \
1755 { #name, NULL((void*)0), !!(flags & BINDING_REVERSES0x02), !!(flags & BINDING_PER_WINDOW0x01) },
1756static MetaKeyPref key_bindings[] = {
1757#include "all-keybindings.h"
1758 { NULL((void*)0), NULL((void*)0), FALSE(0) }
1759};
1760#undef keybind
1761
1762static void
1763init_bindings (GSettings *settings)
1764{
1765 GSettingsSchema *schema;
1766 gchar **list;
1767 gsize i;
1768
1769 g_object_get (settings, "settings-schema", &schema, NULL((void*)0));
1770 list = g_settings_schema_list_keys (schema);
1771 g_settings_schema_unref (schema);
1772
1773 for (i = 0; list[i] != NULL((void*)0); i++)
1774 {
1775 gchar *str_val;
1776
1777 str_val = g_settings_get_string (settings, list[i]);
1778 update_key_binding (list[i], str_val);
1779 g_free (str_val);
1780 }
1781
1782 g_strfreev (list);
1783}
1784
1785static void
1786init_screen_bindings (void)
1787{
1788 init_bindings (settings_screen_bindings);
1789}
1790
1791static void
1792init_window_bindings (void)
1793{
1794 init_bindings (settings_window_bindings);
1795}
1796
1797static void
1798init_commands (void)
1799{
1800 GSettingsSchema *schema;
1801 gchar **list;
1802 gsize i;
1803
1804 g_object_get (settings_command, "settings-schema", &schema, NULL((void*)0));
1805 list = g_settings_schema_list_keys (schema);
1806 g_settings_schema_unref (schema);
1807
1808 for (i = 0; list[i] != NULL((void*)0); i++)
1809 {
1810 gchar *str_val;
1811
1812 str_val = g_settings_get_string (settings_command, list[i]);
1813 update_command (list[i], str_val);
1814 g_free (str_val);
1815 }
1816
1817 g_strfreev (list);
1818}
1819
1820static void
1821init_workspace_names (void)
1822{
1823 GSettingsSchema *schema;
1824 gchar **list;
1825 gsize i;
1826
1827 g_object_get (settings_workspace_names, "settings-schema", &schema, NULL((void*)0));
1828 list = g_settings_schema_list_keys (schema);
1829 g_settings_schema_unref (schema);
1830
1831 for (i = 0; list[i] != NULL((void*)0); i++)
1832 {
1833 gchar *str_val;
1834
1835 str_val = g_settings_get_string (settings_workspace_names, list[i]);
1836 update_workspace_name (list[i], str_val);
1837 g_free (str_val);
1838 }
1839
1840 g_strfreev (list);
1841}
1842
1843static gboolean
1844update_binding (MetaKeyPref *binding,
1845 gchar *value)
1846{
1847 unsigned int keysym;
1848 unsigned int keycode;
1849 MetaVirtualModifier mods;
1850 MetaKeyCombo *combo;
1851 gboolean changed;
1852
1853 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1854 "Binding \"%s\" has new GSettings value \"%s\"\n",
1855 binding->name, value ? value : "none");
1856
1857 keysym = 0;
1858 keycode = 0;
1859 mods = 0;
1860 if (value)
1861 {
1862 if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
1863 {
1864 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1865 "Failed to parse new GSettings value\n");
1866 meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n")((char *) g_dgettext ("marco", "\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"
))
,
1867 value, binding->name);
1868
1869 return FALSE(0);
1870 }
1871 }
1872
1873 /* If there isn't already a first element, make one. */
1874 if (!binding->bindings)
1875 {
1876 MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
1877 binding->bindings = g_slist_alloc();
1878 binding->bindings->data = blank;
1879 }
1880
1881 combo = binding->bindings->data;
1882
1883 /* Bug 329676: Bindings which can be shifted must not have no modifiers,
1884 * nor only SHIFT as a modifier.
1885 */
1886
1887 if (binding->add_shift &&
1888 0 != keysym &&
1889 (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
1890 {
1891 gchar *old_setting;
1892
1893 meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
1894 "such as Ctrl or Alt.\n",
1895 binding->name,
1896 value);
1897
1898 old_setting = meta_ui_accelerator_name (combo->keysym,
1899 combo->modifiers);
1900
1901 if (!strcmp(old_setting, value))
1902 {
1903 /* We were about to set it to the same value
1904 * that it had originally! This must be caused
1905 * by getting an invalid string back from
1906 * meta_ui_accelerator_name. Bail out now
1907 * so we don't get into an infinite loop.
1908 */
1909 g_free (old_setting);
1910 return TRUE(!(0));
1911 }
1912
1913 meta_warning ("Reverting \"%s\" to %s.\n",
1914 binding->name,
1915 old_setting);
1916
1917 /* FIXME: add_shift is currently screen_bindings only, but
1918 * there's no really good reason it should always be.
1919 * So we shouldn't blindly add KEY_SCREEN_BINDINGS_PREFIX
1920 * onto here.
1921 */
1922 g_settings_set_string(settings_screen_bindings,
1923 binding->name,
1924 old_setting);
1925
1926 g_free (old_setting);
1927
1928 /* The call to g_settings_set_string() will cause this function
1929 * to be called again with the new value, so there's no need to
1930 * carry on.
1931 */
1932 return TRUE(!(0));
1933 }
1934
1935 changed = FALSE(0);
1936 if (keysym != combo->keysym ||
1937 keycode != combo->keycode ||
1938 mods != combo->modifiers)
1939 {
1940 changed = TRUE(!(0));
1941
1942 combo->keysym = keysym;
1943 combo->keycode = keycode;
1944 combo->modifiers = mods;
1945
1946 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1947 "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
1948 binding->name, combo->keysym, combo->keycode,
1949 combo->modifiers);
1950 }
1951 else
1952 {
1953 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1954 "Keybinding for \"%s\" is unchanged\n", binding->name);
1955 }
1956
1957 return changed;
1958}
1959
1960static const gchar*
1961relative_key (const gchar* key)
1962{
1963 const gchar* end;
1964
1965 end = strrchr (key, '/');
1966
1967 ++end;
1968
1969 return end;
1970}
1971
1972/* Return value is TRUE if a preference changed and we need to
1973 * notify
1974 */
1975static gboolean
1976find_and_update_binding (MetaKeyPref *bindings,
1977 const char *name,
1978 gchar *value)
1979{
1980 const char *key;
1981 int i;
1982
1983 if (*name == '/')
1984 key = relative_key (name);
1985 else
1986 key = name;
1987
1988 i = 0;
1989 while (bindings[i].name &&
1990 strcmp (key, bindings[i].name) != 0)
1991 ++i;
1992
1993 if (bindings[i].name)
1994 return update_binding (&bindings[i], value);
1995 else
1996 return FALSE(0);
1997}
1998
1999static gboolean
2000update_key_binding (const char *name,
2001 gchar *value)
2002{
2003 return find_and_update_binding (key_bindings, name, value);
2004}
2005
2006static gboolean
2007update_command (const char *name,
2008 const char *value)
2009{
2010 char *p;
2011 int i;
2012
2013 p = strrchr (name, '-');
2014 if (p == NULL((void*)0))
2015 {
2016 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2017 "Command %s has no dash?\n", name);
2018 return FALSE(0);
2019 }
2020
2021 ++p;
2022
2023 if (g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0))
2024 {
2025 i = atoi (p);
2026 i -= 1; /* count from 0 not 1 */
2027 }
2028 else
2029 {
2030 if (strcmp (name, "command-screenshot") == 0)
2031 {
2032 i = SCREENSHOT_COMMAND_IDX((32 + 2) - 2);
2033 }
2034 else if (strcmp (name, "command-window-screenshot") == 0)
2035 {
2036 i = WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1);
2037 }
2038 else
2039 {
2040 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2041 "Command %s doesn't end in number?\n", name);
2042 return FALSE(0);
2043 }
2044 }
2045
2046 if (i >= MAX_COMMANDS(32 + 2))
2047 {
2048 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2049 "Command %d is too highly numbered, ignoring\n", i);
2050 return FALSE(0);
2051 }
2052
2053 if ((commands[i] == NULL((void*)0) && value == NULL((void*)0)) ||
2054 (commands[i] && value && strcmp (commands[i], value) == 0))
2055 {
2056 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2057 "Command %d is unchanged\n", i);
2058 return FALSE(0);
2059 }
2060
2061 g_free (commands[i]);
2062 commands[i] = g_strdup (value)g_strdup_inline (value);
2063
2064 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2065 "Updated command %d to \"%s\"\n",
2066 i, commands[i] ? commands[i] : "none");
2067
2068 return TRUE(!(0));
2069}
2070
2071const char*
2072meta_prefs_get_command (int i)
2073{
2074 g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL)do { if ((i >= 0 && i < (32 + 2))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_COMMANDS"
); return (((void*)0)); } } while (0)
;
2075
2076 return commands[i];
2077}
2078
2079char*
2080meta_prefs_get_settings_key_for_command (int i)
2081{
2082 char *key;
2083
2084 switch (i)
2085 {
2086 case SCREENSHOT_COMMAND_IDX((32 + 2) - 2):
2087 key = g_strdup (KEY_COMMAND_PREFIX "screenshot")g_strdup_inline ("command-" "screenshot");
2088 break;
2089 case WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1):
2090 key = g_strdup (KEY_COMMAND_PREFIX "window-screenshot")g_strdup_inline ("command-" "window-screenshot");
2091 break;
2092 default:
2093 key = g_strdup_printf (KEY_COMMAND_PREFIX"command-""%d", i + 1);
2094 break;
2095 }
2096
2097 return key;
2098}
2099
2100const char*
2101meta_prefs_get_terminal_command (void)
2102{
2103 return terminal_command;
2104}
2105
2106const char*
2107meta_prefs_get_settings_key_for_terminal_command (void)
2108{
2109 return KEY_MATE_TERMINAL_COMMAND"exec";
2110}
2111
2112static gboolean
2113update_workspace_name (const char *name,
2114 const char *value)
2115{
2116 char *p;
2117 int i;
2118
2119 p = strrchr (name, '-');
2120 if (p == NULL((void*)0))
2121 {
2122 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2123 "Workspace name %s has no dash?\n", name);
2124 return FALSE(0);
2125 }
2126
2127 ++p;
2128
2129 if (!g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0))
2130 {
2131 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2132 "Workspace name %s doesn't end in number?\n", name);
2133 return FALSE(0);
2134 }
2135
2136 i = atoi (p);
2137 i -= 1; /* count from 0 not 1 */
2138
2139 if (i >= MAX_REASONABLE_WORKSPACES36)
2140 {
2141 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2142 "Workspace name %d is too highly numbered, ignoring\n", i);
2143 return FALSE(0);
2144 }
2145
2146 if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2147 {
2148 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2149 "Workspace name %d is unchanged\n", i);
2150 return FALSE(0);
2151 }
2152
2153 /* This is a bad hack. We have to treat empty string as
2154 * "unset" because the root window property can't contain
2155 * null. So it gets empty string instead and we don't want
2156 * that to result in setting the empty string as a value that
2157 * overrides "unset".
2158 */
2159 if (value != NULL((void*)0) && *value != '\0')
2160 {
2161 g_free (workspace_names[i]);
2162 workspace_names[i] = g_strdup (value)g_strdup_inline (value);
2163 }
2164 else
2165 {
2166 /* use a default name */
2167 char *d;
2168
2169 d = g_strdup_printf (_("Workspace %d")((char *) g_dgettext ("marco", "Workspace %d")), i + 1);
2170 if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2171 {
2172 g_free (d);
2173 return FALSE(0);
2174 }
2175 else
2176 {
2177 g_free (workspace_names[i]);
2178 workspace_names[i] = d;
2179 }
2180 }
2181
2182 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2183 "Updated workspace name %d to \"%s\"\n",
2184 i, workspace_names[i] ? workspace_names[i] : "none");
2185
2186 return TRUE(!(0));
2187}
2188
2189const char*
2190meta_prefs_get_workspace_name (int i)
2191{
2192 g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL)do { if ((i >= 0 && i < 36)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_REASONABLE_WORKSPACES"
); return (((void*)0)); } } while (0)
;
2193
2194 g_assert (workspace_names[i] != NULL)do { if (workspace_names[i] != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/prefs.c", 2194, ((const char*) (__func__)), "workspace_names[i] != NULL"
); } while (0)
;
2195
2196 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2197 "Getting workspace name for %d: \"%s\"\n",
2198 i, workspace_names[i]);
2199
2200 return workspace_names[i];
2201}
2202
2203void
2204meta_prefs_change_workspace_name (int i,
2205 const char *name)
2206{
2207 char *key;
2208
2209 g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES)do { if ((i >= 0 && i < 36)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_REASONABLE_WORKSPACES"
); return; } } while (0)
;
2210
2211 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2212 "Changing name of workspace %d to %s\n",
2213 i, name ? name : "none");
2214
2215 if (name && *name == '\0')
2216 name = NULL((void*)0);
2217
2218 if ((name == NULL((void*)0) && workspace_names[i] == NULL((void*)0)) ||
2219 (name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2220 {
2221 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2222 "Workspace %d already has name %s\n",
2223 i, name ? name : "none");
2224 return;
2225 }
2226
2227 key = settings_key_for_workspace_name (i);
2228
2229 if (name != NULL((void*)0))
2230 g_settings_set_string (settings_workspace_names,
2231 key,
2232 name);
2233 else
2234 g_settings_set_string (settings_workspace_names,
2235 key,
2236 "");
2237
2238 g_free (key);
2239}
2240
2241static char*
2242settings_key_for_workspace_name (int i)
2243{
2244 char *key;
2245
2246 key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"name-""%d", i + 1);
2247
2248 return key;
2249}
2250
2251void
2252meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2253{
2254 *button_layout_p = button_layout;
2255}
2256
2257gboolean
2258meta_prefs_get_visual_bell (void)
2259{
2260 return provide_visual_bell;
2261}
2262
2263gboolean
2264meta_prefs_bell_is_audible (void)
2265{
2266 return bell_is_audible;
2267}
2268
2269MetaVisualBellType
2270meta_prefs_get_visual_bell_type (void)
2271{
2272 return visual_bell_type;
2273}
2274
2275void
2276meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2277 int *n_bindings)
2278{
2279
2280 *bindings = key_bindings;
2281 *n_bindings = (int) G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 1;
2282}
2283
2284MetaActionTitlebar
2285meta_prefs_get_action_double_click_titlebar (void)
2286{
2287 return action_double_click_titlebar;
2288}
2289
2290MetaActionTitlebar
2291meta_prefs_get_action_middle_click_titlebar (void)
2292{
2293 return action_middle_click_titlebar;
2294}
2295
2296MetaActionTitlebar
2297meta_prefs_get_action_right_click_titlebar (void)
2298{
2299 return action_right_click_titlebar;
2300}
2301
2302gboolean
2303meta_prefs_get_auto_raise (void)
2304{
2305 return auto_raise;
2306}
2307
2308int
2309meta_prefs_get_auto_raise_delay (void)
2310{
2311 return auto_raise_delay;
2312}
2313
2314gboolean
2315meta_prefs_get_reduced_resources (void)
2316{
2317 return reduced_resources;
2318}
2319
2320gboolean
2321meta_prefs_get_mate_accessibility ()
2322{
2323 return mate_accessibility;
2324}
2325
2326gboolean
2327meta_prefs_get_mate_animations ()
2328{
2329 return mate_animations;
2330}
2331
2332MetaKeyBindingAction
2333meta_prefs_get_keybinding_action (const char *name)
2334{
2335 int i;
2336
2337 i = G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 2; /* -2 for dummy entry at end */
2338 while (i >= 0)
2339 {
2340 if (strcmp (key_bindings[i].name, name) == 0)
2341 return (MetaKeyBindingAction) i;
2342
2343 --i;
2344 }
2345
2346 return META_KEYBINDING_ACTION_NONE;
2347}
2348
2349/* This is used by the menu system to decide what key binding
2350 * to display next to an option. We return the first non-disabled
2351 * binding, if any.
2352 */
2353void
2354meta_prefs_get_window_binding (const char *name,
2355 unsigned int *keysym,
2356 MetaVirtualModifier *modifiers)
2357{
2358 int i;
2359
2360 i = G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 2; /* -2 for dummy entry at end */
2361 while (i >= 0)
2362 {
2363 if (key_bindings[i].per_window &&
2364 strcmp (key_bindings[i].name, name) == 0)
2365 {
2366 GSList *s = key_bindings[i].bindings;
2367
2368 while (s)
2369 {
2370 MetaKeyCombo *c = s->data;
2371
2372 if (c->keysym!=0 || c->modifiers!=0)
2373 {
2374 *keysym = c->keysym;
2375 *modifiers = c->modifiers;
2376 return;
2377 }
2378
2379 s = s->next;
2380 }
2381
2382 /* Not found; return the disabled value */
2383 *keysym = *modifiers = 0;
2384 return;
2385 }
2386
2387 --i;
2388 }
2389
2390 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/prefs.c", 2390,
((const char*) (__func__)), ((void*)0)); } while (0)
;
2391}
2392
2393gboolean
2394meta_prefs_get_compositing_manager (void)
2395{
2396 if (use_force_compositor_manager)
2397 return force_compositor_manager;
2398 return compositing_manager;
2399}
2400
2401gboolean
2402meta_prefs_get_compositing_fast_alt_tab (void)
2403{
2404 return compositing_fast_alt_tab;
2405}
2406
2407gboolean
2408meta_prefs_get_center_new_windows (void)
2409{
2410 return center_new_windows;
2411}
2412
2413gboolean
2414meta_prefs_get_allow_tiling ()
2415{
2416 return allow_tiling;
2417}
2418
2419gboolean
2420meta_prefs_get_allow_top_tiling ()
2421{
2422 return allow_top_tiling;
2423}
2424
2425gboolean
2426meta_prefs_get_allow_tile_cycling ()
2427{
2428 return allow_tile_cycling;
2429}
2430
2431guint
2432meta_prefs_get_mouse_button_resize (void)
2433{
2434 return resize_with_right_button ? 3: 2;
2435}
2436
2437guint
2438meta_prefs_get_mouse_button_menu (void)
2439{
2440 return resize_with_right_button ? 2: 3;
2441}
2442
2443gboolean
2444meta_prefs_show_tab_border(void)
2445{
2446 return show_tab_border;
2447}
2448
2449gboolean
2450meta_prefs_get_force_fullscreen (void)
2451{
2452 return force_fullscreen;
2453}
2454
2455MetaPlacementMode
2456meta_prefs_get_placement_mode (void)
2457{
2458 return placement_mode;
2459}
2460
2461void
2462meta_prefs_set_force_compositing_manager (gboolean whether)
2463{
2464 use_force_compositor_manager = TRUE(!(0));
2465 force_compositor_manager = whether;
2466}
2467
2468void
2469meta_prefs_set_compositing_fast_alt_tab (gboolean whether)
2470{
2471 g_settings_set_boolean (settings_general,
2472 KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB"compositing-fast-alt-tab",
2473 whether);
2474}
2475
2476void
2477meta_prefs_set_center_new_windows (gboolean whether)
2478{
2479 g_settings_set_boolean (settings_general,
2480 KEY_GENERAL_CENTER_NEW_WINDOWS"center-new-windows",
2481 whether);
2482}
2483
2484void
2485meta_prefs_set_force_fullscreen (gboolean whether)
2486{
2487 force_fullscreen = whether;
2488}
2489
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-b7dd8c.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-b7dd8c.html new file mode 100644 index 00000000..ce0ee4ad --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-b7dd8c.html @@ -0,0 +1,937 @@ + + + +test-resizing.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:wm-tester/test-resizing.c
Warning:line 139, column 3
Value stored to 'mask' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name test-resizing.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src/wm-tester -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src/wm-tester -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c test-resizing.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1#include <X11/Xlib.h>
2#include <X11/Xutil.h>
3#include <stdlib.h>
4#include <glib.h>
5
6static void
7calc_rects (XRectangle *rects, int width, int height)
8{
9 int w = (width - 21) / 3;
10 int h = (height - 21) / 3;
11 int i;
12
13 i = 0;
14 while (i < 9)
15 {
16 rects[i].width = w;
17 rects[i].height = h;
18 ++i;
19 }
20
21 /* NW */
22 rects[0].x = 0;
23 rects[0].y = 0;
24
25 /* N */
26 rects[1].x = width / 2 - w / 2;
27 rects[1].y = 0;
28
29 /* NE */
30 rects[2].x = width - w;
31 rects[2].y = 0;
32
33 /* E */
34 rects[3].x = width - w;
35 rects[3].y = height / 2 - h / 2;
36
37 /* SE */
38 rects[4].x = width - w;
39 rects[4].y = height - h;
40
41 /* S */
42 rects[5].x = width / 2 - w / 2;
43 rects[5].y = height - h;
44
45 /* SW */
46 rects[6].x = 0;
47 rects[6].y = height - h;
48
49 /* W */
50 rects[7].x = 0;
51 rects[7].y = height / 2 - h / 2;
52
53 /* Center */
54 rects[8].x = width / 2 - w / 2;
55 rects[8].y = height / 2 - h / 2;
56}
57
58static Boolint
59all_events (Display *display,
60 XEvent *event,
61 XPointer arg)
62{
63 return True1;
64}
65
66static void
67get_size (Display *d, Drawable draw,
68 int *xp, int *yp, int *widthp, int *heightp)
69{
70 int x, y;
71 unsigned int width=0, height=0, border=0, depth=0;
72 Window root;
73
74 XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth);
75
76 if (xp)
77 *xp = x;
78 if (yp)
79 *yp = y;
80 if (widthp)
81 *widthp = width;
82 if (heightp)
83 *heightp = height;
84}
85
86int
87main (int argc, char **argv)
88{
89 Display *d;
90 Window w, cw;
91 XSizeHints hints;
92 int screen;
93 XEvent ev;
94 int x, y, width, height;
95 Pixmap pix;
96 GC gc;
97 XGCValues gc_vals;
98 XSetWindowAttributes set_attrs;
99 XWindowChanges changes;
100 XRectangle rects[9];
101 gboolean redraw_pending;
102 unsigned int mask;
103
104 d = XOpenDisplay (NULL((void*)0));
105
106 screen = DefaultScreen (d)(((_XPrivDisplay)(d))->default_screen);
107
108 /* Print some debug spew to show how StaticGravity works */
109 w = XCreateSimpleWindow (d, RootWindow (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root),
110 0, 0, 100, 100, 0,
111 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
112 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
113 cw = XCreateSimpleWindow (d, w,
114 0, 0, 100, 100, 0,
115 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
116 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
117 set_attrs.win_gravity = StaticGravity10;
118
119 XChangeWindowAttributes (d, cw,
120 CWWinGravity(1L<<5),
121 &set_attrs);
122
123 get_size (d, w, &x, &y, &width, &height);
124
125 g_print ("Parent is %d,%d %d x %d before configuring parent\n",
126 x, y, width, height);
127
128 get_size (d, cw, &x, &y, &width, &height);
129
130 g_print ("Child is %d,%d %d x %d before configuring parent\n",
131 x, y, width, height);
132
133 changes.x = 10;
134 changes.y = 10;
135 changes.width = 110;
136 changes.height = 110;
137 /* last mask wins */
138 mask = CWX(1<<0) | CWY(1<<1);
139 mask = CWWidth(1<<2) | CWHeight(1<<3);
Value stored to 'mask' is never read
140 mask = CWX(1<<0) | CWY(1<<1) | CWWidth(1<<2) | CWHeight(1<<3);
141
142 XConfigureWindow (d, w, mask, &changes);
143 XSync (d, False0);
144
145 get_size (d, w, &x, &y, &width, &height);
146
147 g_print ("Parent is %d,%d %d x %d after configuring parent\n",
148 x, y, width, height);
149
150 get_size (d, cw, &x, &y, &width, &height);
151
152 g_print ("Child is %d,%d %d x %d after configuring parent\n",
153 x, y, width, height);
154
155 XDestroyWindow (d, w);
156
157 /* The window that gets displayed */
158
159 x = 20;
160 y = 20;
161 width = 100;
162 height = 100;
163
164 calc_rects (rects, width, height);
165
166 w = XCreateSimpleWindow (d, RootWindow (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root),
167 x, y, width, height, 0,
168 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
169 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
170
171 set_attrs.bit_gravity = StaticGravity10;
172
173 XChangeWindowAttributes (d, w,
174 CWBitGravity(1L<<4),
175 &set_attrs);
176
177 XSelectInput (d, w,
178 ButtonPressMask(1L<<2) | ExposureMask(1L<<15) | StructureNotifyMask(1L<<17));
179
180 hints.flags = PMinSize(1L << 4);
181
182 hints.min_width = 100;
183 hints.min_height = 100;
184
185 XSetWMNormalHints (d, w, &hints);
186 XMapWindow (d, w);
187
188 redraw_pending = FALSE(0);
189 while (1)
190 {
191 XNextEvent (d, &ev);
192
193 switch (ev.xany.type)
194 {
195 case ButtonPress4:
196 if (ev.xbutton.button == 3)
197 {
198 g_print ("Exiting on button 3 press\n");
199 exit (0);
200 }
201 break;
202
203 case ConfigureNotify22:
204 x = ev.xconfigure.x;
205 y = ev.xconfigure.y;
206 width = ev.xconfigure.width;
207 height = ev.xconfigure.height;
208
209 redraw_pending = TRUE(!(0));
210 break;
211
212 case Expose12:
213 redraw_pending = TRUE(!(0));
214 break;
215
216 default:
217 break;
218 }
219
220 /* Primitive event compression */
221 if (XCheckIfEvent (d, &ev, all_events, NULL((void*)0)))
222 {
223 XPutBackEvent (d, &ev);
224 }
225 else if (redraw_pending)
226 {
227 calc_rects (rects, width, height);
228
229 pix = XCreatePixmap (d, w, width, height,
230 DefaultDepth (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root_depth
)
);
231
232 gc_vals.foreground = WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
;
233
234 gc = XCreateGC (d, pix, GCForeground(1L<<2), &gc_vals);
235
236 XFillRectangle (d, pix, gc, 0, 0, width, height);
237
238 /* Draw rectangles at each gravity point */
239 gc_vals.foreground = BlackPixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->black_pixel
)
;
240 XChangeGC (d, gc, GCForeground(1L<<2), &gc_vals);
241
242 XFillRectangles (d, pix, gc, rects, G_N_ELEMENTS (rects)(sizeof (rects) / sizeof ((rects)[0])));
243
244 XCopyArea (d, pix, w, gc, 0, 0, width, height, 0, 0);
245
246 XFreePixmap (d, pix);
247 XFreeGC (d, gc);
248
249 redraw_pending = FALSE(0);
250 }
251 }
252
253 /* This program has an infinite loop above so a return statement would
254 * just cause compiler warnings.
255 */
256}
257
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-c5605e.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-c5605e.html new file mode 100644 index 00000000..d019f423 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-c5605e.html @@ -0,0 +1,1961 @@ + + + +core/edge-resistance.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/edge-resistance.c
Warning:line 204, column 3
Value stored to 'compare' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name edge-resistance.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/edge-resistance.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Edge resistance for move/resize operations */
4
5/*
6 * Copyright (C) 2005, 2006 Elijah Newren
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <config.h>
25#include "edge-resistance.h"
26#include "boxes.h"
27#include "display-private.h"
28#include "workspace.h"
29
30/* A simple macro for whether a given window's edges are potentially
31 * relevant for resistance/snapping during a move/resize operation
32 */
33#define WINDOW_EDGES_RELEVANT(window, display)meta_window_should_be_showing (window) && window->
screen == display->grab_screen && window != display
->grab_window && window->type != META_WINDOW_DESKTOP
&& window->type != META_WINDOW_MENU && window
->type != META_WINDOW_SPLASHSCREEN
\
34 meta_window_should_be_showing (window) && \
35 window->screen == display->grab_screen && \
36 window != display->grab_window && \
37 window->type != META_WINDOW_DESKTOP && \
38 window->type != META_WINDOW_MENU && \
39 window->type != META_WINDOW_SPLASHSCREEN
40
41struct ResistanceDataForAnEdge
42{
43 gboolean timeout_setup;
44 guint timeout_id;
45 int timeout_edge_pos;
46 gboolean timeout_over;
47 GSourceFunc timeout_func;
48 MetaWindow *window;
49 int keyboard_buildup;
50};
51typedef struct ResistanceDataForAnEdge ResistanceDataForAnEdge;
52
53struct MetaEdgeResistanceData
54{
55 GArray *left_edges;
56 GArray *right_edges;
57 GArray *top_edges;
58 GArray *bottom_edges;
59
60 ResistanceDataForAnEdge left_data;
61 ResistanceDataForAnEdge right_data;
62 ResistanceDataForAnEdge top_data;
63 ResistanceDataForAnEdge bottom_data;
64};
65
66static void compute_resistance_and_snapping_edges (MetaDisplay *display);
67
68/* !WARNING!: this function can return invalid indices (namely, either -1 or
69 * edges->len); this is by design, but you need to remember this.
70 */
71static int
72find_index_of_edge_near_position (const GArray *edges,
73 int position,
74 gboolean want_interval_min,
75 gboolean horizontal)
76{
77 /* This is basically like a binary search, except that we're trying to
78 * find a range instead of an exact value. So, if we have in our array
79 * Value: 3 27 316 316 316 505 522 800 1213
80 * Index: 0 1 2 3 4 5 6 7 8
81 * and we call this function with position=500 & want_interval_min=TRUE
82 * then we should get 5 (because 505 is the first value bigger than 500).
83 * If we call this function with position=805 and want_interval_min=FALSE
84 * then we should get 7 (because 800 is the last value smaller than 800).
85 * A couple more, to make things clear:
86 * position want_interval_min correct_answer
87 * 316 TRUE 2
88 * 316 FALSE 4
89 * 2 FALSE -1
90 * 2000 TRUE 9
91 */
92 int low, high, mid;
93 int compare;
94 MetaEdge *edge;
95
96 /* Initialize mid, edge, & compare in the off change that the array only
97 * has one element.
98 */
99 mid = 0;
100 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
101 compare = horizontal ? edge->rect.x : edge->rect.y;
102
103 /* Begin the search... */
104 low = 0;
105 high = edges->len - 1;
106 while (low < high)
107 {
108 mid = low + (high - low)/2;
109 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
110 compare = horizontal ? edge->rect.x : edge->rect.y;
111
112 if (compare == position)
113 break;
114
115 if (compare > position)
116 high = mid - 1;
117 else
118 low = mid + 1;
119 }
120
121 /* mid should now be _really_ close to the index we want, so we start
122 * linearly searching. However, note that we don't know if mid is less
123 * than or greater than what we need and it's possible that there are
124 * several equal values equal to what we were searching for and we ended
125 * up in the middle of them instead of at the end. So we may need to
126 * move mid multiple locations over.
127 */
128 if (want_interval_min)
129 {
130 while (compare >= position && mid > 0)
131 {
132 mid--;
133 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
134 compare = horizontal ? edge->rect.x : edge->rect.y;
135 }
136 while (compare < position && mid < (int)edges->len - 1)
137 {
138 mid++;
139 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
140 compare = horizontal ? edge->rect.x : edge->rect.y;
141 }
142
143 /* Special case for no values in array big enough */
144 if (compare < position)
145 return edges->len;
146
147 /* Return the found value */
148 return mid;
149 }
150 else
151 {
152 while (compare <= position && mid < (int)edges->len - 1)
153 {
154 mid++;
155 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
156 compare = horizontal ? edge->rect.x : edge->rect.y;
157 }
158 while (compare > position && mid > 0)
159 {
160 mid--;
161 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
162 compare = horizontal ? edge->rect.x : edge->rect.y;
163 }
164
165 /* Special case for no values in array small enough */
166 if (compare > position)
167 return -1;
168
169 /* Return the found value */
170 return mid;
171 }
172}
173
174static gboolean
175points_on_same_side (int ref, int pt1, int pt2)
176{
177 return (pt1 - ref) * (pt2 - ref) > 0;
178}
179
180static int
181find_nearest_position (const GArray *edges,
182 int position,
183 int old_position,
184 const MetaRectangle *new_rect,
185 gboolean horizontal,
186 gboolean only_forward)
187{
188 /* This is basically just a binary search except that we're looking
189 * for the value closest to position, rather than finding that
190 * actual value. Also, we ignore any edges that aren't relevant
191 * given the horizontal/vertical position of new_rect.
192 */
193 int low, high, mid;
194 int compare;
195 MetaEdge *edge;
196 int best, best_dist, i;
197 gboolean edges_align;
198
199 /* Initialize mid, edge, & compare in the off change that the array only
200 * has one element.
201 */
202 mid = 0;
203 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
204 compare = horizontal ? edge->rect.x : edge->rect.y;
Value stored to 'compare' is never read
205
206 /* Begin the search... */
207 low = 0;
208 high = edges->len - 1;
209 while (low < high)
210 {
211 mid = low + (high - low)/2;
212 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
213 compare = horizontal ? edge->rect.x : edge->rect.y;
214
215 if (compare == position)
216 break;
217
218 if (compare > position)
219 high = mid - 1;
220 else
221 low = mid + 1;
222 }
223
224 /* mid should now be _really_ close to the index we want, so we
225 * start searching nearby for something that overlaps and is closer
226 * than the original position.
227 */
228 best = old_position;
229 best_dist = INT_MAX2147483647;
230
231 /* Start the search at mid */
232 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
233 compare = horizontal ? edge->rect.x : edge->rect.y;
234 edges_align = meta_rectangle_edge_aligns (new_rect, edge);
235 if (edges_align &&
236 (!only_forward || !points_on_same_side (position, compare, old_position)))
237 {
238 int dist = ABS (compare - position)(((compare - position) < 0) ? -(compare - position) : (compare
- position))
;
239 if (dist < best_dist)
240 {
241 best = compare;
242 best_dist = dist;
243 }
244 }
245
246 /* Now start searching higher than mid */
247 for (i = mid + 1; i < (int)edges->len; i++)
248 {
249 edge = g_array_index (edges, MetaEdge*, i)(((MetaEdge**) (void *) (edges)->data) [(i)]);
250 compare = horizontal ? edge->rect.x : edge->rect.y;
251
252 edges_align = horizontal ?
253 meta_rectangle_vert_overlap (&edge->rect, new_rect) :
254 meta_rectangle_horiz_overlap (&edge->rect, new_rect);
255
256 if (edges_align &&
257 (!only_forward ||
258 !points_on_same_side (position, compare, old_position)))
259 {
260 int dist = ABS (compare - position)(((compare - position) < 0) ? -(compare - position) : (compare
- position))
;
261 if (dist < best_dist)
262 {
263 best = compare;
264 best_dist = dist;
265 }
266 break;
267 }
268 }
269
270 /* Now start searching lower than mid */
271 for (i = mid-1; i >= 0; i--)
272 {
273 edge = g_array_index (edges, MetaEdge*, i)(((MetaEdge**) (void *) (edges)->data) [(i)]);
274 compare = horizontal ? edge->rect.x : edge->rect.y;
275
276 edges_align = horizontal ?
277 meta_rectangle_vert_overlap (&edge->rect, new_rect) :
278 meta_rectangle_horiz_overlap (&edge->rect, new_rect);
279
280 if (edges_align &&
281 (!only_forward ||
282 !points_on_same_side (position, compare, old_position)))
283 {
284 int dist = ABS (compare - position)(((compare - position) < 0) ? -(compare - position) : (compare
- position))
;
285 if (dist < best_dist)
286 {
287 best = compare;
288 }
289 break;
290 }
291 }
292
293 /* Return the best one found */
294 return best;
295}
296
297static gboolean
298movement_towards_edge (MetaSide side, int increment)
299{
300 switch (side)
301 {
302 case META_SIDE_LEFT:
303 case META_SIDE_TOP:
304 return increment < 0;
305 case META_SIDE_RIGHT:
306 case META_SIDE_BOTTOM:
307 return increment > 0;
308 default:
309 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 309, ((const char*) (__func__)), ((void*)0)); } while (0)
;
310 }
311}
312
313static gboolean
314edge_resistance_timeout (gpointer data)
315{
316 ResistanceDataForAnEdge *resistance_data = data;
317
318 resistance_data->timeout_over = TRUE(!(0));
319 resistance_data->timeout_id = 0;
320 (*resistance_data->timeout_func)(resistance_data->window);
321
322 return FALSE(0);
323}
324
325static int
326apply_edge_resistance (MetaWindow *window,
327 int old_pos,
328 int new_pos,
329 const MetaRectangle *old_rect,
330 const MetaRectangle *new_rect,
331 GArray *edges,
332 ResistanceDataForAnEdge *resistance_data,
333 GSourceFunc timeout_func,
334 gboolean xdir,
335 gboolean keyboard_op)
336{
337 int i, begin, end;
338 int last_edge;
339 gboolean increasing = new_pos > old_pos;
340 int increment = increasing ? 1 : -1;
341
342 const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW = 16;
343 const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW = 0;
344 const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_XINERAMA = 32;
345 const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_XINERAMA = 0;
346 const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN = 32;
347 const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN = 0;
348 const int TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW = 0;
349 const int TIMEOUT_RESISTANCE_LENGTH_MS_XINERAMA = 0;
350 const int TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN = 0;
351
352 /* Quit if no movement was specified */
353 if (old_pos == new_pos)
354 return new_pos;
355
356 /* Remove the old timeout if it's no longer relevant */
357 if (resistance_data->timeout_setup &&
358 ((resistance_data->timeout_edge_pos > old_pos &&
359 resistance_data->timeout_edge_pos > new_pos) ||
360 (resistance_data->timeout_edge_pos < old_pos &&
361 resistance_data->timeout_edge_pos < new_pos)))
362 {
363 resistance_data->timeout_setup = FALSE(0);
364 if (resistance_data->timeout_id != 0)
365 {
366 g_source_remove (resistance_data->timeout_id);
367 resistance_data->timeout_id = 0;
368 }
369 }
370
371 /* Get the range of indices in the edge array that we move past/to. */
372 begin = find_index_of_edge_near_position (edges, old_pos, increasing, xdir);
373 end = find_index_of_edge_near_position (edges, new_pos, !increasing, xdir);
374
375 /* begin and end can be outside the array index, if the window is partially
376 * off the screen
377 */
378 last_edge = edges->len - 1;
379 begin = CLAMP (begin, 0, last_edge)(((begin) > (last_edge)) ? (last_edge) : (((begin) < (0
)) ? (0) : (begin)))
;
380 end = CLAMP (end, 0, last_edge)(((end) > (last_edge)) ? (last_edge) : (((end) < (0)) ?
(0) : (end)))
;
381
382 /* Loop over all these edges we're moving past/to. */
383 i = begin;
384 while ((increasing && i <= end) ||
385 (!increasing && i >= end))
386 {
387 gboolean edges_align;
388 MetaEdge *edge = g_array_index (edges, MetaEdge*, i)(((MetaEdge**) (void *) (edges)->data) [(i)]);
389 int compare = xdir ? edge->rect.x : edge->rect.y;
390
391 /* Find out if this edge is relevant */
392 edges_align = meta_rectangle_edge_aligns (new_rect, edge) ||
393 meta_rectangle_edge_aligns (old_rect, edge);
394
395 /* Nothing to do unless the edges align */
396 if (!edges_align)
397 {
398 /* Go to the next edge in the range */
399 i += increment;
400 continue;
401 }
402
403 /* Rest is easier to read if we split on keyboard vs. mouse op */
404 if (keyboard_op)
405 {
406 if ((old_pos < compare && compare < new_pos) ||
407 (old_pos > compare && compare > new_pos))
408 return compare;
409 }
410 else /* mouse op */
411 {
412 int threshold;
413
414 /* TIMEOUT RESISTANCE: If the edge is relevant and we're moving
415 * towards it, then we may want to have some kind of time delay
416 * before the user can move past this edge.
417 */
418 if (movement_towards_edge (edge->side_type, increment))
419 {
420 /* First, determine the length of time for the resistance */
421 int timeout_length_ms = 0;
422 switch (edge->edge_type)
423 {
424 case META_EDGE_WINDOW:
425 timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW;
426 break;
427 case META_EDGE_XINERAMA:
428 timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_XINERAMA;
429 break;
430 case META_EDGE_SCREEN:
431 timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN;
432 break;
433 }
434
435 if (!resistance_data->timeout_setup &&
436 timeout_length_ms != 0)
437 {
438 resistance_data->timeout_id =
439 g_timeout_add (timeout_length_ms,
440 edge_resistance_timeout,
441 resistance_data);
442 resistance_data->timeout_setup = TRUE(!(0));
443 resistance_data->timeout_edge_pos = compare;
444 resistance_data->timeout_over = FALSE(0);
445 resistance_data->timeout_func = timeout_func;
446 resistance_data->window = window;
447 }
448 if (!resistance_data->timeout_over &&
449 timeout_length_ms != 0)
450 return compare;
451 }
452
453 /* PIXEL DISTANCE MOUSE RESISTANCE: If the edge matters and the
454 * user hasn't moved at least threshold pixels past this edge,
455 * stop movement at this edge. (Note that this is different from
456 * keyboard resistance precisely because keyboard move ops are
457 * relative to previous positions, whereas mouse move ops are
458 * relative to differences in mouse position and mouse position
459 * is an absolute quantity rather than a relative quantity)
460 */
461
462 /* First, determine the threshold */
463 switch (edge->edge_type)
464 {
465 case META_EDGE_WINDOW:
466 if (movement_towards_edge (edge->side_type, increment))
467 threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW;
468 else
469 threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW;
470 break;
471 case META_EDGE_XINERAMA:
472 if (movement_towards_edge (edge->side_type, increment))
473 threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_XINERAMA;
474 else
475 threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_XINERAMA;
476 break;
477 case META_EDGE_SCREEN:
478 if (movement_towards_edge (edge->side_type, increment))
479 threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN;
480 else
481 threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN;
482 break;
483 default:
484 threshold = 0;
485 }
486
487 if (ABS (compare - new_pos)(((compare - new_pos) < 0) ? -(compare - new_pos) : (compare
- new_pos))
< threshold)
488 return compare;
489 }
490
491 /* Go to the next edge in the range */
492 i += increment;
493 }
494
495 return new_pos;
496}
497
498static int
499apply_edge_snapping (int old_pos,
500 int new_pos,
501 const MetaRectangle *new_rect,
502 GArray *edges,
503 gboolean xdir,
504 gboolean keyboard_op)
505{
506 int snap_to;
507
508 if (old_pos == new_pos)
509 return new_pos;
510
511 snap_to = find_nearest_position (edges,
512 new_pos,
513 old_pos,
514 new_rect,
515 xdir,
516 keyboard_op);
517
518 /* If mouse snap-moving, the user could easily accidentally move just a
519 * couple pixels in a direction they didn't mean to move; so ignore snap
520 * movement in those cases unless it's only a small number of pixels
521 * anyway.
522 */
523 if (!keyboard_op &&
524 ABS (snap_to - old_pos)(((snap_to - old_pos) < 0) ? -(snap_to - old_pos) : (snap_to
- old_pos))
>= 8 &&
525 ABS (new_pos - old_pos)(((new_pos - old_pos) < 0) ? -(new_pos - old_pos) : (new_pos
- old_pos))
< 8)
526 return old_pos;
527 else
528 /* Otherwise, return the snapping position found */
529 return snap_to;
530}
531
532/* This function takes the position (including any frame) of the window and
533 * a proposed new position (ignoring edge resistance/snapping), and then
534 * applies edge resistance to EACH edge (separately) updating new_outer.
535 * It returns true if new_outer is modified, false otherwise.
536 *
537 * display->grab_edge_resistance_data MUST already be setup or calling this
538 * function will cause a crash.
539 */
540static gboolean
541apply_edge_resistance_to_each_side (MetaDisplay *display,
542 MetaWindow *window,
543 const MetaRectangle *old_outer,
544 MetaRectangle *new_outer,
545 GSourceFunc timeout_func,
546 gboolean auto_snap,
547 gboolean keyboard_op,
548 gboolean is_resize)
549{
550 MetaEdgeResistanceData *edge_data;
551 MetaRectangle modified_rect;
552 gboolean modified;
553 int new_left, new_right, new_top, new_bottom;
554
555 if (display->grab_edge_resistance_data == NULL((void*)0))
556 compute_resistance_and_snapping_edges (display);
557
558 edge_data = display->grab_edge_resistance_data;
559
560 if (auto_snap)
561 {
562 /* Do the auto snapping instead of normal edge resistance; in all
563 * cases, we allow snapping to opposite kinds of edges (e.g. left
564 * sides of windows to both left and right edges.
565 */
566
567 new_left = apply_edge_snapping (BOX_LEFT (*old_outer)((*old_outer).x),
568 BOX_LEFT (*new_outer)((*new_outer).x),
569 new_outer,
570 edge_data->left_edges,
571 TRUE(!(0)),
572 keyboard_op);
573
574 new_right = apply_edge_snapping (BOX_RIGHT (*old_outer)((*old_outer).x + (*old_outer).width),
575 BOX_RIGHT (*new_outer)((*new_outer).x + (*new_outer).width),
576 new_outer,
577 edge_data->right_edges,
578 TRUE(!(0)),
579 keyboard_op);
580
581 new_top = apply_edge_snapping (BOX_TOP (*old_outer)((*old_outer).y),
582 BOX_TOP (*new_outer)((*new_outer).y),
583 new_outer,
584 edge_data->top_edges,
585 FALSE(0),
586 keyboard_op);
587
588 new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer)((*old_outer).y + (*old_outer).height),
589 BOX_BOTTOM (*new_outer)((*new_outer).y + (*new_outer).height),
590 new_outer,
591 edge_data->bottom_edges,
592 FALSE(0),
593 keyboard_op);
594 }
595 else
596 {
597 /* Disable edge resistance for resizes when windows have size
598 * increment hints; see #346782. For all other cases, apply
599 * them.
600 */
601 if (!is_resize || window->size_hints.width_inc == 1)
602 {
603 /* Now, apply the normal horizontal edge resistance */
604 new_left = apply_edge_resistance (window,
605 BOX_LEFT (*old_outer)((*old_outer).x),
606 BOX_LEFT (*new_outer)((*new_outer).x),
607 old_outer,
608 new_outer,
609 edge_data->left_edges,
610 &edge_data->left_data,
611 timeout_func,
612 TRUE(!(0)),
613 keyboard_op);
614 new_right = apply_edge_resistance (window,
615 BOX_RIGHT (*old_outer)((*old_outer).x + (*old_outer).width),
616 BOX_RIGHT (*new_outer)((*new_outer).x + (*new_outer).width),
617 old_outer,
618 new_outer,
619 edge_data->right_edges,
620 &edge_data->right_data,
621 timeout_func,
622 TRUE(!(0)),
623 keyboard_op);
624 }
625 else
626 {
627 new_left = new_outer->x;
628 new_right = new_outer->x + new_outer->width;
629 }
630 /* Same for vertical resizes... */
631 if (!is_resize || window->size_hints.height_inc == 1)
632 {
633 new_top = apply_edge_resistance (window,
634 BOX_TOP (*old_outer)((*old_outer).y),
635 BOX_TOP (*new_outer)((*new_outer).y),
636 old_outer,
637 new_outer,
638 edge_data->top_edges,
639 &edge_data->top_data,
640 timeout_func,
641 FALSE(0),
642 keyboard_op);
643 new_bottom = apply_edge_resistance (window,
644 BOX_BOTTOM (*old_outer)((*old_outer).y + (*old_outer).height),
645 BOX_BOTTOM (*new_outer)((*new_outer).y + (*new_outer).height),
646 old_outer,
647 new_outer,
648 edge_data->bottom_edges,
649 &edge_data->bottom_data,
650 timeout_func,
651 FALSE(0),
652 keyboard_op);
653 }
654 else
655 {
656 new_top = new_outer->y;
657 new_bottom = new_outer->y + new_outer->height;
658 }
659 }
660
661 /* Determine whether anything changed, and save the changes */
662 modified_rect = meta_rect (new_left,
663 new_top,
664 new_right - new_left,
665 new_bottom - new_top);
666 modified = !meta_rectangle_equal (new_outer, &modified_rect);
667 *new_outer = modified_rect;
668 return modified;
669}
670
671void
672meta_display_cleanup_edges (MetaDisplay *display)
673{
674 guint i,j;
675 MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data;
676 GHashTable *edges_to_be_freed;
677
678 if (edge_data == NULL((void*)0)) /* Not currently cached */
679 return;
680
681 /* We first need to clean out any window edges */
682 edges_to_be_freed = g_hash_table_new_full (g_direct_hash, g_direct_equal,
683 g_free, NULL((void*)0));
684 for (i = 0; i < 4; i++)
685 {
686 GArray *tmp = NULL((void*)0);
687 MetaSide side;
688 switch (i)
689 {
690 case 0:
691 tmp = edge_data->left_edges;
692 side = META_SIDE_LEFT;
693 break;
694 case 1:
695 tmp = edge_data->right_edges;
696 side = META_SIDE_RIGHT;
697 break;
698 case 2:
699 tmp = edge_data->top_edges;
700 side = META_SIDE_TOP;
701 break;
702 case 3:
703 tmp = edge_data->bottom_edges;
704 side = META_SIDE_BOTTOM;
705 break;
706 default:
707 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 707, ((const char*) (__func__)), ((void*)0)); } while (0)
;
708 }
709
710 for (j = 0; j < tmp->len; j++)
711 {
712 MetaEdge *edge = g_array_index (tmp, MetaEdge*, j)(((MetaEdge**) (void *) (tmp)->data) [(j)]);
713 if (edge->edge_type == META_EDGE_WINDOW &&
714 edge->side_type == side)
715 {
716 /* The same edge will appear in two arrays, and we can't free
717 * it yet we still need to compare edge->side_type for the other
718 * array that it is in. So store it in a hash table for later
719 * freeing. Could also do this in a simple linked list.
720 */
721 g_hash_table_insert (edges_to_be_freed, edge, edge);
722 }
723 }
724 }
725
726 /* Now free all the window edges (the key destroy function is g_free) */
727 g_hash_table_destroy (edges_to_be_freed);
728
729 /* Now free the arrays and data */
730 g_array_free (edge_data->left_edges, TRUE(!(0)));
731 g_array_free (edge_data->right_edges, TRUE(!(0)));
732 g_array_free (edge_data->top_edges, TRUE(!(0)));
733 g_array_free (edge_data->bottom_edges, TRUE(!(0)));
734 edge_data->left_edges = NULL((void*)0);
735 edge_data->right_edges = NULL((void*)0);
736 edge_data->top_edges = NULL((void*)0);
737 edge_data->bottom_edges = NULL((void*)0);
738
739 /* Cleanup the timeouts */
740 if (edge_data->left_data.timeout_setup &&
741 edge_data->left_data.timeout_id != 0)
742 g_source_remove (edge_data->left_data.timeout_id);
743 if (edge_data->right_data.timeout_setup &&
744 edge_data->right_data.timeout_id != 0)
745 g_source_remove (edge_data->right_data.timeout_id);
746 if (edge_data->top_data.timeout_setup &&
747 edge_data->top_data.timeout_id != 0)
748 g_source_remove (edge_data->top_data.timeout_id);
749 if (edge_data->bottom_data.timeout_setup &&
750 edge_data->bottom_data.timeout_id != 0)
751 g_source_remove (edge_data->bottom_data.timeout_id);
752
753 g_free (display->grab_edge_resistance_data);
754 display->grab_edge_resistance_data = NULL((void*)0);
755}
756
757static int
758stupid_sort_requiring_extra_pointer_dereference (gconstpointer a,
759 gconstpointer b)
760{
761 const MetaEdge * const *a_edge = a;
762 const MetaEdge * const *b_edge = b;
763 return meta_rectangle_edge_cmp_ignore_type (*a_edge, *b_edge);
764}
765
766static void
767cache_edges (MetaDisplay *display,
768 GList *window_edges,
769 GList *xinerama_edges,
770 GList *screen_edges)
771{
772 MetaEdgeResistanceData *edge_data;
773 GList *tmp;
774 int num_left, num_right, num_top, num_bottom;
775 int i;
776
777 /*
778 * 0th: Print debugging information to the log about the edges
779 */
780#ifdef WITH_VERBOSE_MODE1
781 if (meta_is_verbose())
782 {
783 int max_edges = MAX (MAX( g_list_length (window_edges),((((((g_list_length (window_edges)) > (g_list_length (xinerama_edges
))) ? (g_list_length (window_edges)) : (g_list_length (xinerama_edges
)))) > (g_list_length (screen_edges))) ? ((((g_list_length
(window_edges)) > (g_list_length (xinerama_edges))) ? (g_list_length
(window_edges)) : (g_list_length (xinerama_edges)))) : (g_list_length
(screen_edges)))
784 g_list_length (xinerama_edges)),((((((g_list_length (window_edges)) > (g_list_length (xinerama_edges
))) ? (g_list_length (window_edges)) : (g_list_length (xinerama_edges
)))) > (g_list_length (screen_edges))) ? ((((g_list_length
(window_edges)) > (g_list_length (xinerama_edges))) ? (g_list_length
(window_edges)) : (g_list_length (xinerama_edges)))) : (g_list_length
(screen_edges)))
785 g_list_length (screen_edges))((((((g_list_length (window_edges)) > (g_list_length (xinerama_edges
))) ? (g_list_length (window_edges)) : (g_list_length (xinerama_edges
)))) > (g_list_length (screen_edges))) ? ((((g_list_length
(window_edges)) > (g_list_length (xinerama_edges))) ? (g_list_length
(window_edges)) : (g_list_length (xinerama_edges)))) : (g_list_length
(screen_edges)))
;
786 char big_buffer[(EDGE_LENGTH37+2)*max_edges];
787
788 meta_rectangle_edge_list_to_string (window_edges, ", ", big_buffer);
789 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
790 "Window edges for resistance : %s\n", big_buffer);
791
792 meta_rectangle_edge_list_to_string (xinerama_edges, ", ", big_buffer);
793 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
794 "Xinerama edges for resistance: %s\n", big_buffer);
795
796 meta_rectangle_edge_list_to_string (screen_edges, ", ", big_buffer);
797 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
798 "Screen edges for resistance : %s\n", big_buffer);
799 }
800#endif
801
802 /*
803 * 1st: Get the total number of each kind of edge
804 */
805 num_left = num_right = num_top = num_bottom = 0;
806 for (i = 0; i < 3; i++)
807 {
808 tmp = NULL((void*)0);
809 switch (i)
810 {
811 case 0:
812 tmp = window_edges;
813 break;
814 case 1:
815 tmp = xinerama_edges;
816 break;
817 case 2:
818 tmp = screen_edges;
819 break;
820 default:
821 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 821, ((const char*) (__func__)), ((void*)0)); } while (0)
;
822 }
823
824 while (tmp)
825 {
826 MetaEdge *edge = tmp->data;
827 switch (edge->side_type)
828 {
829 case META_SIDE_LEFT:
830 num_left++;
831 break;
832 case META_SIDE_RIGHT:
833 num_right++;
834 break;
835 case META_SIDE_TOP:
836 num_top++;
837 break;
838 case META_SIDE_BOTTOM:
839 num_bottom++;
840 break;
841 default:
842 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 842, ((const char*) (__func__)), ((void*)0)); } while (0)
;
843 }
844 tmp = tmp->next;
845 }
846 }
847
848 /*
849 * 2nd: Allocate the edges
850 */
851 g_assert (display->grab_edge_resistance_data == NULL)do { if (display->grab_edge_resistance_data == ((void*)0))
; else g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 851, ((const char*) (__func__)), "display->grab_edge_resistance_data == NULL"
); } while (0)
;
852 display->grab_edge_resistance_data = g_new (MetaEdgeResistanceData, 1)((MetaEdgeResistanceData *) g_malloc_n ((1), sizeof (MetaEdgeResistanceData
)))
;
853 edge_data = display->grab_edge_resistance_data;
854 edge_data->left_edges = g_array_sized_new (FALSE(0),
855 FALSE(0),
856 sizeof(MetaEdge*),
857 num_left + num_right);
858 edge_data->right_edges = g_array_sized_new (FALSE(0),
859 FALSE(0),
860 sizeof(MetaEdge*),
861 num_left + num_right);
862 edge_data->top_edges = g_array_sized_new (FALSE(0),
863 FALSE(0),
864 sizeof(MetaEdge*),
865 num_top + num_bottom);
866 edge_data->bottom_edges = g_array_sized_new (FALSE(0),
867 FALSE(0),
868 sizeof(MetaEdge*),
869 num_top + num_bottom);
870
871 /*
872 * 3rd: Add the edges to the arrays
873 */
874 for (i = 0; i < 3; i++)
875 {
876 tmp = NULL((void*)0);
877 switch (i)
878 {
879 case 0:
880 tmp = window_edges;
881 break;
882 case 1:
883 tmp = xinerama_edges;
884 break;
885 case 2:
886 tmp = screen_edges;
887 break;
888 default:
889 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 889, ((const char*) (__func__)), ((void*)0)); } while (0)
;
890 }
891
892 while (tmp)
893 {
894 MetaEdge *edge = tmp->data;
895 switch (edge->side_type)
896 {
897 case META_SIDE_LEFT:
898 case META_SIDE_RIGHT:
899 g_array_append_val (edge_data->left_edges, edge)g_array_append_vals (edge_data->left_edges, &(edge), 1
)
;
900 g_array_append_val (edge_data->right_edges, edge)g_array_append_vals (edge_data->right_edges, &(edge), 1
)
;
901 break;
902 case META_SIDE_TOP:
903 case META_SIDE_BOTTOM:
904 g_array_append_val (edge_data->top_edges, edge)g_array_append_vals (edge_data->top_edges, &(edge), 1);
905 g_array_append_val (edge_data->bottom_edges, edge)g_array_append_vals (edge_data->bottom_edges, &(edge),
1)
;
906 break;
907 default:
908 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/edge-resistance.c"
, 908, ((const char*) (__func__)), ((void*)0)); } while (0)
;
909 }
910 tmp = tmp->next;
911 }
912 }
913
914 /*
915 * 4th: Sort the arrays (FIXME: This is kinda dumb since the arrays were
916 * individually sorted earlier and we could have done this faster and
917 * avoided this sort by sticking them into the array with some simple
918 * merging of the lists).
919 */
920 g_array_sort (display->grab_edge_resistance_data->left_edges,
921 stupid_sort_requiring_extra_pointer_dereference);
922 g_array_sort (display->grab_edge_resistance_data->right_edges,
923 stupid_sort_requiring_extra_pointer_dereference);
924 g_array_sort (display->grab_edge_resistance_data->top_edges,
925 stupid_sort_requiring_extra_pointer_dereference);
926 g_array_sort (display->grab_edge_resistance_data->bottom_edges,
927 stupid_sort_requiring_extra_pointer_dereference);
928}
929
930static void
931initialize_grab_edge_resistance_data (MetaDisplay *display)
932{
933 MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data;
934
935 edge_data->left_data.timeout_setup = FALSE(0);
936 edge_data->right_data.timeout_setup = FALSE(0);
937 edge_data->top_data.timeout_setup = FALSE(0);
938 edge_data->bottom_data.timeout_setup = FALSE(0);
939
940 edge_data->left_data.keyboard_buildup = 0;
941 edge_data->right_data.keyboard_buildup = 0;
942 edge_data->top_data.keyboard_buildup = 0;
943 edge_data->bottom_data.keyboard_buildup = 0;
944}
945
946static void
947compute_resistance_and_snapping_edges (MetaDisplay *display)
948{
949 GList *stacked_windows;
950 GList *cur_window_iter;
951 GList *edges;
952 /* Lists of window positions (rects) and their relative stacking positions */
953 int stack_position;
954 GSList *obscuring_windows, *window_stacking;
955 /* The portions of the above lists that still remain at the stacking position
956 * in the layer that we are working on
957 */
958 GSList *rem_windows, *rem_win_stacking;
959
960 g_assert (display->grab_window != NULL)do { if (display->grab_window != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/edge-resistance.c", 960, ((const char*) (__func__
)), "display->grab_window != NULL"); } while (0)
;
961 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
962 "Computing edges to resist-movement or snap-to for %s.\n",
963 display->grab_window->desc);
964
965 /*
966 * 1st: Get the list of relevant windows, from bottom to top
967 */
968 stacked_windows =
969 meta_stack_list_windows (display->grab_screen->stack,
970 display->grab_screen->active_workspace);
971
972 /*
973 * 2nd: we need to separate that stacked list into a list of windows that
974 * can obscure other edges. To make sure we only have windows obscuring
975 * those below it instead of going both ways, we also need to keep a
976 * counter list. Messy, I know.
977 */
978 obscuring_windows = window_stacking = NULL((void*)0);
979 cur_window_iter = stacked_windows;
980 stack_position = 0;
981 while (cur_window_iter != NULL((void*)0))
982 {
983 MetaWindow *cur_window = cur_window_iter->data;
984 if (WINDOW_EDGES_RELEVANT (cur_window, display)meta_window_should_be_showing (cur_window) && cur_window
->screen == display->grab_screen && cur_window !=
display->grab_window && cur_window->type != META_WINDOW_DESKTOP
&& cur_window->type != META_WINDOW_MENU &&
cur_window->type != META_WINDOW_SPLASHSCREEN
)
985 {
986 MetaRectangle *new_rect;
987 new_rect = g_new (MetaRectangle, 1)((MetaRectangle *) g_malloc_n ((1), sizeof (MetaRectangle)));
988 meta_window_get_outer_rect (cur_window, new_rect);
989 obscuring_windows = g_slist_prepend (obscuring_windows, new_rect);
990 window_stacking =
991 g_slist_prepend (window_stacking, GINT_TO_POINTER (stack_position)((gpointer) (glong) (stack_position)));
992 }
993
994 stack_position++;
995 cur_window_iter = cur_window_iter->next;
996 }
997 /* Put 'em in bottom to top order */
998 rem_windows = obscuring_windows = g_slist_reverse (obscuring_windows);
999 rem_win_stacking = window_stacking = g_slist_reverse (window_stacking);
1000
1001 /*
1002 * 3rd: loop over the windows again, this time getting the edges from
1003 * them and removing intersections with the relevant obscuring_windows &
1004 * obscuring_docks.
1005 */
1006 edges = NULL((void*)0);
1007 stack_position = 0;
1008 cur_window_iter = stacked_windows;
1009 while (cur_window_iter != NULL((void*)0))
1010 {
1011 MetaRectangle cur_rect;
1012 MetaWindow *cur_window = cur_window_iter->data;
1013 meta_window_get_outer_rect (cur_window, &cur_rect);
1014
1015 /* Check if we want to use this window's edges for edge
1016 * resistance (note that dock edges are considered screen edges
1017 * which are handled separately
1018 */
1019 if (WINDOW_EDGES_RELEVANT (cur_window, display)meta_window_should_be_showing (cur_window) && cur_window
->screen == display->grab_screen && cur_window !=
display->grab_window && cur_window->type != META_WINDOW_DESKTOP
&& cur_window->type != META_WINDOW_MENU &&
cur_window->type != META_WINDOW_SPLASHSCREEN
&&
1020 cur_window->type != META_WINDOW_DOCK)
1021 {
1022 GList *new_edges;
1023 MetaEdge *new_edge;
1024 MetaRectangle reduced;
1025
1026 /* We don't care about snapping to any portion of the window that
1027 * is offscreen (we also don't care about parts of edges covered
1028 * by other windows or DOCKS, but that's handled below).
1029 */
1030 meta_rectangle_intersect (&cur_rect,
1031 &display->grab_screen->rect,
1032 &reduced);
1033
1034 new_edges = NULL((void*)0);
1035
1036 /* Left side of this window is resistance for the right edge of
1037 * the window being moved.
1038 */
1039 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1040 new_edge->rect = reduced;
1041 new_edge->rect.width = 0;
1042 new_edge->side_type = META_SIDE_RIGHT;
1043 new_edge->edge_type = META_EDGE_WINDOW;
1044 new_edges = g_list_prepend (new_edges, new_edge);
1045
1046 /* Right side of this window is resistance for the left edge of
1047 * the window being moved.
1048 */
1049 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1050 new_edge->rect = reduced;
1051 new_edge->rect.x += new_edge->rect.width;
1052 new_edge->rect.width = 0;
1053 new_edge->side_type = META_SIDE_LEFT;
1054 new_edge->edge_type = META_EDGE_WINDOW;
1055 new_edges = g_list_prepend (new_edges, new_edge);
1056
1057 /* Top side of this window is resistance for the bottom edge of
1058 * the window being moved.
1059 */
1060 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1061 new_edge->rect = reduced;
1062 new_edge->rect.height = 0;
1063 new_edge->side_type = META_SIDE_BOTTOM;
1064 new_edge->edge_type = META_EDGE_WINDOW;
1065 new_edges = g_list_prepend (new_edges, new_edge);
1066
1067 /* Top side of this window is resistance for the bottom edge of
1068 * the window being moved.
1069 */
1070 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1071 new_edge->rect = reduced;
1072 new_edge->rect.y += new_edge->rect.height;
1073 new_edge->rect.height = 0;
1074 new_edge->side_type = META_SIDE_TOP;
1075 new_edge->edge_type = META_EDGE_WINDOW;
1076 new_edges = g_list_prepend (new_edges, new_edge);
1077
1078 /* Update the remaining windows to only those at a higher
1079 * stacking position than this one.
1080 */
1081 while (rem_win_stacking &&
1082 stack_position >= GPOINTER_TO_INT (rem_win_stacking->data)((gint) (glong) (rem_win_stacking->data)))
1083 {
1084 rem_windows = rem_windows->next;
1085 rem_win_stacking = rem_win_stacking->next;
1086 }
1087
1088 /* Remove edge portions overlapped by rem_windows and rem_docks */
1089 new_edges =
1090 meta_rectangle_remove_intersections_with_boxes_from_edges (
1091 new_edges,
1092 rem_windows);
1093
1094 /* Save the new edges */
1095 edges = g_list_concat (new_edges, edges);
1096 }
1097
1098 stack_position++;
1099 cur_window_iter = cur_window_iter->next;
1100 }
1101
1102 /*
1103 * 4th: Free the extra memory not needed and sort the list
1104 */
1105 g_list_free (stacked_windows);
1106 /* Free the memory used by the obscuring windows/docks lists */
1107 g_slist_free (window_stacking);
1108 g_slist_free_full (obscuring_windows, g_free);
1109
1110 /* Sort the list. FIXME: Should I bother with this sorting? I just
1111 * sort again later in cache_edges() anyway...
1112 */
1113 edges = g_list_sort (edges, meta_rectangle_edge_cmp);
1114
1115 /*
1116 * 5th: Cache the combination of these edges with the onscreen and
1117 * xinerama edges in an array for quick access. Free the edges since
1118 * they've been cached elsewhere.
1119 */
1120 cache_edges (display,
1121 edges,
1122 display->grab_screen->active_workspace->xinerama_edges,
1123 display->grab_screen->active_workspace->screen_edges);
1124 g_list_free (edges);
1125
1126 /*
1127 * 6th: Initialize the resistance timeouts and buildups
1128 */
1129 initialize_grab_edge_resistance_data (display);
1130}
1131
1132/* Note that old_[xy] and new_[xy] are with respect to inner positions of
1133 * the window.
1134 */
1135void
1136meta_window_edge_resistance_for_move (MetaWindow *window,
1137 int old_x,
1138 int old_y,
1139 int *new_x,
1140 int *new_y,
1141 GSourceFunc timeout_func,
1142 gboolean snap,
1143 gboolean is_keyboard_op)
1144{
1145 MetaRectangle old_outer, proposed_outer, new_outer;
1146 gboolean is_resize;
1147
1148 if (window == window->display->grab_window &&
1149 window->display->grab_wireframe_active)
1150 {
1151 meta_window_get_xor_rect (window,
1152 &window->display->grab_wireframe_rect,
1153 &old_outer);
1154 }
1155 else
1156 {
1157 meta_window_get_outer_rect (window, &old_outer);
1158 }
1159 proposed_outer = old_outer;
1160 proposed_outer.x += (*new_x - old_x);
1161 proposed_outer.y += (*new_y - old_y);
1162 new_outer = proposed_outer;
1163
1164 window->display->grab_last_user_action_was_snap = (snap != FALSE(0));
1165 is_resize = FALSE(0);
1166 if (apply_edge_resistance_to_each_side (window->display,
1167 window,
1168 &old_outer,
1169 &new_outer,
1170 timeout_func,
1171 snap,
1172 is_keyboard_op,
1173 is_resize))
1174 {
1175 /* apply_edge_resistance_to_each_side independently applies
1176 * resistance to both the right and left edges of new_outer as both
1177 * could meet areas of resistance. But we don't want a resize, so we
1178 * just have both edges move according to the stricter of the
1179 * resistances. Same thing goes for top & bottom edges.
1180 */
1181 MetaRectangle *reference;
1182 int left_change, right_change, smaller_x_change;
1183 int top_change, bottom_change, smaller_y_change;
1184
1185 if (snap && !is_keyboard_op)
1186 reference = &proposed_outer;
1187 else
1188 reference = &old_outer;
1189
1190 left_change = BOX_LEFT (new_outer)((new_outer).x) - BOX_LEFT (*reference)((*reference).x);
1191 right_change = BOX_RIGHT (new_outer)((new_outer).x + (new_outer).width) - BOX_RIGHT (*reference)((*reference).x + (*reference).width);
1192 if ( snap && is_keyboard_op && left_change == 0)
1193 smaller_x_change = right_change;
1194 else if (snap && is_keyboard_op && right_change == 0)
1195 smaller_x_change = left_change;
1196 else if (ABS (left_change)(((left_change) < 0) ? -(left_change) : (left_change)) < ABS (right_change)(((right_change) < 0) ? -(right_change) : (right_change)))
1197 smaller_x_change = left_change;
1198 else
1199 smaller_x_change = right_change;
1200
1201 top_change = BOX_TOP (new_outer)((new_outer).y) - BOX_TOP (*reference)((*reference).y);
1202 bottom_change = BOX_BOTTOM (new_outer)((new_outer).y + (new_outer).height) - BOX_BOTTOM (*reference)((*reference).y + (*reference).height);
1203 if ( snap && is_keyboard_op && top_change == 0)
1204 smaller_y_change = bottom_change;
1205 else if (snap && is_keyboard_op && bottom_change == 0)
1206 smaller_y_change = top_change;
1207 else if (ABS (top_change)(((top_change) < 0) ? -(top_change) : (top_change)) < ABS (bottom_change)(((bottom_change) < 0) ? -(bottom_change) : (bottom_change
))
)
1208 smaller_y_change = top_change;
1209 else
1210 smaller_y_change = bottom_change;
1211
1212 *new_x = old_x + smaller_x_change +
1213 (BOX_LEFT (*reference)((*reference).x) - BOX_LEFT (old_outer)((old_outer).x));
1214 *new_y = old_y + smaller_y_change +
1215 (BOX_TOP (*reference)((*reference).y) - BOX_TOP (old_outer)((old_outer).y));
1216
1217 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
1218 "outer x & y move-to coordinate changed from %d,%d to %d,%d\n",
1219 proposed_outer.x, proposed_outer.y,
1220 old_outer.x + (*new_x - old_x),
1221 old_outer.y + (*new_y - old_y));
1222 }
1223}
1224
1225/* Note that old_(width|height) and new_(width|height) are with respect to
1226 * sizes of the inner window.
1227 */
1228void
1229meta_window_edge_resistance_for_resize (MetaWindow *window,
1230 int old_width,
1231 int old_height,
1232 int *new_width,
1233 int *new_height,
1234 int gravity,
1235 GSourceFunc timeout_func,
1236 gboolean snap,
1237 gboolean is_keyboard_op)
1238{
1239 MetaRectangle old_outer, new_outer;
1240 int proposed_outer_width, proposed_outer_height;
1241 gboolean is_resize;
1242
1243 if (window == window->display->grab_window &&
1244 window->display->grab_wireframe_active)
1245 {
1246 meta_window_get_xor_rect (window,
1247 &window->display->grab_wireframe_rect,
1248 &old_outer);
1249 }
1250 else
1251 {
1252 meta_window_get_outer_rect (window, &old_outer);
1253 }
1254 proposed_outer_width = old_outer.width + (*new_width - old_width);
1255 proposed_outer_height = old_outer.height + (*new_height - old_height);
1256 meta_rectangle_resize_with_gravity (&old_outer,
1257 &new_outer,
1258 gravity,
1259 proposed_outer_width,
1260 proposed_outer_height);
1261
1262 window->display->grab_last_user_action_was_snap = (snap != FALSE(0));
1263 is_resize = TRUE(!(0));
1264 if (apply_edge_resistance_to_each_side (window->display,
1265 window,
1266 &old_outer,
1267 &new_outer,
1268 timeout_func,
1269 snap,
1270 is_keyboard_op,
1271 is_resize))
1272 {
1273 *new_width = old_width + (new_outer.width - old_outer.width);
1274 *new_height = old_height + (new_outer.height - old_outer.height);
1275
1276 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
1277 "outer width & height got changed from %d,%d to %d,%d\n",
1278 proposed_outer_width, proposed_outer_height,
1279 new_outer.width, new_outer.height);
1280 }
1281}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-d1db2e.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-d1db2e.html new file mode 100644 index 00000000..656d6c1a --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-d1db2e.html @@ -0,0 +1,8003 @@ + + + +ui/theme.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme.c
Warning:line 6783, column 10
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco Theme Rendering */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24/**
25 * \file theme.c Making Marco look pretty
26 *
27 * The window decorations drawn by Marco are described by files on disk
28 * known internally as "themes" (externally as "window border themes" on
29 * http://art.gnome.org/themes/marco/ or "Marco themes"). This file
30 * contains most of the code necessary to support themes; it does not
31 * contain the XML parser, which is in theme-parser.c.
32 *
33 * \bug This is a big file with lots of different subsystems, which might
34 * be better split out into separate files.
35 */
36
37/**
38 * \defgroup tokenizer The theme expression tokenizer
39 *
40 * Themes can use a simple expression language to represent the values of
41 * things. This is the tokeniser used for that language.
42 *
43 * \bug We could remove almost all this code by using GScanner instead,
44 * but we would also have to find every expression in every existing theme
45 * we could and make sure the parse trees were the same.
46 */
47
48/**
49 * \defgroup parser The theme expression parser
50 *
51 * Themes can use a simple expression language to represent the values of
52 * things. This is the parser used for that language.
53 */
54
55#include <config.h>
56#include <glib/gi18n-lib.h>
57
58#include "prefs.h"
59#include "theme.h"
60#include "theme-parser.h"
61#include "util.h"
62#include "gradient.h"
63#include <gtk/gtk.h>
64#include <string.h>
65#include <stdlib.h>
66#define __USE_XOPEN
67#include <math.h>
68
69#define GDK_COLOR_RGBA(color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
\
70 ((guint32) (0xff | \
71 ((int)((color).red * 255) << 24) | \
72 ((int)((color).green * 255) << 16) | \
73 ((int)((color).blue * 255) << 8)))
74
75#define GDK_COLOR_RGB(color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
\
76 ((guint32) (((int)((color).red * 255) << 16) | \
77 ((int)((color).green * 255) << 8) | \
78 ((int)((color).blue * 255))))
79
80#define DEBUG_FILL_STRUCT(s)memset ((s), 0xef, sizeof (*(s))) memset ((s), 0xef, sizeof (*(s)))
81#define CLAMP_UCHAR(v)((guchar) ((((((int)v)) > ((int)255)) ? ((int)255) : (((((
int)v)) < ((int)0)) ? ((int)0) : (((int)v))))))
((guchar) (CLAMP (((int)v), (int)0, (int)255)(((((int)v)) > ((int)255)) ? ((int)255) : (((((int)v)) <
((int)0)) ? ((int)0) : (((int)v))))
))
82#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
83
84static void gtk_style_shade (GdkRGBA *a,
85 GdkRGBA *b,
86 gdouble k);
87static void rgb_to_hls (gdouble *r,
88 gdouble *g,
89 gdouble *b);
90static void hls_to_rgb (gdouble *h,
91 gdouble *l,
92 gdouble *s);
93
94/**
95 * The current theme. (Themes are singleton.)
96 */
97static MetaTheme *meta_current_theme = NULL((void*)0);
98
99static cairo_surface_t *
100scale_surface (cairo_surface_t *surface,
101 gdouble old_width,
102 gdouble old_height,
103 gdouble new_width,
104 gdouble new_height,
105 gboolean vertical_stripes,
106 gboolean horizontal_stripes)
107{
108 gdouble scale_x;
109 gdouble scale_y;
110 cairo_content_t content;
111 gdouble width;
112 gdouble height;
113 cairo_surface_t *scaled;
114 cairo_t *cr;
115
116 scale_x = new_width / old_width;
117 scale_y = new_height / old_height;
118
119 if (horizontal_stripes && !vertical_stripes)
120 {
121 new_width = old_width;
122 scale_x = 1.0;
123 }
124 else if (vertical_stripes && !horizontal_stripes)
125 {
126 new_height = old_height;
127 scale_y = 1.0;
128 }
129
130 content = CAIRO_CONTENT_COLOR_ALPHA;
131 width = ceil (new_width);
132 height = ceil (new_height);
133
134 scaled = cairo_surface_create_similar (surface, content, (int) width, (int) height);
135 cr = cairo_create (scaled);
136
137 cairo_scale (cr, scale_x, scale_y);
138 cairo_set_source_surface (cr, surface, 0, 0);
139
140 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
141
142 cairo_paint (cr);
143 cairo_destroy (cr);
144
145 return scaled;
146}
147
148static cairo_surface_t *
149get_surface_from_pixbuf (GdkPixbuf *pixbuf,
150 MetaImageFillType fill_type,
151 gdouble width,
152 gdouble height,
153 gboolean vertical_stripes,
154 gboolean horizontal_stripes)
155{
156 gdouble pixbuf_width;
157 gdouble pixbuf_height;
158 cairo_surface_t *surface;
159 cairo_content_t content;
160 cairo_surface_t *copy;
161 cairo_t *cr;
162
163 pixbuf_width = gdk_pixbuf_get_width (pixbuf);
164 pixbuf_height = gdk_pixbuf_get_height (pixbuf);
165 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL((void*)0));
166
167 if (pixbuf_width == width && pixbuf_height == height)
168 {
169 return surface;
170 }
171
172 if (fill_type != META_IMAGE_FILL_TILE)
173 {
174 cairo_surface_t *scaled;
175
176 scaled = scale_surface (surface, pixbuf_width, pixbuf_height,
177 width, height, vertical_stripes,
178 horizontal_stripes);
179
180 cairo_surface_destroy (surface);
181 surface = scaled;
182 }
183
184 content = CAIRO_CONTENT_COLOR_ALPHA;
185 width = ceil (width);
186 height = ceil (height);
187
188 copy = cairo_surface_create_similar (surface, content, (int) width, (int) height);
189 cr = cairo_create (copy);
190
191 cairo_set_source_surface (cr, surface, 0, 0);
192
193 if (fill_type == META_IMAGE_FILL_TILE ||
194 vertical_stripes || horizontal_stripes)
195 {
196 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
197 }
198
199 cairo_paint (cr);
200 cairo_destroy (cr);
201
202 cairo_surface_destroy (surface);
203
204 return copy;
205}
206
207static GdkPixbuf *
208colorize_pixbuf (GdkPixbuf *orig,
209 GdkRGBA *new_color)
210{
211 GdkPixbuf *pixbuf;
212 double intensity;
213 int x, y;
214 const guchar *src;
215 guchar *dest;
216 int orig_rowstride;
217 int dest_rowstride;
218 int width, height;
219 gboolean has_alpha;
220 const guchar *src_pixels;
221 guchar *dest_pixels;
222
223 pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
224 gdk_pixbuf_get_bits_per_sample (orig),
225 gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
226
227 if (pixbuf == NULL((void*)0))
228 return NULL((void*)0);
229
230 orig_rowstride = gdk_pixbuf_get_rowstride (orig);
231 dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
232 width = gdk_pixbuf_get_width (pixbuf);
233 height = gdk_pixbuf_get_height (pixbuf);
234 has_alpha = gdk_pixbuf_get_has_alpha (orig);
235 src_pixels = gdk_pixbuf_get_pixels (orig);
236 dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
237
238 for (y = 0; y < height; y++)
239 {
240 src = src_pixels + y * orig_rowstride;
241 dest = dest_pixels + y * dest_rowstride;
242
243 for (x = 0; x < width; x++)
244 {
245 double dr, dg, db;
246
247 intensity = INTENSITY (src[0], src[1], src[2])((src[0]) * 0.30 + (src[1]) * 0.59 + (src[2]) * 0.11) / 255.0;
248
249 if (intensity <= 0.5)
250 {
251 /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
252 dr = new_color->red * intensity * 2.0;
253 dg = new_color->green * intensity * 2.0;
254 db = new_color->blue * intensity * 2.0;
255 }
256 else
257 {
258 /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
259 dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
260 dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
261 db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
262 }
263
264 dest[0] = CLAMP_UCHAR (255 * dr)((guchar) ((((((int)255 * dr)) > ((int)255)) ? ((int)255) :
(((((int)255 * dr)) < ((int)0)) ? ((int)0) : (((int)255 *
dr))))))
;
265 dest[1] = CLAMP_UCHAR (255 * dg)((guchar) ((((((int)255 * dg)) > ((int)255)) ? ((int)255) :
(((((int)255 * dg)) < ((int)0)) ? ((int)0) : (((int)255 *
dg))))))
;
266 dest[2] = CLAMP_UCHAR (255 * db)((guchar) ((((((int)255 * db)) > ((int)255)) ? ((int)255) :
(((((int)255 * db)) < ((int)0)) ? ((int)0) : (((int)255 *
db))))))
;
267
268 if (has_alpha)
269 {
270 dest[3] = src[3];
271 src += 4;
272 dest += 4;
273 }
274 else
275 {
276 src += 3;
277 dest += 3;
278 }
279 }
280 }
281
282 return pixbuf;
283}
284
285static void
286color_composite (const GdkRGBA *bg,
287 const GdkRGBA *fg,
288 double alpha,
289 GdkRGBA *color)
290{
291 *color = *bg;
292 color->red = color->red + (fg->red - color->red) * alpha;
293 color->green = color->green + (fg->green - color->green) * alpha;
294 color->blue = color->blue + (fg->blue - color->blue) * alpha;
295}
296
297/**
298 * Sets all the fields of a border to dummy values.
299 *
300 * \param border The border whose fields should be reset.
301 */
302static void
303init_border (GtkBorder *border)
304{
305 border->top = -1;
306 border->bottom = -1;
307 border->left = -1;
308 border->right = -1;
309}
310
311/**
312 * Creates a new, empty MetaFrameLayout. The fields will be set to dummy
313 * values.
314 *
315 * \return The newly created MetaFrameLayout.
316 */
317MetaFrameLayout*
318meta_frame_layout_new (void)
319{
320 MetaFrameLayout *layout;
321
322 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
323
324 layout->refcount = 1;
325
326 /* Fill with -1 values to detect invalid themes */
327 layout->left_width = -1;
328 layout->right_width = -1;
329 layout->bottom_height = -1;
330
331 layout->invisible_border.left = 10;
332 layout->invisible_border.right = 10;
333 layout->invisible_border.bottom = 10;
334 layout->invisible_border.top = 10;
335
336 init_border (&layout->title_border);
337
338 layout->title_vertical_pad = -1;
339
340 layout->right_titlebar_edge = -1;
341 layout->left_titlebar_edge = -1;
342
343 layout->button_sizing = META_BUTTON_SIZING_LAST;
344 layout->button_aspect = 1.0;
345 layout->button_width = -1;
346 layout->button_height = -1;
347
348 layout->has_title = TRUE(!(0));
349 layout->title_scale = 1.0;
350
351 init_border (&layout->button_border);
352
353 return layout;
354}
355
356/**
357 *
358 */
359static gboolean
360validate_border (const GtkBorder *border,
361 const char **bad)
362{
363 *bad = NULL((void*)0);
364
365 if (border->top < 0)
366 *bad = _("top")((char *) g_dgettext ("marco", "top"));
367 else if (border->bottom < 0)
368 *bad = _("bottom")((char *) g_dgettext ("marco", "bottom"));
369 else if (border->left < 0)
370 *bad = _("left")((char *) g_dgettext ("marco", "left"));
371 else if (border->right < 0)
372 *bad = _("right")((char *) g_dgettext ("marco", "right"));
373
374 return *bad == NULL((void*)0);
375}
376
377/**
378 * Ensures that the theme supplied a particular dimension. When a
379 * MetaFrameLayout is created, all its integer fields are set to -1
380 * by meta_frame_layout_new(). After an instance of this type
381 * should have been initialised, this function checks that
382 * a given field is not still at -1. It is never called directly, but
383 * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER
384 * macros.
385 *
386 * \param val The value to check
387 * \param name The name to use in the error message
388 * \param[out] error Set to an error if val was not initialised
389 */
390static gboolean
391validate_geometry_value (int val,
392 const char *name,
393 GError **error)
394{
395 if (val < 0)
396 {
397 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
398 META_THEME_ERROR_FRAME_GEOMETRY,
399 _("frame geometry does not specify \"%s\" dimension")((char *) g_dgettext ("marco", "frame geometry does not specify \"%s\" dimension"
))
,
400 name);
401 return FALSE(0);
402 }
403 else
404 return TRUE(!(0));
405}
406
407static gboolean
408validate_geometry_border (const GtkBorder *border,
409 const char *name,
410 GError **error)
411{
412 const char *bad;
413
414 if (!validate_border (border, &bad))
415 {
416 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
417 META_THEME_ERROR_FRAME_GEOMETRY,
418 _("frame geometry does not specify dimension \"%s\" for border \"%s\"")((char *) g_dgettext ("marco", "frame geometry does not specify dimension \"%s\" for border \"%s\""
))
,
419 bad, name);
420 return FALSE(0);
421 }
422 else
423 return TRUE(!(0));
424}
425
426gboolean
427meta_frame_layout_validate (const MetaFrameLayout *layout,
428 GError **error)
429{
430 g_return_val_if_fail (layout != NULL, FALSE)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
((0)); } } while (0)
;
431
432#define CHECK_GEOMETRY_VALUE(vname)if (!validate_geometry_value (layout->vname, "vname", error
)) return (0)
if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE(0)
433
434#define CHECK_GEOMETRY_BORDER(bname)if (!validate_geometry_border (&layout->bname, "bname"
, error)) return (0)
if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE(0)
435
436 CHECK_GEOMETRY_VALUE (left_width)if (!validate_geometry_value (layout->left_width, "left_width"
, error)) return (0)
;
437 CHECK_GEOMETRY_VALUE (right_width)if (!validate_geometry_value (layout->right_width, "right_width"
, error)) return (0)
;
438 CHECK_GEOMETRY_VALUE (bottom_height)if (!validate_geometry_value (layout->bottom_height, "bottom_height"
, error)) return (0)
;
439
440 CHECK_GEOMETRY_BORDER (title_border)if (!validate_geometry_border (&layout->title_border, "title_border"
, error)) return (0)
;
441
442 CHECK_GEOMETRY_VALUE (title_vertical_pad)if (!validate_geometry_value (layout->title_vertical_pad, "title_vertical_pad"
, error)) return (0)
;
443
444 CHECK_GEOMETRY_VALUE (right_titlebar_edge)if (!validate_geometry_value (layout->right_titlebar_edge,
"right_titlebar_edge", error)) return (0)
;
445 CHECK_GEOMETRY_VALUE (left_titlebar_edge)if (!validate_geometry_value (layout->left_titlebar_edge, "left_titlebar_edge"
, error)) return (0)
;
446
447 switch (layout->button_sizing)
448 {
449 case META_BUTTON_SIZING_ASPECT:
450 if (layout->button_aspect < (0.1) ||
451 layout->button_aspect > (15.0))
452 {
453 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
454 META_THEME_ERROR_FRAME_GEOMETRY,
455 _("Button aspect ratio %g is not reasonable")((char *) g_dgettext ("marco", "Button aspect ratio %g is not reasonable"
))
,
456 layout->button_aspect);
457 return FALSE(0);
458 }
459 break;
460 case META_BUTTON_SIZING_FIXED:
461 CHECK_GEOMETRY_VALUE (button_width)if (!validate_geometry_value (layout->button_width, "button_width"
, error)) return (0)
;
462 CHECK_GEOMETRY_VALUE (button_height)if (!validate_geometry_value (layout->button_height, "button_height"
, error)) return (0)
;
463 break;
464 case META_BUTTON_SIZING_LAST:
465 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
466 META_THEME_ERROR_FRAME_GEOMETRY,
467 _("Frame geometry does not specify size of buttons")((char *) g_dgettext ("marco", "Frame geometry does not specify size of buttons"
))
);
468 return FALSE(0);
469 }
470
471 CHECK_GEOMETRY_BORDER (button_border)if (!validate_geometry_border (&layout->button_border,
"button_border", error)) return (0)
;
472
473 return TRUE(!(0));
474}
475
476MetaFrameLayout*
477meta_frame_layout_copy (const MetaFrameLayout *src)
478{
479 MetaFrameLayout *layout;
480
481 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
482
483 *layout = *src;
484
485 layout->refcount = 1;
486
487 return layout;
488}
489
490void
491meta_frame_layout_ref (MetaFrameLayout *layout)
492{
493 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
494
495 layout->refcount += 1;
496}
497
498void
499meta_frame_layout_unref (MetaFrameLayout *layout)
500{
501 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
502 g_return_if_fail (layout->refcount > 0)do { if ((layout->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout->refcount > 0"
); return; } } while (0)
;
503
504 layout->refcount -= 1;
505
506 if (layout->refcount == 0)
507 {
508 DEBUG_FILL_STRUCT (layout)memset ((layout), 0xef, sizeof (*(layout)));
509 g_free (layout);
510 }
511}
512
513void
514meta_frame_layout_get_borders (const MetaFrameLayout *layout,
515 int text_height,
516 MetaFrameFlags flags,
517 MetaFrameBorders *borders)
518{
519 int buttons_height, title_height;
520
521 meta_frame_borders_clear (borders);
522
523 /* For a full-screen window, we don't have any borders, visible or not. */
524 if (flags & META_FRAME_FULLSCREEN)
525 return;
526
527 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
528
529 if (!layout->has_title)
530 text_height = 0;
531
532 buttons_height = layout->button_height +
533 layout->button_border.top + layout->button_border.bottom;
534 title_height = text_height +
535 layout->title_vertical_pad +
536 layout->title_border.top + layout->title_border.bottom;
537
538 borders->visible.top = MAX (buttons_height, title_height)(((buttons_height) > (title_height)) ? (buttons_height) : (
title_height))
;
539 borders->visible.left = layout->left_width;
540 borders->visible.right = layout->right_width;
541 borders->visible.bottom = layout->bottom_height;
542
543 if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
544 {
545 borders->invisible.left = layout->invisible_border.left;
546 borders->invisible.right = layout->invisible_border.right;
547 }
548
549 if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
550 {
551 borders->invisible.bottom = layout->invisible_border.bottom;
552 borders->invisible.top = layout->invisible_border.top;
553 }
554
555 if (flags & META_FRAME_SHADED)
556 borders->visible.bottom = borders->invisible.bottom = 0;
557
558 borders->total.left = borders->invisible.left + borders->visible.left;
559 borders->total.right = borders->invisible.right + borders->visible.right;
560 borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
561 borders->total.top = borders->invisible.top + borders->visible.top;
562}
563
564static MetaButtonType
565map_button_function_to_type (MetaButtonFunction function)
566{
567 switch (function)
568 {
569 case META_BUTTON_FUNCTION_SHADE:
570 return META_BUTTON_TYPE_SHADE;
571 case META_BUTTON_FUNCTION_ABOVE:
572 return META_BUTTON_TYPE_ABOVE;
573 case META_BUTTON_FUNCTION_STICK:
574 return META_BUTTON_TYPE_STICK;
575 case META_BUTTON_FUNCTION_UNSHADE:
576 return META_BUTTON_TYPE_UNSHADE;
577 case META_BUTTON_FUNCTION_UNABOVE:
578 return META_BUTTON_TYPE_UNABOVE;
579 case META_BUTTON_FUNCTION_UNSTICK:
580 return META_BUTTON_TYPE_UNSTICK;
581 case META_BUTTON_FUNCTION_MENU:
582 return META_BUTTON_TYPE_MENU;
583 case META_BUTTON_FUNCTION_APPMENU:
584 return META_BUTTON_TYPE_APPMENU;
585 case META_BUTTON_FUNCTION_MINIMIZE:
586 return META_BUTTON_TYPE_MINIMIZE;
587 case META_BUTTON_FUNCTION_MAXIMIZE:
588 return META_BUTTON_TYPE_MAXIMIZE;
589 case META_BUTTON_FUNCTION_CLOSE:
590 return META_BUTTON_TYPE_CLOSE;
591 case META_BUTTON_FUNCTION_LAST:
592 return META_BUTTON_TYPE_LAST;
593 }
594
595 return META_BUTTON_TYPE_LAST;
596}
597
598static MetaButtonSpace*
599rect_for_function (MetaFrameGeometry *fgeom,
600 MetaFrameFlags flags,
601 MetaButtonFunction function,
602 MetaTheme *theme)
603{
604
605 /* Firstly, check version-specific things. */
606
607 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
608 {
609 switch (function)
610 {
611 case META_BUTTON_FUNCTION_SHADE:
612 if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
613 return &fgeom->shade_rect;
614 else
615 return NULL((void*)0);
616 case META_BUTTON_FUNCTION_ABOVE:
617 if (!(flags & META_FRAME_ABOVE))
618 return &fgeom->above_rect;
619 else
620 return NULL((void*)0);
621 case META_BUTTON_FUNCTION_STICK:
622 if (!(flags & META_FRAME_STUCK))
623 return &fgeom->stick_rect;
624 else
625 return NULL((void*)0);
626 case META_BUTTON_FUNCTION_UNSHADE:
627 if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
628 return &fgeom->unshade_rect;
629 else
630 return NULL((void*)0);
631 case META_BUTTON_FUNCTION_UNABOVE:
632 if (flags & META_FRAME_ABOVE)
633 return &fgeom->unabove_rect;
634 else
635 return NULL((void*)0);
636 case META_BUTTON_FUNCTION_UNSTICK:
637 if (flags & META_FRAME_STUCK)
638 return &fgeom->unstick_rect;
639 default:
640 /* just go on to the next switch block */;
641 }
642 }
643
644 /* now consider the buttons which exist in all versions */
645
646 switch (function)
647 {
648 case META_BUTTON_FUNCTION_MENU:
649 if (flags & META_FRAME_ALLOWS_MENU)
650 return &fgeom->menu_rect;
651 else
652 return NULL((void*)0);
653 case META_BUTTON_FUNCTION_APPMENU:
654 if (flags & META_FRAME_ALLOWS_APPMENU)
655 return &fgeom->appmenu_rect;
656 else
657 return NULL((void*)0);
658 case META_BUTTON_FUNCTION_MINIMIZE:
659 if (flags & META_FRAME_ALLOWS_MINIMIZE)
660 return &fgeom->min_rect;
661 else
662 return NULL((void*)0);
663 case META_BUTTON_FUNCTION_MAXIMIZE:
664 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
665 return &fgeom->max_rect;
666 else
667 return NULL((void*)0);
668 case META_BUTTON_FUNCTION_CLOSE:
669 if (flags & META_FRAME_ALLOWS_DELETE)
670 return &fgeom->close_rect;
671 else
672 return NULL((void*)0);
673 case META_BUTTON_FUNCTION_STICK:
674 case META_BUTTON_FUNCTION_SHADE:
675 case META_BUTTON_FUNCTION_ABOVE:
676 case META_BUTTON_FUNCTION_UNSTICK:
677 case META_BUTTON_FUNCTION_UNSHADE:
678 case META_BUTTON_FUNCTION_UNABOVE:
679 /* we are being asked for a >v1 button which hasn't been handled yet,
680 * so obviously we're not in a theme which supports that version.
681 * therefore, we don't show the button. return NULL and all will
682 * be well.
683 */
684 return NULL((void*)0);
685
686 case META_BUTTON_FUNCTION_LAST:
687 return NULL((void*)0);
688 }
689
690 return NULL((void*)0);
691}
692
693static gboolean
694strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
695 GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
696 int *n_rects,
697 MetaButtonSpace *to_strip)
698{
699 int i;
700
701 i = 0;
702 while (i < *n_rects)
703 {
704 if (func_rects[i] == to_strip)
705 {
706 *n_rects -= 1;
707
708 /* shift the other rects back in the array */
709 while (i < *n_rects)
710 {
711 func_rects[i] = func_rects[i+1];
712 bg_rects[i] = bg_rects[i+1];
713
714 ++i;
715 }
716
717 func_rects[i] = NULL((void*)0);
718 bg_rects[i] = NULL((void*)0);
719
720 return TRUE(!(0));
721 }
722
723 ++i;
724 }
725
726 return FALSE(0); /* did not strip anything */
727}
728
729void
730meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
731 int text_height,
732 MetaFrameFlags flags,
733 int client_width,
734 int client_height,
735 const MetaButtonLayout *button_layout,
736 MetaFrameGeometry *fgeom,
737 MetaTheme *theme)
738{
739 int i, n_left, n_right, n_left_spacers, n_right_spacers;
740 int x;
741 int button_y;
742 int title_right_edge;
743 int width, height;
744 int button_width, button_height;
745 int min_size_for_rounding;
746
747 /* the left/right rects in order; the max # of rects
748 * is the number of button functions
749 */
750 MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
751 MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
752 GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
753 gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
754 GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
755 gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
756
757 MetaFrameBorders borders;
758
759 meta_frame_layout_get_borders (layout, text_height,
760 flags,
761 &borders);
762
763 fgeom->borders = borders;
764
765 width = client_width + borders.total.left + borders.total.right;
766
767 height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
768 borders.total.top + borders.total.bottom;
769
770 fgeom->width = width;
771 fgeom->height = height;
772
773 fgeom->top_titlebar_edge = layout->title_border.top;
774 fgeom->bottom_titlebar_edge = layout->title_border.bottom;
775 fgeom->left_titlebar_edge = layout->left_titlebar_edge;
776 fgeom->right_titlebar_edge = layout->right_titlebar_edge;
777
778 switch (layout->button_sizing)
779 {
780 case META_BUTTON_SIZING_ASPECT:
781 button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
782 button_width = (int) (((double) button_height) / layout->button_aspect);
783 break;
784 case META_BUTTON_SIZING_FIXED:
785 button_width = layout->button_width;
786 button_height = layout->button_height;
787 break;
788 case META_BUTTON_SIZING_LAST:
789 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 789, ((
const char*) (__func__)), ((void*)0)); } while (0)
;
790 default:
791 button_width = -1;
792 button_height = -1;
793 }
794
795 /* FIXME all this code sort of pretends that duplicate buttons
796 * with the same function are allowed, but that breaks the
797 * code in frames.c, so isn't really allowed right now.
798 * Would need left_close_rect, right_close_rect, etc.
799 */
800
801 /* Init all button rects to 0, lame hack */
802 memset (ADDRESS_OF_BUTTON_RECTS (fgeom)(((char*)(fgeom)) + ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
, '\0',
803 LENGTH_OF_BUTTON_RECTS(((glong) __builtin_offsetof(MetaFrameGeometry, right_single_background
)) + sizeof (GdkRectangle) - ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
);
804
805 n_left = 0;
806 n_right = 0;
807 n_left_spacers = 0;
808 n_right_spacers = 0;
809
810 if (!layout->hide_buttons)
811 {
812 /* Try to fill in rects */
813 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
814 {
815 left_func_rects[n_left] = rect_for_function (fgeom, flags,
816 button_layout->left_buttons[i],
817 theme);
818 if (left_func_rects[n_left] != NULL((void*)0))
819 {
820 left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
821 if (button_layout->left_buttons_has_spacer[i])
822 ++n_left_spacers;
823
824 ++n_left;
825 }
826 }
827
828 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
829 {
830 right_func_rects[n_right] = rect_for_function (fgeom, flags,
831 button_layout->right_buttons[i],
832 theme);
833 if (right_func_rects[n_right] != NULL((void*)0))
834 {
835 right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
836 if (button_layout->right_buttons_has_spacer[i])
837 ++n_right_spacers;
838
839 ++n_right;
840 }
841 }
842 }
843
844 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST; i++)
845 {
846 left_bg_rects[i] = NULL((void*)0);
847 right_bg_rects[i] = NULL((void*)0);
848 }
849
850 for (i = 0; i < n_left; i++)
851 {
852 if (n_left == 1)
853 left_bg_rects[i] = &fgeom->left_single_background;
854 else if (i == 0)
855 left_bg_rects[i] = &fgeom->left_left_background;
856 else if (i == (n_left - 1))
857 left_bg_rects[i] = &fgeom->left_right_background;
858 else
859 left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
860 }
861
862 for (i = 0; i < n_right; i++)
863 {
864 if (n_right == 1)
865 right_bg_rects[i] = &fgeom->right_single_background;
866 else if (i == (n_right - 1))
867 right_bg_rects[i] = &fgeom->right_right_background;
868 else if (i == 0)
869 right_bg_rects[i] = &fgeom->right_left_background;
870 else
871 right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
872 }
873
874 /* Be sure buttons fit */
875 while (n_left > 0 || n_right > 0)
876 {
877 int space_used_by_buttons;
878 int space_available;
879
880 space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
881
882 space_used_by_buttons = 0;
883
884 space_used_by_buttons += button_width * n_left;
885 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_left_spacers));
886 space_used_by_buttons += layout->button_border.left * n_left;
887 space_used_by_buttons += layout->button_border.right * n_left;
888
889 space_used_by_buttons += button_width * n_right;
890 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_right_spacers));
891 space_used_by_buttons += layout->button_border.left * n_right;
892 space_used_by_buttons += layout->button_border.right * n_right;
893
894 if (space_used_by_buttons <= space_available)
895 break; /* Everything fits, bail out */
896
897 /* First try to remove separators */
898 if (n_left_spacers > 0)
899 {
900 left_buttons_has_spacer[--n_left_spacers] = FALSE(0);
901 continue;
902 }
903 else if (n_right_spacers > 0)
904 {
905 right_buttons_has_spacer[--n_right_spacers] = FALSE(0);
906 continue;
907 }
908
909 /* Otherwise we need to shave out a button. Shave
910 * above, stick, shade, min, max, close, then menu (menu is most useful);
911 * prefer the default button locations.
912 */
913 if (strip_button (left_func_rects, left_bg_rects,
914 &n_left, &fgeom->above_rect))
915 continue;
916 else if (strip_button (right_func_rects, right_bg_rects,
917 &n_right, &fgeom->above_rect))
918 continue;
919 else if (strip_button (left_func_rects, left_bg_rects,
920 &n_left, &fgeom->stick_rect))
921 continue;
922 else if (strip_button (right_func_rects, right_bg_rects,
923 &n_right, &fgeom->stick_rect))
924 continue;
925 else if (strip_button (left_func_rects, left_bg_rects,
926 &n_left, &fgeom->shade_rect))
927 continue;
928 else if (strip_button (right_func_rects, right_bg_rects,
929 &n_right, &fgeom->shade_rect))
930 continue;
931 else if (strip_button (left_func_rects, left_bg_rects,
932 &n_left, &fgeom->min_rect))
933 continue;
934 else if (strip_button (right_func_rects, right_bg_rects,
935 &n_right, &fgeom->min_rect))
936 continue;
937 else if (strip_button (left_func_rects, left_bg_rects,
938 &n_left, &fgeom->max_rect))
939 continue;
940 else if (strip_button (right_func_rects, right_bg_rects,
941 &n_right, &fgeom->max_rect))
942 continue;
943 else if (strip_button (left_func_rects, left_bg_rects,
944 &n_left, &fgeom->close_rect))
945 continue;
946 else if (strip_button (right_func_rects, right_bg_rects,
947 &n_right, &fgeom->close_rect))
948 continue;
949 else if (strip_button (right_func_rects, right_bg_rects,
950 &n_right, &fgeom->menu_rect))
951 continue;
952 else if (strip_button (left_func_rects, left_bg_rects,
953 &n_left, &fgeom->menu_rect))
954 continue;
955 else if (strip_button (right_func_rects, right_bg_rects,
956 &n_right, &fgeom->appmenu_rect))
957 continue;
958 else if (strip_button (left_func_rects, left_bg_rects,
959 &n_left, &fgeom->appmenu_rect))
960 continue;
961 else
962 {
963 meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
964 n_left, n_right);
965 }
966 }
967
968 /* Save the button layout */
969 fgeom->button_layout = *button_layout;
970 fgeom->n_left_buttons = n_left;
971 fgeom->n_right_buttons = n_right;
972
973 /* center buttons vertically */
974 button_y = (borders.visible.top -
975 (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + borders.invisible.top;
976
977 /* right edge of farthest-right button */
978 x = width - layout->right_titlebar_edge - borders.invisible.right;
979
980 i = n_right - 1;
981 while (i >= 0)
982 {
983 MetaButtonSpace *rect;
984
985 if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
986 break;
987
988 rect = right_func_rects[i];
989 rect->visible.x = x - layout->button_border.right - button_width;
990 if (right_buttons_has_spacer[i])
991 rect->visible.x -= (int) (0.75 * (double) button_width);
992
993 rect->visible.y = button_y;
994 rect->visible.width = button_width;
995 rect->visible.height = button_height;
996
997 if (flags & META_FRAME_MAXIMIZED ||
998 flags & META_FRAME_TILED_LEFT ||
999 flags & META_FRAME_TILED_RIGHT)
1000 {
1001 rect->clickable.x = rect->visible.x;
1002 rect->clickable.y = rect->visible.y;
1003 rect->clickable.width = button_width;
1004 rect->clickable.height = button_height;
1005
1006 if (i == n_right - 1)
1007 rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
1008
1009 }
1010 else
1011 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1012
1013 *(right_bg_rects[i]) = rect->visible;
1014
1015 x = rect->visible.x - layout->button_border.left;
1016
1017 --i;
1018 }
1019
1020 /* save right edge of titlebar for later use */
1021 title_right_edge = x - layout->title_border.right;
1022
1023 /* Now x changes to be position from the left and we go through
1024 * the left-side buttons
1025 */
1026 x = layout->left_titlebar_edge + borders.invisible.left;
1027 for (i = 0; i < n_left; i++)
1028 {
1029 MetaButtonSpace *rect;
1030
1031 rect = left_func_rects[i];
1032
1033 rect->visible.x = x + layout->button_border.left;
1034 rect->visible.y = button_y;
1035 rect->visible.width = button_width;
1036 rect->visible.height = button_height;
1037
1038 if (flags & META_FRAME_MAXIMIZED)
1039 {
1040 rect->clickable.x = rect->visible.x;
1041 rect->clickable.y = rect->visible.y;
1042 rect->clickable.width = button_width;
1043 rect->clickable.height = button_height;
1044 }
1045 else
1046 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1047
1048 x = rect->visible.x + rect->visible.width + layout->button_border.right;
1049 if (left_buttons_has_spacer[i])
1050 x += (int) (0.75 * (double) button_width);
1051
1052 *(left_bg_rects[i]) = rect->visible;
1053 }
1054
1055 /* We always fill as much vertical space as possible with title rect,
1056 * rather than centering it like the buttons
1057 */
1058 fgeom->title_rect.x = x + layout->title_border.left;
1059 fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
1060 fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
1061 fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
1062
1063 /* Nuke title if it won't fit */
1064 if (fgeom->title_rect.width < 0 ||
1065 fgeom->title_rect.height < 0)
1066 {
1067 fgeom->title_rect.width = 0;
1068 fgeom->title_rect.height = 0;
1069 }
1070
1071 if (flags & META_FRAME_SHADED)
1072 min_size_for_rounding = 0;
1073 else
1074 min_size_for_rounding = 5;
1075
1076 fgeom->top_left_corner_rounded_radius = 0;
1077 fgeom->top_right_corner_rounded_radius = 0;
1078 fgeom->bottom_left_corner_rounded_radius = 0;
1079 fgeom->bottom_right_corner_rounded_radius = 0;
1080
1081 if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
1082 fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
1083 if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
1084 fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
1085
1086 if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
1087 fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
1088 if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
1089 fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
1090}
1091
1092MetaGradientSpec*
1093meta_gradient_spec_new (MetaGradientType type)
1094{
1095 MetaGradientSpec *spec;
1096
1097 spec = g_new (MetaGradientSpec, 1)((MetaGradientSpec *) g_malloc_n ((1), sizeof (MetaGradientSpec
)))
;
1098
1099 spec->type = type;
1100 spec->color_specs = NULL((void*)0);
1101
1102 return spec;
1103}
1104
1105static cairo_pattern_t *
1106create_cairo_pattern_from_gradient_spec (const MetaGradientSpec *spec,
1107 const MetaAlphaGradientSpec *alpha_spec,
1108 GtkStyleContext *context)
1109{
1110 gint n_colors;
1111 cairo_pattern_t *pattern;
1112 GSList *tmp;
1113 gint i;
1114
1115 n_colors = g_slist_length (spec->color_specs);
1116 if (n_colors == 0)
1117 return NULL((void*)0);
1118
1119 if (alpha_spec != NULL((void*)0) && alpha_spec->n_alphas != 1)
1120 g_assert (n_colors == alpha_spec->n_alphas)do { if (n_colors == alpha_spec->n_alphas) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1120, ((const char*) (__func__)), "n_colors == alpha_spec->n_alphas"
); } while (0)
;
1121
1122 if (spec->type == META_GRADIENT_HORIZONTAL)
1123 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1124 else if (spec->type == META_GRADIENT_VERTICAL)
1125 pattern = cairo_pattern_create_linear (0, 0, 0, 1);
1126 else if (spec->type == META_GRADIENT_DIAGONAL)
1127 pattern = cairo_pattern_create_linear (0, 0, 1, 1);
1128 else
1129 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1129, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1130
1131 i = 0;
1132 tmp = spec->color_specs;
1133 while (tmp != NULL((void*)0))
1134 {
1135 GdkRGBA color;
1136
1137 meta_color_spec_render (tmp->data, context, &color);
1138
1139 if (alpha_spec != NULL((void*)0))
1140 {
1141 gdouble alpha;
1142
1143 if (alpha_spec->n_alphas == 1)
1144 alpha = alpha_spec->alphas[0] / 255.0;
1145 else
1146 alpha = alpha_spec->alphas[i] / 255.0;
1147
1148 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_colors - 1),
1149 color.red, color.green, color.blue,
1150 alpha);
1151 }
1152 else
1153 cairo_pattern_add_color_stop_rgb (pattern, i / (gfloat) (n_colors - 1),
1154 color.red, color.green, color.blue);
1155
1156 tmp = tmp->next;
1157 ++i;
1158 }
1159
1160 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1161 {
1162 cairo_pattern_destroy (pattern);
1163 return NULL((void*)0);
1164 }
1165
1166 return pattern;
1167}
1168
1169static void
1170free_color_spec (gpointer spec, gpointer user_data)
1171{
1172 meta_color_spec_free (spec);
1173}
1174
1175void
1176meta_gradient_spec_free (MetaGradientSpec *spec)
1177{
1178 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1179
1180 g_slist_foreach (spec->color_specs, free_color_spec, NULL((void*)0));
1181 g_slist_free (spec->color_specs);
1182
1183 DEBUG_FILL_STRUCT (spec)memset ((spec), 0xef, sizeof (*(spec)));
1184 g_free (spec);
1185}
1186
1187void
1188meta_gradient_spec_render (const MetaGradientSpec *spec,
1189 const MetaAlphaGradientSpec *alpha_spec,
1190 cairo_t *cr,
1191 GtkStyleContext *context,
1192 gint x,
1193 gint y,
1194 gint width,
1195 gint height)
1196{
1197 cairo_pattern_t *pattern;
1198
1199 pattern = create_cairo_pattern_from_gradient_spec (spec, alpha_spec, context);
1200 if (pattern == NULL((void*)0))
1201 return;
1202
1203 cairo_save (cr);
1204
1205 cairo_rectangle (cr, x, y, width, height);
1206
1207 cairo_translate (cr, x, y);
1208 cairo_scale (cr, width, height);
1209
1210 cairo_set_source (cr, pattern);
1211 cairo_fill (cr);
1212 cairo_pattern_destroy (pattern);
1213
1214 cairo_restore (cr);
1215}
1216
1217gboolean
1218meta_gradient_spec_validate (MetaGradientSpec *spec,
1219 GError **error)
1220{
1221 g_return_val_if_fail (spec != NULL, FALSE)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
((0)); } } while (0)
;
1222
1223 if (g_slist_length (spec->color_specs) < 2)
1224 {
1225 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1226 META_THEME_ERROR_FAILED,
1227 _("Gradients should have at least two colors")((char *) g_dgettext ("marco", "Gradients should have at least two colors"
))
);
1228 return FALSE(0);
1229 }
1230
1231 return TRUE(!(0));
1232}
1233
1234MetaAlphaGradientSpec*
1235meta_alpha_gradient_spec_new (MetaGradientType type,
1236 int n_alphas)
1237{
1238 MetaAlphaGradientSpec *spec;
1239
1240 g_return_val_if_fail (n_alphas > 0, NULL)do { if ((n_alphas > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_alphas > 0"); return
(((void*)0)); } } while (0)
;
1241
1242 spec = g_new0 (MetaAlphaGradientSpec, 1)((MetaAlphaGradientSpec *) g_malloc0_n ((1), sizeof (MetaAlphaGradientSpec
)))
;
1243
1244 spec->type = type;
1245 spec->alphas = g_new0 (unsigned char, n_alphas)((unsigned char *) g_malloc0_n ((n_alphas), sizeof (unsigned char
)))
;
1246 spec->n_alphas = n_alphas;
1247
1248 return spec;
1249}
1250
1251void
1252meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
1253{
1254 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1255
1256 g_free (spec->alphas);
1257 g_free (spec);
1258}
1259
1260cairo_pattern_t *
1261meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec)
1262{
1263 gint n_alphas;
1264 cairo_pattern_t *pattern;
1265 gint i;
1266
1267 /* Hardcoded in theme-parser.c */
1268 g_assert (spec->type == META_GRADIENT_HORIZONTAL)do { if (spec->type == META_GRADIENT_HORIZONTAL) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1268, ((const char*) (__func__)), "spec->type == META_GRADIENT_HORIZONTAL"
); } while (0)
;
1269
1270 n_alphas = spec->n_alphas;
1271 if (n_alphas == 0)
1272 return NULL((void*)0);
1273
1274 if (n_alphas == 1)
1275 return cairo_pattern_create_rgba (0, 0, 0, spec->alphas[0] / 255.0);
1276
1277 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1278
1279 for (i = 0; i < n_alphas; i++)
1280 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_alphas - 1),
1281 0, 0, 0, spec->alphas[i] / 255.0);
1282
1283 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1284 {
1285 cairo_pattern_destroy (pattern);
1286 return NULL((void*)0);
1287 }
1288
1289 return pattern;
1290}
1291
1292MetaColorSpec*
1293meta_color_spec_new (MetaColorSpecType type)
1294{
1295 MetaColorSpec *spec;
1296 MetaColorSpec dummy;
1297 int size;
1298
1299 size = G_STRUCT_OFFSET (MetaColorSpec, data)((glong) __builtin_offsetof(MetaColorSpec, data));
1300
1301 switch (type)
1302 {
1303 case META_COLOR_SPEC_BASIC:
1304 size += sizeof (dummy.data.basic);
1305 break;
1306
1307 case META_COLOR_SPEC_GTK:
1308 size += sizeof (dummy.data.gtk);
1309 break;
1310
1311 case META_COLOR_SPEC_GTK_CUSTOM:
1312 size += sizeof (dummy.data.gtkcustom);
1313 break;
1314
1315 case META_COLOR_SPEC_BLEND:
1316 size += sizeof (dummy.data.blend);
1317 break;
1318
1319 case META_COLOR_SPEC_SHADE:
1320 size += sizeof (dummy.data.shade);
1321 break;
1322 }
1323
1324 spec = g_malloc0 (size);
1325
1326 spec->type = type;
1327
1328 return spec;
1329}
1330
1331void
1332meta_color_spec_free (MetaColorSpec *spec)
1333{
1334 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1335
1336 switch (spec->type)
1337 {
1338 case META_COLOR_SPEC_BASIC:
1339 DEBUG_FILL_STRUCT (&spec->data.basic)memset ((&spec->data.basic), 0xef, sizeof (*(&spec
->data.basic)))
;
1340 break;
1341
1342 case META_COLOR_SPEC_GTK:
1343 DEBUG_FILL_STRUCT (&spec->data.gtk)memset ((&spec->data.gtk), 0xef, sizeof (*(&spec->
data.gtk)))
;
1344 break;
1345
1346 case META_COLOR_SPEC_GTK_CUSTOM:
1347 if (spec->data.gtkcustom.color_name)
1348 g_free (spec->data.gtkcustom.color_name);
1349 if (spec->data.gtkcustom.fallback)
1350 meta_color_spec_free (spec->data.gtkcustom.fallback);
1351 DEBUG_FILL_STRUCT (&spec->data.gtkcustom)memset ((&spec->data.gtkcustom), 0xef, sizeof (*(&
spec->data.gtkcustom)))
;
1352 break;
1353
1354 case META_COLOR_SPEC_BLEND:
1355 if (spec->data.blend.foreground)
1356 meta_color_spec_free (spec->data.blend.foreground);
1357 if (spec->data.blend.background)
1358 meta_color_spec_free (spec->data.blend.background);
1359 DEBUG_FILL_STRUCT (&spec->data.blend)memset ((&spec->data.blend), 0xef, sizeof (*(&spec
->data.blend)))
;
1360 break;
1361
1362 case META_COLOR_SPEC_SHADE:
1363 if (spec->data.shade.base)
1364 meta_color_spec_free (spec->data.shade.base);
1365 DEBUG_FILL_STRUCT (&spec->data.shade)memset ((&spec->data.shade), 0xef, sizeof (*(&spec
->data.shade)))
;
1366 break;
1367 }
1368
1369 g_free (spec);
1370}
1371
1372MetaColorSpec*
1373meta_color_spec_new_from_string (const char *str,
1374 GError **err)
1375{
1376 MetaColorSpec *spec;
1377
1378 spec = NULL((void*)0);
1379
1380 if (strncmp (str, "gtk:custom", 10) == 0)
1381 {
1382 const char *color_name_start, *fallback_str_start, *end;
1383 char *color_name;
1384 MetaColorSpec *fallback = NULL((void*)0);
1385 static gboolean debug, debug_set = FALSE(0);
1386
1387 if (!debug_set)
1388 {
1389 debug = g_getenv ("MARCO_DISABLE_FALLBACK_COLOR") != NULL((void*)0);
1390 debug_set = TRUE(!(0));
1391 }
1392
1393 if (str[10] != '(')
1394 {
1395 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1396 META_THEME_ERROR_FAILED,
1397 _("GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""
))
,
1398 str);
1399 return NULL((void*)0);
1400 }
1401
1402 color_name_start = str + 11;
1403
1404 fallback_str_start = color_name_start;
1405 while (*fallback_str_start && *fallback_str_start != ',')
1406 {
1407 if (!(g_ascii_isalnum (*fallback_str_start)((g_ascii_table[(guchar) (*fallback_str_start)] & G_ASCII_ALNUM
) != 0)
1408 || *fallback_str_start == '-'
1409 || *fallback_str_start == '_'))
1410 {
1411 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1412 META_THEME_ERROR_FAILED,
1413 _("Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid")((char *) g_dgettext ("marco", "Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid"
))
,
1414 *fallback_str_start);
1415 return NULL((void*)0);
1416 }
1417 fallback_str_start++;
1418 }
1419 fallback_str_start++;
1420
1421 end = strrchr (str, ')');
1422
1423 if (color_name_start == NULL((void*)0) || fallback_str_start == NULL((void*)0) || end == NULL((void*)0))
1424 {
1425 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1426 META_THEME_ERROR_FAILED,
1427 _("Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format"
))
,
1428 str);
1429 return NULL((void*)0);
1430 }
1431
1432 if (!debug)
1433 {
1434 char *fallback_str;
1435 fallback_str = g_strndup (fallback_str_start,
1436 end - fallback_str_start);
1437 fallback = meta_color_spec_new_from_string (fallback_str, err);
1438 g_free (fallback_str);
1439 }
1440 else
1441 {
1442 fallback = meta_color_spec_new_from_string ("pink", err);
1443 }
1444
1445 if (fallback == NULL((void*)0))
1446 return NULL((void*)0);
1447
1448 color_name = g_strndup (color_name_start, fallback_str_start - color_name_start - 1);
1449
1450 spec = meta_color_spec_new (META_COLOR_SPEC_GTK_CUSTOM);
1451 spec->data.gtkcustom.color_name = color_name;
1452 spec->data.gtkcustom.fallback = fallback;
1453 }
1454 else if (strncmp (str, "gtk:", 4) == 0)
1455 {
1456 /* GTK color */
1457 const char *bracket;
1458 const char *end_bracket;
1459 char *tmp;
1460 GtkStateFlags state;
1461 MetaGtkColorComponent component;
1462
1463 bracket = str;
1464 while (*bracket && *bracket != '[')
1465 ++bracket;
1466
1467 if (*bracket == '\0')
1468 {
1469 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1470 META_THEME_ERROR_FAILED,
1471 _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1472 str);
1473 return NULL((void*)0);
1474 }
1475
1476 end_bracket = bracket;
1477 ++end_bracket;
1478 while (*end_bracket && *end_bracket != ']')
1479 ++end_bracket;
1480
1481 if (*end_bracket == '\0')
1482 {
1483 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1484 META_THEME_ERROR_FAILED,
1485 _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1486 str);
1487 return NULL((void*)0);
1488 }
1489
1490 tmp = g_strndup (bracket + 1, end_bracket - bracket - 1);
1491 state = meta_gtk_state_from_string (tmp);
1492 if (((int) state) == -1)
1493 {
1494 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1495 META_THEME_ERROR_FAILED,
1496 _("Did not understand state \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand state \"%s\" in color specification"
))
,
1497 tmp);
1498 g_free (tmp);
1499 return NULL((void*)0);
1500 }
1501 g_free (tmp);
1502
1503 tmp = g_strndup (str + 4, bracket - str - 4);
1504 component = meta_color_component_from_string (tmp);
1505 if (component == META_GTK_COLOR_LAST)
1506 {
1507 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1508 META_THEME_ERROR_FAILED,
1509 _("Did not understand color component \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand color component \"%s\" in color specification"
))
,
1510 tmp);
1511 g_free (tmp);
1512 return NULL((void*)0);
1513 }
1514 g_free (tmp);
1515
1516 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1517 spec->data.gtk.state = state;
1518 spec->data.gtk.component = component;
1519 g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST)do { if (spec->data.gtk.component < META_GTK_COLOR_LAST
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 1519
, ((const char*) (__func__)), "spec->data.gtk.component < META_GTK_COLOR_LAST"
); } while (0)
;
1520 }
1521 else if (strncmp (str, "blend/", 6) == 0)
1522 {
1523 /* blend */
1524 char **split;
1525 double alpha;
1526 char *end;
1527 MetaColorSpec *fg;
1528 MetaColorSpec *bg;
1529
1530 split = g_strsplit (str, "/", 4);
1531
1532 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1533 split[2] == NULL((void*)0) || split[3] == NULL((void*)0))
1534 {
1535 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1536 META_THEME_ERROR_FAILED,
1537 _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"
))
,
1538 str);
1539 g_strfreev (split);
1540 return NULL((void*)0);
1541 }
1542
1543 alpha = g_ascii_strtod (split[3], &end);
1544 if (end == split[3])
1545 {
1546 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1547 META_THEME_ERROR_FAILED,
1548 _("Could not parse alpha value \"%s\" in blended color")((char *) g_dgettext ("marco", "Could not parse alpha value \"%s\" in blended color"
))
,
1549 split[3]);
1550 g_strfreev (split);
1551 return NULL((void*)0);
1552 }
1553
1554 if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6))
1555 {
1556 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1557 META_THEME_ERROR_FAILED,
1558 _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0")((char *) g_dgettext ("marco", "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
))
,
1559 split[3]);
1560 g_strfreev (split);
1561 return NULL((void*)0);
1562 }
1563
1564 fg = NULL((void*)0);
1565 bg = NULL((void*)0);
1566
1567 bg = meta_color_spec_new_from_string (split[1], err);
1568 if (bg == NULL((void*)0))
1569 {
1570 g_strfreev (split);
1571 return NULL((void*)0);
1572 }
1573
1574 fg = meta_color_spec_new_from_string (split[2], err);
1575 if (fg == NULL((void*)0))
1576 {
1577 meta_color_spec_free (bg);
1578 g_strfreev (split);
1579 return NULL((void*)0);
1580 }
1581
1582 g_strfreev (split);
1583
1584 spec = meta_color_spec_new (META_COLOR_SPEC_BLEND);
1585 spec->data.blend.alpha = alpha;
1586 spec->data.blend.background = bg;
1587 spec->data.blend.foreground = fg;
1588 }
1589 else if (strncmp (str, "shade/", 6) == 0)
1590 {
1591 /* shade */
1592 char **split;
1593 double factor;
1594 char *end;
1595 MetaColorSpec *base;
1596
1597 split = g_strsplit (str, "/", 3);
1598
1599 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1600 split[2] == NULL((void*)0))
1601 {
1602 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1603 META_THEME_ERROR_FAILED,
1604 _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
))
,
1605 str);
1606 g_strfreev (split);
1607 return NULL((void*)0);
1608 }
1609
1610 factor = g_ascii_strtod (split[2], &end);
1611 if (end == split[2])
1612 {
1613 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1614 META_THEME_ERROR_FAILED,
1615 _("Could not parse shade factor \"%s\" in shaded color")((char *) g_dgettext ("marco", "Could not parse shade factor \"%s\" in shaded color"
))
,
1616 split[2]);
1617 g_strfreev (split);
1618 return NULL((void*)0);
1619 }
1620
1621 if (factor < (0.0 - 1e6))
1622 {
1623 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1624 META_THEME_ERROR_FAILED,
1625 _("Shade factor \"%s\" in shaded color is negative")((char *) g_dgettext ("marco", "Shade factor \"%s\" in shaded color is negative"
))
,
1626 split[2]);
1627 g_strfreev (split);
1628 return NULL((void*)0);
1629 }
1630
1631 base = NULL((void*)0);
1632
1633 base = meta_color_spec_new_from_string (split[1], err);
1634 if (base == NULL((void*)0))
1635 {
1636 g_strfreev (split);
1637 return NULL((void*)0);
1638 }
1639
1640 g_strfreev (split);
1641
1642 spec = meta_color_spec_new (META_COLOR_SPEC_SHADE);
1643 spec->data.shade.factor = factor;
1644 spec->data.shade.base = base;
1645 }
1646 else
1647 {
1648 spec = meta_color_spec_new (META_COLOR_SPEC_BASIC);
1649
1650 if (!gdk_rgba_parse (&spec->data.basic.color, str))
1651 {
1652 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1653 META_THEME_ERROR_FAILED,
1654 _("Could not parse color \"%s\"")((char *) g_dgettext ("marco", "Could not parse color \"%s\""
))
,
1655 str);
1656 meta_color_spec_free (spec);
1657 return NULL((void*)0);
1658 }
1659 }
1660
1661 g_assert (spec)do { if (spec) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 1661, ((const char*) (__func__)), "spec"); } while (0)
;
1662
1663 return spec;
1664}
1665
1666MetaColorSpec*
1667meta_color_spec_new_gtk (MetaGtkColorComponent component,
1668 GtkStateFlags state)
1669{
1670 MetaColorSpec *spec;
1671
1672 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1673
1674 spec->data.gtk.component = component;
1675 spec->data.gtk.state = state;
1676
1677 return spec;
1678}
1679
1680static void
1681get_background_color_real (GtkStyleContext *context,
1682 GtkStateFlags state,
1683 GdkRGBA *color)
1684{
1685 GdkRGBA *c;
1686
1687 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "color != NULL"); return
; } } while (0)
;
1688 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context)); GType __t = ((gtk_style_context_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "GTK_IS_STYLE_CONTEXT (context)"); return; } }
while (0)
;
1689
1690 gtk_style_context_get (context,
1691 state,
1692 "background-color", &c,
1693 NULL((void*)0));
1694
1695 *color = *c;
1696 gdk_rgba_free (c);
1697}
1698
1699static void
1700get_background_color (GtkStyleContext *context,
1701 GtkStateFlags state,
1702 GdkRGBA *color)
1703{
1704 GdkRGBA empty = { 0.0, 0.0, 0.0, 0.0 };
1705 GdkRGBA rgba;
1706
1707 get_background_color_real (context, state, &rgba);
1708
1709 if (gdk_rgba_equal (&rgba, &empty))
1710 {
1711 GtkWidget *toplevel;
1712 GtkStyleContext *tmp;
1713
1714 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1715 tmp = gtk_widget_get_style_context (toplevel);
1716
1717 get_background_color_real (tmp, state, &rgba);
1718
1719 gtk_widget_destroy (toplevel);
1720 }
1721
1722 *color = rgba;
1723}
1724
1725/* Based on set_color() in gtkstyle.c */
1726#define LIGHTNESS_MULT1.3 1.3
1727#define DARKNESS_MULT0.7 0.7
1728void
1729meta_gtk_style_get_light_color (GtkStyleContext *style,
1730 GtkStateFlags state,
1731 GdkRGBA *color)
1732{
1733 get_background_color (style, state, color);
1734 gtk_style_shade (color, color, LIGHTNESS_MULT1.3);
1735}
1736
1737void
1738meta_gtk_style_get_dark_color (GtkStyleContext *style,
1739 GtkStateFlags state,
1740 GdkRGBA *color)
1741{
1742 get_background_color (style, state, color);
1743 gtk_style_shade (color, color, DARKNESS_MULT0.7);
1744}
1745
1746static void
1747meta_set_color_from_style (GdkRGBA *color,
1748 GtkStyleContext *context,
1749 GtkStateFlags state,
1750 MetaGtkColorComponent component)
1751{
1752 GdkRGBA other;
1753
1754 /* Add background class to context to get the correct colors from the GTK+
1755 theme instead of white text over black background. */
1756 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND"background");
1757
1758 switch (component)
1759 {
1760 case META_GTK_COLOR_BG:
1761 case META_GTK_COLOR_BASE:
1762 get_background_color (context, state, color);
1763 break;
1764 case META_GTK_COLOR_FG:
1765 case META_GTK_COLOR_TEXT:
1766 gtk_style_context_get_color (context, state, color);
1767 break;
1768 case META_GTK_COLOR_TEXT_AA:
1769 gtk_style_context_get_color (context, state, color);
1770 meta_set_color_from_style (&other, context, state, META_GTK_COLOR_BASE);
1771
1772 color->red = (color->red + other.red) / 2;
1773 color->green = (color->green + other.green) / 2;
1774 color->blue = (color->blue + other.blue) / 2;
1775 break;
1776 case META_GTK_COLOR_MID:
1777 meta_gtk_style_get_light_color (context, state, color);
1778 meta_gtk_style_get_dark_color (context, state, &other);
1779
1780 color->red = (color->red + other.red) / 2;
1781 color->green = (color->green + other.green) / 2;
1782 color->blue = (color->blue + other.blue) / 2;
1783 break;
1784 case META_GTK_COLOR_LIGHT:
1785 meta_gtk_style_get_light_color (context, state, color);
1786 break;
1787 case META_GTK_COLOR_DARK:
1788 meta_gtk_style_get_dark_color (context, state, color);
1789 break;
1790 case META_GTK_COLOR_LAST:
1791 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1791, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1792 break;
1793 }
1794}
1795
1796static void
1797meta_set_custom_color_from_style (GdkRGBA *color,
1798 GtkStyleContext *context,
1799 char *color_name,
1800 MetaColorSpec *fallback)
1801{
1802 if (!gtk_style_context_lookup_color (context, color_name, color))
1803 meta_color_spec_render (fallback, context, color);
1804}
1805
1806void
1807meta_color_spec_render (MetaColorSpec *spec,
1808 GtkStyleContext *style,
1809 GdkRGBA *color)
1810{
1811 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1812
1813 g_return_if_fail (GTK_IS_STYLE_CONTEXT (style))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((style)); GType __t = ((gtk_style_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GTK_IS_STYLE_CONTEXT (style)"); return; } } while (0)
;
1814
1815 switch (spec->type)
1816 {
1817 case META_COLOR_SPEC_BASIC:
1818 *color = spec->data.basic.color;
1819 break;
1820
1821 case META_COLOR_SPEC_GTK:
1822 meta_set_color_from_style (color,
1823 style,
1824 spec->data.gtk.state,
1825 spec->data.gtk.component);
1826 break;
1827
1828 case META_COLOR_SPEC_GTK_CUSTOM:
1829 meta_set_custom_color_from_style (color,
1830 style,
1831 spec->data.gtkcustom.color_name,
1832 spec->data.gtkcustom.fallback);
1833 break;
1834
1835 case META_COLOR_SPEC_BLEND:
1836 {
1837 GdkRGBA bg, fg;
1838
1839 meta_color_spec_render (spec->data.blend.background, style, &bg);
1840 meta_color_spec_render (spec->data.blend.foreground, style, &fg);
1841
1842 color_composite (&bg, &fg, spec->data.blend.alpha,
1843 &spec->data.blend.color);
1844
1845 *color = spec->data.blend.color;
1846 }
1847 break;
1848
1849 case META_COLOR_SPEC_SHADE:
1850 {
1851 meta_color_spec_render (spec->data.shade.base, style,
1852 &spec->data.shade.color);
1853
1854 gtk_style_shade (&spec->data.shade.color,
1855 &spec->data.shade.color, spec->data.shade.factor);
1856
1857 *color = spec->data.shade.color;
1858 }
1859 break;
1860 }
1861}
1862
1863/**
1864 * Represents an operation as a string.
1865 *
1866 * \param type an operation, such as addition
1867 * \return a string, such as "+"
1868 */
1869static const char*
1870op_name (PosOperatorType type)
1871{
1872 switch (type)
1873 {
1874 case POS_OP_ADD:
1875 return "+";
1876 case POS_OP_SUBTRACT:
1877 return "-";
1878 case POS_OP_MULTIPLY:
1879 return "*";
1880 case POS_OP_DIVIDE:
1881 return "/";
1882 case POS_OP_MOD:
1883 return "%";
1884 case POS_OP_MAX:
1885 return "`max`";
1886 case POS_OP_MIN:
1887 return "`min`";
1888 case POS_OP_NONE:
1889 break;
1890 }
1891
1892 return "<unknown>";
1893}
1894
1895/**
1896 * Parses a string and returns an operation.
1897 *
1898 * \param p a pointer into a string representing an operation; part of an
1899 * expression somewhere, so not null-terminated
1900 * \param len set to the length of the string found. Set to 0 if none is.
1901 * \return the operation found. If none was, returns POS_OP_NONE.
1902 */
1903static PosOperatorType
1904op_from_string (const char *p,
1905 int *len)
1906{
1907 *len = 0;
1908
1909 switch (*p)
1910 {
1911 case '+':
1912 *len = 1;
1913 return POS_OP_ADD;
1914 case '-':
1915 *len = 1;
1916 return POS_OP_SUBTRACT;
1917 case '*':
1918 *len = 1;
1919 return POS_OP_MULTIPLY;
1920 case '/':
1921 *len = 1;
1922 return POS_OP_DIVIDE;
1923 case '%':
1924 *len = 1;
1925 return POS_OP_MOD;
1926
1927 case '`':
1928 if (strncmp (p, "`max`", 5) == 0)
1929 {
1930 *len = 5;
1931 return POS_OP_MAX;
1932 }
1933 else if (strncmp (p, "`min`", 5) == 0)
1934 {
1935 *len = 5;
1936 return POS_OP_MIN;
1937 }
1938 }
1939
1940 return POS_OP_NONE;
1941}
1942
1943/**
1944 * Frees an array of tokens. All the tokens and their associated memory
1945 * will be freed.
1946 *
1947 * \param tokens an array of tokens to be freed
1948 * \param n_tokens how many tokens are in the array.
1949 */
1950static void
1951free_tokens (PosToken *tokens,
1952 int n_tokens)
1953{
1954 int i;
1955
1956 /* n_tokens can be 0 since tokens may have been allocated more than
1957 * it was initialized
1958 */
1959
1960 for (i = 0; i < n_tokens; i++)
1961 if (tokens[i].type == POS_TOKEN_VARIABLE)
1962 g_free (tokens[i].d.v.name);
1963
1964 g_free (tokens);
1965}
1966
1967/**
1968 * Tokenises a number in an expression.
1969 *
1970 * \param p a pointer into a string representing an operation; part of an
1971 * expression somewhere, so not null-terminated
1972 * \param end_return set to a pointer to the end of the number found; but
1973 * not updated if no number was found at all
1974 * \param next set to either an integer or a float token
1975 * \param[out] err set to the problem if there was a problem
1976 * \return TRUE if a valid number was found, FALSE otherwise (and "err" will
1977 * have been set)
1978 *
1979 * \bug The "while (*start)..." part: what's wrong with strchr-ish things?
1980 * \bug The name is wrong: it doesn't parse anything.
1981 * \ingroup tokenizer
1982 */
1983static gboolean
1984parse_number (const char *p,
1985 const char **end_return,
1986 PosToken *next,
1987 GError **err)
1988{
1989 const char *start = p;
1990 char *end;
1991 gboolean is_float;
1992 char *num_str;
1993
1994 while (*p && (*p == '.' || g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0)))
1995 ++p;
1996
1997 if (p == start)
1998 {
1999 char buf[7] = { '\0' };
2000 buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0';
2001 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2002 META_THEME_ERROR_BAD_CHARACTER,
2003 _("Coordinate expression contains character '%s' which is not allowed")((char *) g_dgettext ("marco", "Coordinate expression contains character '%s' which is not allowed"
))
,
2004 buf);
2005 return FALSE(0);
2006 }
2007
2008 *end_return = p;
2009
2010 /* we need this to exclude floats like "1e6" */
2011 num_str = g_strndup (start, p - start);
2012 start = num_str;
2013 is_float = FALSE(0);
2014 while (*start)
2015 {
2016 if (*start == '.')
2017 is_float = TRUE(!(0));
2018 ++start;
2019 }
2020
2021 if (is_float)
2022 {
2023 next->type = POS_TOKEN_DOUBLE;
2024 next->d.d.val = g_ascii_strtod (num_str, &end);
2025
2026 if (end == num_str)
2027 {
2028 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2029 META_THEME_ERROR_FAILED,
2030 _("Coordinate expression contains floating point number '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains floating point number '%s' which could not be parsed"
))
,
2031 num_str);
2032 g_free (num_str);
2033 return FALSE(0);
2034 }
2035 }
2036 else
2037 {
2038 next->type = POS_TOKEN_INT;
2039 next->d.i.val = strtol (num_str, &end, 10);
2040 if (end == num_str)
2041 {
2042 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2043 META_THEME_ERROR_FAILED,
2044 _("Coordinate expression contains integer '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains integer '%s' which could not be parsed"
))
,
2045 num_str);
2046 g_free (num_str);
2047 return FALSE(0);
2048 }
2049 }
2050
2051 g_free (num_str);
2052
2053 g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE)do { if (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 2053
, ((const char*) (__func__)), "next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE"
); } while (0)
;
2054
2055 return TRUE(!(0));
2056}
2057
2058/**
2059 * Whether a variable can validly appear as part of the name of a variable.
2060 */
2061#define IS_VARIABLE_CHAR(c)(((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) ||
(c) == '_')
(g_ascii_isalpha ((c))((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) || (c) == '_')
2062
2063#if 0
2064static void
2065debug_print_tokens (PosToken *tokens,
2066 int n_tokens)
2067{
2068 int i;
2069
2070 for (i = 0; i < n_tokens; i++)
2071 {
2072 PosToken *t = &tokens[i];
2073
2074 g_print (" ");
2075
2076 switch (t->type)
2077 {
2078 case POS_TOKEN_INT:
2079 g_print ("\"%d\"", t->d.i.val);
2080 break;
2081 case POS_TOKEN_DOUBLE:
2082 g_print ("\"%g\"", t->d.d.val);
2083 break;
2084 case POS_TOKEN_OPEN_PAREN:
2085 g_print ("\"(\"");
2086 break;
2087 case POS_TOKEN_CLOSE_PAREN:
2088 g_print ("\")\"");
2089 break;
2090 case POS_TOKEN_VARIABLE:
2091 g_print ("\"%s\"", t->d.v.name);
2092 break;
2093 case POS_TOKEN_OPERATOR:
2094 g_print ("\"%s\"", op_name (t->d.o.op));
2095 break;
2096 }
2097 }
2098
2099 g_print ("\n");
2100}
2101#endif
2102
2103/**
2104 * Tokenises an expression.
2105 *
2106 * \param expr The expression
2107 * \param[out] tokens_p The resulting tokens
2108 * \param[out] n_tokens_p The number of resulting tokens
2109 * \param[out] err set to the problem if there was a problem
2110 *
2111 * \return True if the expression was successfully tokenised; false otherwise.
2112 *
2113 * \ingroup tokenizer
2114 */
2115static gboolean
2116pos_tokenize (const char *expr,
2117 PosToken **tokens_p,
2118 int *n_tokens_p,
2119 GError **err)
2120{
2121 PosToken *tokens;
2122 int n_tokens;
2123 int allocated;
2124 const char *p;
2125
2126 *tokens_p = NULL((void*)0);
2127 *n_tokens_p = 0;
2128
2129 allocated = 3;
2130 n_tokens = 0;
2131 tokens = g_new (PosToken, allocated)((PosToken *) g_malloc_n ((allocated), sizeof (PosToken)));
2132
2133 p = expr;
2134 while (*p)
2135 {
2136 PosToken *next;
2137 int len;
2138
2139 if (n_tokens == allocated)
2140 {
2141 allocated *= 2;
2142 tokens = g_renew (PosToken, tokens, allocated)((PosToken *) g_realloc_n (tokens, (allocated), sizeof (PosToken
)))
;
2143 }
2144
2145 next = &tokens[n_tokens];
2146
2147 switch (*p)
2148 {
2149 case '*':
2150 case '/':
2151 case '+':
2152 case '-': /* negative numbers aren't allowed so this is easy */
2153 case '%':
2154 case '`':
2155 next->type = POS_TOKEN_OPERATOR;
2156 next->d.o.op = op_from_string (p, &len);
2157 if (next->d.o.op != POS_OP_NONE)
2158 {
2159 ++n_tokens;
2160 p = p + (len - 1); /* -1 since we ++p later */
2161 }
2162 else
2163 {
2164 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2165 META_THEME_ERROR_FAILED,
2166 _("Coordinate expression contained unknown operator at the start of this text: \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression contained unknown operator at the start of this text: \"%s\""
))
,
2167 p);
2168
2169 goto error;
2170 }
2171 break;
2172
2173 case '(':
2174 next->type = POS_TOKEN_OPEN_PAREN;
2175 ++n_tokens;
2176 break;
2177
2178 case ')':
2179 next->type = POS_TOKEN_CLOSE_PAREN;
2180 ++n_tokens;
2181 break;
2182
2183 case ' ':
2184 case '\t':
2185 case '\n':
2186 break;
2187
2188 default:
2189 if (IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2190 {
2191 /* Assume variable */
2192 const char *start = p;
2193 while (*p && IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2194 ++p;
2195 g_assert (p != start)do { if (p != start) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2195, ((const char*) (__func__)), "p != start"
); } while (0)
;
2196 next->type = POS_TOKEN_VARIABLE;
2197 next->d.v.name = g_strndup (start, p - start);
2198 ++n_tokens;
2199 --p; /* since we ++p again at the end of while loop */
2200 }
2201 else
2202 {
2203 /* Assume number */
2204 const char *end;
2205
2206 if (!parse_number (p, &end, next, err))
2207 goto error;
2208
2209 ++n_tokens;
2210 p = end - 1; /* -1 since we ++p again at the end of while loop */
2211 }
2212
2213 break;
2214 }
2215
2216 ++p;
2217 }
2218
2219 if (n_tokens == 0)
2220 {
2221 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2222 META_THEME_ERROR_FAILED,
2223 _("Coordinate expression was empty or not understood")((char *) g_dgettext ("marco", "Coordinate expression was empty or not understood"
))
);
2224
2225 goto error;
2226 }
2227
2228 *tokens_p = tokens;
2229 *n_tokens_p = n_tokens;
2230
2231 return TRUE(!(0));
2232
2233 error:
2234 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2234, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2235
2236 free_tokens (tokens, n_tokens);
2237 return FALSE(0);
2238}
2239
2240/**
2241 * The type of a PosExpr: either integer, double, or an operation.
2242 * \ingroup parser
2243 */
2244typedef enum
2245{
2246 POS_EXPR_INT,
2247 POS_EXPR_DOUBLE,
2248 POS_EXPR_OPERATOR
2249} PosExprType;
2250
2251/**
2252 * Type and value of an expression in a parsed sequence. We don't
2253 * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR,
2254 * the arguments of the operator will be in the array positions
2255 * immediately preceding and following this operator; they cannot
2256 * themselves be operators.
2257 *
2258 * \bug operator is char; it should really be of PosOperatorType.
2259 * \ingroup parser
2260 */
2261typedef struct
2262{
2263 PosExprType type;
2264 union
2265 {
2266 double double_val;
2267 int int_val;
2268 char operator;
2269 } d;
2270} PosExpr;
2271
2272#if 0
2273static void
2274debug_print_exprs (PosExpr *exprs,
2275 int n_exprs)
2276{
2277 int i;
2278
2279 for (i = 0; i < n_exprs; i++)
2280 {
2281 switch (exprs[i].type)
2282 {
2283 case POS_EXPR_INT:
2284 g_print (" %d", exprs[i].d.int_val);
2285 break;
2286 case POS_EXPR_DOUBLE:
2287 g_print (" %g", exprs[i].d.double_val);
2288 break;
2289 case POS_EXPR_OPERATOR:
2290 g_print (" %s", op_name (exprs[i].d.operator));
2291 break;
2292 }
2293 }
2294 g_print ("\n");
2295}
2296#endif
2297
2298static gboolean
2299do_operation (PosExpr *a,
2300 PosExpr *b,
2301 PosOperatorType op,
2302 GError **err)
2303{
2304 /* Promote types to double if required */
2305 if (a->type == POS_EXPR_DOUBLE ||
2306 b->type == POS_EXPR_DOUBLE)
2307 {
2308 if (a->type != POS_EXPR_DOUBLE)
2309 {
2310 a->type = POS_EXPR_DOUBLE;
2311 a->d.double_val = a->d.int_val;
2312 }
2313 if (b->type != POS_EXPR_DOUBLE)
2314 {
2315 b->type = POS_EXPR_DOUBLE;
2316 b->d.double_val = b->d.int_val;
2317 }
2318 }
2319
2320 g_assert (a->type == b->type)do { if (a->type == b->type) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2320, ((const char*) (__func__)), "a->type == b->type"
); } while (0)
;
2321
2322 if (a->type == POS_EXPR_INT)
2323 {
2324 switch (op)
2325 {
2326 case POS_OP_MULTIPLY:
2327 a->d.int_val = a->d.int_val * b->d.int_val;
2328 break;
2329 case POS_OP_DIVIDE:
2330 if (b->d.int_val == 0)
2331 {
2332 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2333 META_THEME_ERROR_DIVIDE_BY_ZERO,
2334 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2335 return FALSE(0);
2336 }
2337 a->d.int_val = a->d.int_val / b->d.int_val;
2338 break;
2339 case POS_OP_MOD:
2340 if (b->d.int_val == 0)
2341 {
2342 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2343 META_THEME_ERROR_DIVIDE_BY_ZERO,
2344 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2345 return FALSE(0);
2346 }
2347 a->d.int_val = a->d.int_val % b->d.int_val;
2348 break;
2349 case POS_OP_ADD:
2350 a->d.int_val = a->d.int_val + b->d.int_val;
2351 break;
2352 case POS_OP_SUBTRACT:
2353 a->d.int_val = a->d.int_val - b->d.int_val;
2354 break;
2355 case POS_OP_MAX:
2356 a->d.int_val = MAX (a->d.int_val, b->d.int_val)(((a->d.int_val) > (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2357 break;
2358 case POS_OP_MIN:
2359 a->d.int_val = MIN (a->d.int_val, b->d.int_val)(((a->d.int_val) < (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2360 break;
2361 case POS_OP_NONE:
2362 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2362, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2363 break;
2364 }
2365 }
2366 else if (a->type == POS_EXPR_DOUBLE)
2367 {
2368 switch (op)
2369 {
2370 case POS_OP_MULTIPLY:
2371 a->d.double_val = a->d.double_val * b->d.double_val;
2372 break;
2373 case POS_OP_DIVIDE:
2374 if (b->d.double_val == 0.0)
2375 {
2376 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2377 META_THEME_ERROR_DIVIDE_BY_ZERO,
2378 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2379 return FALSE(0);
2380 }
2381 a->d.double_val = a->d.double_val / b->d.double_val;
2382 break;
2383 case POS_OP_MOD:
2384 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2385 META_THEME_ERROR_MOD_ON_FLOAT,
2386 _("Coordinate expression tries to use mod operator on a floating-point number")((char *) g_dgettext ("marco", "Coordinate expression tries to use mod operator on a floating-point number"
))
);
2387 return FALSE(0);
2388 case POS_OP_ADD:
2389 a->d.double_val = a->d.double_val + b->d.double_val;
2390 break;
2391 case POS_OP_SUBTRACT:
2392 a->d.double_val = a->d.double_val - b->d.double_val;
2393 break;
2394 case POS_OP_MAX:
2395 a->d.double_val = MAX (a->d.double_val, b->d.double_val)(((a->d.double_val) > (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2396 break;
2397 case POS_OP_MIN:
2398 a->d.double_val = MIN (a->d.double_val, b->d.double_val)(((a->d.double_val) < (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2399 break;
2400 case POS_OP_NONE:
2401 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2401, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2402 break;
2403 }
2404 }
2405 else
2406 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2406, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2407
2408 return TRUE(!(0));
2409}
2410
2411static gboolean
2412do_operations (PosExpr *exprs,
2413 int *n_exprs,
2414 int precedence,
2415 GError **err)
2416{
2417 int i;
2418
2419#if 0
2420 g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs);
2421 debug_print_exprs (exprs, *n_exprs);
2422#endif
2423
2424 i = 1;
2425 while (i < *n_exprs)
2426 {
2427 gboolean compress;
2428
2429 /* exprs[i-1] first operand
2430 * exprs[i] operator
2431 * exprs[i+1] second operand
2432 *
2433 * we replace first operand with result of mul/div/mod,
2434 * or skip over operator and second operand if we have
2435 * an add/subtract
2436 */
2437
2438 if (exprs[i-1].type == POS_EXPR_OPERATOR)
2439 {
2440 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2441 META_THEME_ERROR_FAILED,
2442 _("Coordinate expression has an operator \"%s\" where an operand was expected")((char *) g_dgettext ("marco", "Coordinate expression has an operator \"%s\" where an operand was expected"
))
,
2443 op_name (exprs[i-1].d.operator));
2444 return FALSE(0);
2445 }
2446
2447 if (exprs[i].type != POS_EXPR_OPERATOR)
2448 {
2449 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2450 META_THEME_ERROR_FAILED,
2451 _("Coordinate expression had an operand where an operator was expected")((char *) g_dgettext ("marco", "Coordinate expression had an operand where an operator was expected"
))
);
2452 return FALSE(0);
2453 }
2454
2455 if (i == (*n_exprs - 1))
2456 {
2457 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2458 META_THEME_ERROR_FAILED,
2459 _("Coordinate expression ended with an operator instead of an operand")((char *) g_dgettext ("marco", "Coordinate expression ended with an operator instead of an operand"
))
);
2460 return FALSE(0);
2461 }
2462
2463 g_assert ((i+1) < *n_exprs)do { if ((i+1) < *n_exprs) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2463, ((const char*) (__func__)), "(i+1) < *n_exprs"
); } while (0)
;
2464
2465 if (exprs[i+1].type == POS_EXPR_OPERATOR)
2466 {
2467 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2468 META_THEME_ERROR_FAILED,
2469 _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between")((char *) g_dgettext ("marco", "Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"
))
,
2470 exprs[i+1].d.operator,
2471 exprs[i].d.operator);
2472 return FALSE(0);
2473 }
2474
2475 compress = FALSE(0);
2476
2477 switch (precedence)
2478 {
2479 case 2:
2480 switch (exprs[i].d.operator)
2481 {
2482 case POS_OP_DIVIDE:
2483 case POS_OP_MOD:
2484 case POS_OP_MULTIPLY:
2485 compress = TRUE(!(0));
2486 if (!do_operation (&exprs[i-1], &exprs[i+1],
2487 exprs[i].d.operator,
2488 err))
2489 return FALSE(0);
2490 break;
2491 }
2492 break;
2493 case 1:
2494 switch (exprs[i].d.operator)
2495 {
2496 case POS_OP_ADD:
2497 case POS_OP_SUBTRACT:
2498 compress = TRUE(!(0));
2499 if (!do_operation (&exprs[i-1], &exprs[i+1],
2500 exprs[i].d.operator,
2501 err))
2502 return FALSE(0);
2503 break;
2504 }
2505 break;
2506 /* I have no rationale at all for making these low-precedence */
2507 case 0:
2508 switch (exprs[i].d.operator)
2509 {
2510 case POS_OP_MAX:
2511 case POS_OP_MIN:
2512 compress = TRUE(!(0));
2513 if (!do_operation (&exprs[i-1], &exprs[i+1],
2514 exprs[i].d.operator,
2515 err))
2516 return FALSE(0);
2517 break;
2518 }
2519 break;
2520 }
2521
2522 if (compress)
2523 {
2524 /* exprs[i-1] first operand (now result)
2525 * exprs[i] operator
2526 * exprs[i+1] second operand
2527 * exprs[i+2] new operator
2528 *
2529 * we move new operator just after first operand
2530 */
2531 if ((i+2) < *n_exprs)
2532 {
2533 memmove (&exprs[i], &exprs[i+2],
2534 sizeof (PosExpr) * (*n_exprs - i - 2));
2535 }
2536
2537 *n_exprs -= 2;
2538 }
2539 else
2540 {
2541 /* Skip operator and next operand */
2542 i += 2;
2543 }
2544 }
2545
2546 return TRUE(!(0));
2547}
2548
2549/**
2550 * There is a predefined set of variables which can appear in an expression.
2551 * Here we take a token representing a variable, and return the current value
2552 * of that variable in a particular environment.
2553 * (The value is always an integer.)
2554 *
2555 * There are supposedly some circumstances in which this function can be
2556 * called from outside Marco, in which case env->theme will be NULL, and
2557 * therefore we can't use it to find out quark values, so we do the comparison
2558 * using strcmp, which is slower.
2559 *
2560 * \param t The token representing a variable
2561 * \param[out] result The value of that variable; not set if the token did
2562 * not represent a known variable
2563 * \param env The environment within which t should be evaluated
2564 * \param[out] err set to the problem if there was a problem
2565 *
2566 * \return true if we found the variable asked for, false if we didn't
2567 *
2568 * \bug shouldn't t be const?
2569 * \bug we should perhaps consider some sort of lookup arrangement into an
2570 * array; also, the duplication of code is unlovely; perhaps using glib
2571 * string hashes instead of quarks would fix both problems?
2572 * \ingroup parser
2573 */
2574static gboolean
2575pos_eval_get_variable (PosToken *t,
2576 int *result,
2577 const MetaPositionExprEnv *env,
2578 GError **err)
2579{
2580 if (env->theme)
2581 {
2582 if (t->d.v.name_quark == env->theme->quark_width)
2583 *result = env->rect.width;
2584 else if (t->d.v.name_quark == env->theme->quark_height)
2585 *result = env->rect.height;
2586 else if (env->object_width >= 0 &&
2587 t->d.v.name_quark == env->theme->quark_object_width)
2588 *result = env->object_width;
2589 else if (env->object_height >= 0 &&
2590 t->d.v.name_quark == env->theme->quark_object_height)
2591 *result = env->object_height;
2592 else if (t->d.v.name_quark == env->theme->quark_left_width)
2593 *result = env->left_width;
2594 else if (t->d.v.name_quark == env->theme->quark_right_width)
2595 *result = env->right_width;
2596 else if (t->d.v.name_quark == env->theme->quark_top_height)
2597 *result = env->top_height;
2598 else if (t->d.v.name_quark == env->theme->quark_bottom_height)
2599 *result = env->bottom_height;
2600 else if (t->d.v.name_quark == env->theme->quark_mini_icon_width)
2601 *result = env->mini_icon_width;
2602 else if (t->d.v.name_quark == env->theme->quark_mini_icon_height)
2603 *result = env->mini_icon_height;
2604 else if (t->d.v.name_quark == env->theme->quark_icon_width)
2605 *result = env->icon_width;
2606 else if (t->d.v.name_quark == env->theme->quark_icon_height)
2607 *result = env->icon_height;
2608 else if (t->d.v.name_quark == env->theme->quark_title_width)
2609 *result = env->title_width;
2610 else if (t->d.v.name_quark == env->theme->quark_title_height)
2611 *result = env->title_height;
2612 else if (t->d.v.name_quark == env->theme->quark_frame_x_center)
2613 *result = env->frame_x_center;
2614 else if (t->d.v.name_quark == env->theme->quark_frame_y_center)
2615 *result = env->frame_y_center;
2616 else
2617 {
2618 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2619 META_THEME_ERROR_UNKNOWN_VARIABLE,
2620 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2621 t->d.v.name);
2622 return FALSE(0);
2623 }
2624 }
2625 else
2626 {
2627 if (strcmp (t->d.v.name, "width") == 0)
2628 *result = env->rect.width;
2629 else if (strcmp (t->d.v.name, "height") == 0)
2630 *result = env->rect.height;
2631 else if (env->object_width >= 0 &&
2632 strcmp (t->d.v.name, "object_width") == 0)
2633 *result = env->object_width;
2634 else if (env->object_height >= 0 &&
2635 strcmp (t->d.v.name, "object_height") == 0)
2636 *result = env->object_height;
2637 else if (strcmp (t->d.v.name, "left_width") == 0)
2638 *result = env->left_width;
2639 else if (strcmp (t->d.v.name, "right_width") == 0)
2640 *result = env->right_width;
2641 else if (strcmp (t->d.v.name, "top_height") == 0)
2642 *result = env->top_height;
2643 else if (strcmp (t->d.v.name, "bottom_height") == 0)
2644 *result = env->bottom_height;
2645 else if (strcmp (t->d.v.name, "mini_icon_width") == 0)
2646 *result = env->mini_icon_width;
2647 else if (strcmp (t->d.v.name, "mini_icon_height") == 0)
2648 *result = env->mini_icon_height;
2649 else if (strcmp (t->d.v.name, "icon_width") == 0)
2650 *result = env->icon_width;
2651 else if (strcmp (t->d.v.name, "icon_height") == 0)
2652 *result = env->icon_height;
2653 else if (strcmp (t->d.v.name, "title_width") == 0)
2654 *result = env->title_width;
2655 else if (strcmp (t->d.v.name, "title_height") == 0)
2656 *result = env->title_height;
2657 else if (strcmp (t->d.v.name, "frame_x_center") == 0)
2658 *result = env->frame_x_center;
2659 else if (strcmp (t->d.v.name, "frame_y_center") == 0)
2660 *result = env->frame_y_center;
2661 else
2662 {
2663 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2664 META_THEME_ERROR_UNKNOWN_VARIABLE,
2665 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2666 t->d.v.name);
2667 return FALSE(0);
2668 }
2669 }
2670
2671 return TRUE(!(0));
2672}
2673
2674/**
2675 * Evaluates a sequence of tokens within a particular environment context,
2676 * and returns the current value. May recur if parantheses are found.
2677 *
2678 * \param tokens A list of tokens to evaluate.
2679 * \param n_tokens How many tokens are in the list.
2680 * \param env The environment context in which to evaluate the expression.
2681 * \param[out] result The current value of the expression
2682 *
2683 * \bug Yes, we really do reparse the expression every time it's evaluated.
2684 * We should keep the parse tree around all the time and just
2685 * run the new values through it.
2686 * \ingroup parser
2687 */
2688static gboolean
2689pos_eval_helper (PosToken *tokens,
2690 int n_tokens,
2691 const MetaPositionExprEnv *env,
2692 PosExpr *result,
2693 GError **err)
2694{
2695 /* Lazy-ass hardcoded limit on number of terms in expression */
2696#define MAX_EXPRS32 32
2697 int paren_level;
2698 int first_paren;
2699 int i;
2700 PosExpr exprs[MAX_EXPRS32];
2701 int n_exprs;
2702 int precedence;
2703
2704 /* Our first goal is to get a list of PosExpr, essentially
2705 * substituting variables and handling parentheses.
2706 */
2707
2708 first_paren = 0;
2709 paren_level = 0;
2710 n_exprs = 0;
2711 for (i = 0; i < n_tokens; i++)
2712 {
2713 PosToken *t = &tokens[i];
2714
2715 if (n_exprs >= MAX_EXPRS32)
2716 {
2717 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2718 META_THEME_ERROR_FAILED,
2719 _("Coordinate expression parser overflowed its buffer.")((char *) g_dgettext ("marco", "Coordinate expression parser overflowed its buffer."
))
);
2720 return FALSE(0);
2721 }
2722
2723 if (paren_level == 0)
2724 {
2725 switch (t->type)
2726 {
2727 case POS_TOKEN_INT:
2728 exprs[n_exprs].type = POS_EXPR_INT;
2729 exprs[n_exprs].d.int_val = t->d.i.val;
2730 ++n_exprs;
2731 break;
2732
2733 case POS_TOKEN_DOUBLE:
2734 exprs[n_exprs].type = POS_EXPR_DOUBLE;
2735 exprs[n_exprs].d.double_val = t->d.d.val;
2736 ++n_exprs;
2737 break;
2738
2739 case POS_TOKEN_OPEN_PAREN:
2740 ++paren_level;
2741 if (paren_level == 1)
2742 first_paren = i;
2743 break;
2744
2745 case POS_TOKEN_CLOSE_PAREN:
2746 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2747 META_THEME_ERROR_BAD_PARENS,
2748 _("Coordinate expression had a close parenthesis with no open parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had a close parenthesis with no open parenthesis"
))
);
2749 return FALSE(0);
2750
2751 case POS_TOKEN_VARIABLE:
2752 exprs[n_exprs].type = POS_EXPR_INT;
2753
2754 /* FIXME we should just dump all this crap
2755 * in a hash, maybe keep width/height out
2756 * for optimization purposes
2757 */
2758 if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err))
2759 return FALSE(0);
2760
2761 ++n_exprs;
2762 break;
2763
2764 case POS_TOKEN_OPERATOR:
2765 exprs[n_exprs].type = POS_EXPR_OPERATOR;
2766 exprs[n_exprs].d.operator = t->d.o.op;
2767 ++n_exprs;
2768 break;
2769 }
2770 }
2771 else
2772 {
2773 g_assert (paren_level > 0)do { if (paren_level > 0) ; else g_assertion_message_expr (
"marco", "ui/theme.c", 2773, ((const char*) (__func__)), "paren_level > 0"
); } while (0)
;
2774
2775 switch (t->type)
2776 {
2777 case POS_TOKEN_INT:
2778 case POS_TOKEN_DOUBLE:
2779 case POS_TOKEN_VARIABLE:
2780 case POS_TOKEN_OPERATOR:
2781 break;
2782
2783 case POS_TOKEN_OPEN_PAREN:
2784 ++paren_level;
2785 break;
2786
2787 case POS_TOKEN_CLOSE_PAREN:
2788 if (paren_level == 1)
2789 {
2790 /* We closed a toplevel paren group, so recurse */
2791 if (!pos_eval_helper (&tokens[first_paren+1],
2792 i - first_paren - 1,
2793 env,
2794 &exprs[n_exprs],
2795 err))
2796 return FALSE(0);
2797
2798 ++n_exprs;
2799 }
2800
2801 --paren_level;
2802 break;
2803
2804 }
2805 }
2806 }
2807
2808 if (paren_level > 0)
2809 {
2810 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2811 META_THEME_ERROR_BAD_PARENS,
2812 _("Coordinate expression had an open parenthesis with no close parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had an open parenthesis with no close parenthesis"
))
);
2813 return FALSE(0);
2814 }
2815
2816 /* Now we have no parens and no vars; so we just do all the multiplies
2817 * and divides, then all the add and subtract.
2818 */
2819 if (n_exprs == 0)
2820 {
2821 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2822 META_THEME_ERROR_FAILED,
2823 _("Coordinate expression doesn't seem to have any operators or operands")((char *) g_dgettext ("marco", "Coordinate expression doesn't seem to have any operators or operands"
))
);
2824 return FALSE(0);
2825 }
2826
2827 /* precedence 1 ops */
2828 precedence = 2;
2829 while (precedence >= 0)
2830 {
2831 if (!do_operations (exprs, &n_exprs, precedence, err))
2832 return FALSE(0);
2833 --precedence;
2834 }
2835
2836 g_assert (n_exprs == 1)do { if (n_exprs == 1) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2836, ((const char*) (__func__)), "n_exprs == 1"
); } while (0)
;
2837
2838 *result = *exprs;
2839
2840 return TRUE(!(0));
2841}
2842
2843/*
2844 * expr = int | double | expr * expr | expr / expr |
2845 * expr + expr | expr - expr | (expr)
2846 *
2847 * so very not worth fooling with bison, yet so very painful by hand.
2848 */
2849/**
2850 * Evaluates an expression.
2851 *
2852 * \param spec The expression to evaluate.
2853 * \param env The environment context to evaluate the expression in.
2854 * \param[out] val_p The integer value of the expression; if the expression
2855 * is of type float, this will be rounded. If we return
2856 * FALSE because the expression is invalid, this will be
2857 * zero.
2858 * \param[out] err The error, if anything went wrong.
2859 *
2860 * \return True if we evaluated the expression successfully; false otherwise.
2861 *
2862 * \bug Shouldn't spec be const?
2863 * \ingroup parser
2864 */
2865static gboolean
2866pos_eval (MetaDrawSpec *spec,
2867 const MetaPositionExprEnv *env,
2868 int *val_p,
2869 GError **err)
2870{
2871 PosExpr expr;
2872
2873 *val_p = 0;
2874
2875 if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err))
2876 {
2877 switch (expr.type)
2878 {
2879 case POS_EXPR_INT:
2880 *val_p = expr.d.int_val;
2881 break;
2882 case POS_EXPR_DOUBLE:
2883 *val_p = (int) expr.d.double_val;
2884 break;
2885 case POS_EXPR_OPERATOR:
2886 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2886, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2887 break;
2888 }
2889 return TRUE(!(0));
2890 }
2891 else
2892 {
2893 return FALSE(0);
2894 }
2895}
2896
2897/* We always return both X and Y, but only one will be meaningful in
2898 * most contexts.
2899 */
2900
2901gboolean
2902meta_parse_position_expression (MetaDrawSpec *spec,
2903 const MetaPositionExprEnv *env,
2904 int *x_return,
2905 int *y_return,
2906 GError **err)
2907{
2908 /* All positions are in a coordinate system with x, y at the origin.
2909 * The expression can have -, +, *, / as operators, floating point
2910 * or integer constants, and the variables "width" and "height" and
2911 * optionally "object_width" and object_height". Negative numbers
2912 * aren't allowed.
2913 */
2914 int val;
2915
2916 if (spec->constant)
2917 val = spec->value;
2918 else
2919 {
2920 if (!pos_eval (spec, env, &spec->value, err))
2921 {
2922 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2922, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2923 return FALSE(0);
2924 }
2925
2926 val = spec->value;
2927 }
2928
2929 if (x_return)
2930 *x_return = env->rect.x + val;
2931 if (y_return)
2932 *y_return = env->rect.y + val;
2933
2934 return TRUE(!(0));
2935}
2936
2937gboolean
2938meta_parse_size_expression (MetaDrawSpec *spec,
2939 const MetaPositionExprEnv *env,
2940 int *val_return,
2941 GError **err)
2942{
2943 int val;
2944
2945 if (spec->constant)
2946 val = spec->value;
2947 else
2948 {
2949 if (!pos_eval (spec, env, &spec->value, err))
2950 {
2951 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2951, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2952 return FALSE(0);
2953 }
2954
2955 val = spec->value;
2956 }
2957
2958 if (val_return)
2959 *val_return = MAX (val, 1)(((val) > (1)) ? (val) : (1)); /* require that sizes be at least 1x1 */
2960
2961 return TRUE(!(0));
2962}
2963
2964/* To do this we tokenize, replace variable tokens
2965 * that are constants, then reassemble. The purpose
2966 * here is to optimize expressions so we don't do hash
2967 * lookups to eval them. Obviously it's a tradeoff that
2968 * slows down theme load times.
2969 */
2970gboolean
2971meta_theme_replace_constants (MetaTheme *theme,
2972 PosToken *tokens,
2973 int n_tokens,
2974 GError **err)
2975{
2976 int i;
2977 double dval;
2978 int ival;
2979 gboolean is_constant = TRUE(!(0));
2980
2981 /* Loop through tokenized string looking for variables to replace */
2982 for (i = 0; i < n_tokens; i++)
2983 {
2984 PosToken *t = &tokens[i];
2985
2986 if (t->type == POS_TOKEN_VARIABLE)
2987 {
2988 if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival))
2989 {
2990 g_free (t->d.v.name);
2991 t->type = POS_TOKEN_INT;
2992 t->d.i.val = ival;
2993 }
2994 else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval))
2995 {
2996 g_free (t->d.v.name);
2997 t->type = POS_TOKEN_DOUBLE;
2998 t->d.d.val = dval;
2999 }
3000 else
3001 {
3002 /* If we've found a variable that cannot be replaced then the
3003 expression is not a constant expression and we want to
3004 replace it with a GQuark */
3005
3006 t->d.v.name_quark = g_quark_from_string (t->d.v.name);
3007 is_constant = FALSE(0);
3008 }
3009 }
3010 }
3011
3012 return is_constant;
3013}
3014
3015static int
3016parse_x_position_unchecked (MetaDrawSpec *spec,
3017 const MetaPositionExprEnv *env)
3018{
3019 int retval;
3020 GError *error;
3021
3022 retval = 0;
3023 error = NULL((void*)0);
3024 if (!meta_parse_position_expression (spec, env, &retval, NULL((void*)0), &error))
3025 {
3026 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3027 error->message);
3028
3029 g_error_free (error);
3030 }
3031
3032 return retval;
3033}
3034
3035static int
3036parse_y_position_unchecked (MetaDrawSpec *spec,
3037 const MetaPositionExprEnv *env)
3038{
3039 int retval;
3040 GError *error;
3041
3042 retval = 0;
3043 error = NULL((void*)0);
3044 if (!meta_parse_position_expression (spec, env, NULL((void*)0), &retval, &error))
3045 {
3046 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3047 error->message);
3048
3049 g_error_free (error);
3050 }
3051
3052 return retval;
3053}
3054
3055static int
3056parse_size_unchecked (MetaDrawSpec *spec,
3057 MetaPositionExprEnv *env)
3058{
3059 int retval;
3060 GError *error;
3061
3062 retval = 0;
3063 error = NULL((void*)0);
3064 if (!meta_parse_size_expression (spec, env, &retval, &error))
3065 {
3066 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3067 error->message);
3068
3069 g_error_free (error);
3070 }
3071
3072 return retval;
3073}
3074
3075void
3076meta_draw_spec_free (MetaDrawSpec *spec)
3077{
3078 if (!spec) return;
3079 free_tokens (spec->tokens, spec->n_tokens);
3080 g_slice_free (MetaDrawSpec, spec)do { if (1) g_slice_free1 (sizeof (MetaDrawSpec), (spec)); else
(void) ((MetaDrawSpec*) 0 == (spec)); } while (0)
;
3081}
3082
3083MetaDrawSpec *
3084meta_draw_spec_new (MetaTheme *theme,
3085 const char *expr,
3086 GError **error)
3087{
3088 MetaDrawSpec *spec;
3089
3090 spec = g_slice_new0 (MetaDrawSpec)((MetaDrawSpec*) g_slice_alloc0 (sizeof (MetaDrawSpec)));
3091
3092 pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL((void*)0));
3093
3094 spec->constant = meta_theme_replace_constants (theme, spec->tokens,
3095 spec->n_tokens, NULL((void*)0));
3096 if (spec->constant)
3097 {
3098 if (!pos_eval (spec, NULL((void*)0), &spec->value, error))
3099 {
3100 meta_draw_spec_free (spec);
3101 return NULL((void*)0);
3102 }
3103 }
3104
3105 return spec;
3106}
3107
3108MetaDrawOp*
3109meta_draw_op_new (MetaDrawType type)
3110{
3111 MetaDrawOp *op;
3112 MetaDrawOp dummy;
3113 int size;
3114
3115 size = G_STRUCT_OFFSET (MetaDrawOp, data)((glong) __builtin_offsetof(MetaDrawOp, data));
3116
3117 switch (type)
3118 {
3119 case META_DRAW_LINE:
3120 size += sizeof (dummy.data.line);
3121 break;
3122
3123 case META_DRAW_RECTANGLE:
3124 size += sizeof (dummy.data.rectangle);
3125 break;
3126
3127 case META_DRAW_ARC:
3128 size += sizeof (dummy.data.arc);
3129 break;
3130
3131 case META_DRAW_CLIP:
3132 size += sizeof (dummy.data.clip);
3133 break;
3134
3135 case META_DRAW_TINT:
3136 size += sizeof (dummy.data.tint);
3137 break;
3138
3139 case META_DRAW_GRADIENT:
3140 size += sizeof (dummy.data.gradient);
3141 break;
3142
3143 case META_DRAW_IMAGE:
3144 size += sizeof (dummy.data.image);
3145 break;
3146
3147 case META_DRAW_GTK_ARROW:
3148 size += sizeof (dummy.data.gtk_arrow);
3149 break;
3150
3151 case META_DRAW_GTK_BOX:
3152 size += sizeof (dummy.data.gtk_box);
3153 break;
3154
3155 case META_DRAW_GTK_VLINE:
3156 size += sizeof (dummy.data.gtk_vline);
3157 break;
3158
3159 case META_DRAW_ICON:
3160 size += sizeof (dummy.data.icon);
3161 break;
3162
3163 case META_DRAW_TITLE:
3164 size += sizeof (dummy.data.title);
3165 break;
3166 case META_DRAW_OP_LIST:
3167 size += sizeof (dummy.data.op_list);
3168 break;
3169 case META_DRAW_TILE:
3170 size += sizeof (dummy.data.tile);
3171 break;
3172 }
3173
3174 op = g_malloc0 (size);
3175
3176 op->type = type;
3177
3178 return op;
3179}
3180
3181void
3182meta_draw_op_free (MetaDrawOp *op)
3183{
3184 g_return_if_fail (op != NULL)do { if ((op != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op != NULL"); return;
} } while (0)
;
3185
3186 switch (op->type)
3187 {
3188 case META_DRAW_LINE:
3189 if (op->data.line.color_spec)
3190 meta_color_spec_free (op->data.line.color_spec);
3191
3192 meta_draw_spec_free (op->data.line.x1);
3193 meta_draw_spec_free (op->data.line.y1);
3194 meta_draw_spec_free (op->data.line.x2);
3195 meta_draw_spec_free (op->data.line.y2);
3196 break;
3197
3198 case META_DRAW_RECTANGLE:
3199 if (op->data.rectangle.color_spec)
3200 g_free (op->data.rectangle.color_spec);
3201
3202 meta_draw_spec_free (op->data.rectangle.x);
3203 meta_draw_spec_free (op->data.rectangle.y);
3204 meta_draw_spec_free (op->data.rectangle.width);
3205 meta_draw_spec_free (op->data.rectangle.height);
3206 break;
3207
3208 case META_DRAW_ARC:
3209 if (op->data.arc.color_spec)
3210 g_free (op->data.arc.color_spec);
3211
3212 meta_draw_spec_free (op->data.arc.x);
3213 meta_draw_spec_free (op->data.arc.y);
3214 meta_draw_spec_free (op->data.arc.width);
3215 meta_draw_spec_free (op->data.arc.height);
3216 break;
3217
3218 case META_DRAW_CLIP:
3219 meta_draw_spec_free (op->data.clip.x);
3220 meta_draw_spec_free (op->data.clip.y);
3221 meta_draw_spec_free (op->data.clip.width);
3222 meta_draw_spec_free (op->data.clip.height);
3223 break;
3224
3225 case META_DRAW_TINT:
3226 if (op->data.tint.color_spec)
3227 meta_color_spec_free (op->data.tint.color_spec);
3228
3229 if (op->data.tint.alpha_spec)
3230 meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
3231
3232 meta_draw_spec_free (op->data.tint.x);
3233 meta_draw_spec_free (op->data.tint.y);
3234 meta_draw_spec_free (op->data.tint.width);
3235 meta_draw_spec_free (op->data.tint.height);
3236 break;
3237
3238 case META_DRAW_GRADIENT:
3239 if (op->data.gradient.gradient_spec)
3240 meta_gradient_spec_free (op->data.gradient.gradient_spec);
3241
3242 if (op->data.gradient.alpha_spec)
3243 meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
3244
3245 meta_draw_spec_free (op->data.gradient.x);
3246 meta_draw_spec_free (op->data.gradient.y);
3247 meta_draw_spec_free (op->data.gradient.width);
3248 meta_draw_spec_free (op->data.gradient.height);
3249 break;
3250
3251 case META_DRAW_IMAGE:
3252 if (op->data.image.alpha_spec)
3253 meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
3254
3255 if (op->data.image.pixbuf)
3256 g_object_unref (G_OBJECT (op->data.image.pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.pixbuf)), (((GType) ((20) << (2)
)))))))
);
3257
3258 if (op->data.image.colorize_spec)
3259 meta_color_spec_free (op->data.image.colorize_spec);
3260
3261 if (op->data.image.colorize_cache_pixbuf)
3262 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3263
3264 meta_draw_spec_free (op->data.image.x);
3265 meta_draw_spec_free (op->data.image.y);
3266 meta_draw_spec_free (op->data.image.width);
3267 meta_draw_spec_free (op->data.image.height);
3268 break;
3269
3270 case META_DRAW_GTK_ARROW:
3271 meta_draw_spec_free (op->data.gtk_arrow.x);
3272 meta_draw_spec_free (op->data.gtk_arrow.y);
3273 meta_draw_spec_free (op->data.gtk_arrow.width);
3274 meta_draw_spec_free (op->data.gtk_arrow.height);
3275 break;
3276
3277 case META_DRAW_GTK_BOX:
3278 meta_draw_spec_free (op->data.gtk_box.x);
3279 meta_draw_spec_free (op->data.gtk_box.y);
3280 meta_draw_spec_free (op->data.gtk_box.width);
3281 meta_draw_spec_free (op->data.gtk_box.height);
3282 break;
3283
3284 case META_DRAW_GTK_VLINE:
3285 meta_draw_spec_free (op->data.gtk_vline.x);
3286 meta_draw_spec_free (op->data.gtk_vline.y1);
3287 meta_draw_spec_free (op->data.gtk_vline.y2);
3288 break;
3289
3290 case META_DRAW_ICON:
3291 if (op->data.icon.alpha_spec)
3292 meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
3293
3294 meta_draw_spec_free (op->data.icon.x);
3295 meta_draw_spec_free (op->data.icon.y);
3296 meta_draw_spec_free (op->data.icon.width);
3297 meta_draw_spec_free (op->data.icon.height);
3298 break;
3299
3300 case META_DRAW_TITLE:
3301 if (op->data.title.color_spec)
3302 meta_color_spec_free (op->data.title.color_spec);
3303
3304 meta_draw_spec_free (op->data.title.x);
3305 meta_draw_spec_free (op->data.title.y);
3306 if (op->data.title.ellipsize_width)
3307 meta_draw_spec_free (op->data.title.ellipsize_width);
3308 break;
3309
3310 case META_DRAW_OP_LIST:
3311 if (op->data.op_list.op_list)
3312 meta_draw_op_list_unref (op->data.op_list.op_list);
3313
3314 meta_draw_spec_free (op->data.op_list.x);
3315 meta_draw_spec_free (op->data.op_list.y);
3316 meta_draw_spec_free (op->data.op_list.width);
3317 meta_draw_spec_free (op->data.op_list.height);
3318 break;
3319
3320 case META_DRAW_TILE:
3321 if (op->data.tile.op_list)
3322 meta_draw_op_list_unref (op->data.tile.op_list);
3323
3324 meta_draw_spec_free (op->data.tile.x);
3325 meta_draw_spec_free (op->data.tile.y);
3326 meta_draw_spec_free (op->data.tile.width);
3327 meta_draw_spec_free (op->data.tile.height);
3328 meta_draw_spec_free (op->data.tile.tile_xoffset);
3329 meta_draw_spec_free (op->data.tile.tile_yoffset);
3330 meta_draw_spec_free (op->data.tile.tile_width);
3331 meta_draw_spec_free (op->data.tile.tile_height);
3332 break;
3333 }
3334
3335 g_free (op);
3336}
3337
3338static GdkPixbuf*
3339apply_alpha (GdkPixbuf *pixbuf,
3340 MetaAlphaGradientSpec *spec,
3341 gboolean force_copy)
3342{
3343 GdkPixbuf *new_pixbuf;
3344 gboolean needs_alpha;
3345
3346 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return (((void*)0)); } } while
(0)
;
3347
3348 needs_alpha = spec && (spec->n_alphas > 1 ||
3349 spec->alphas[0] != 0xff);
3350
3351 if (!needs_alpha)
3352 return pixbuf;
3353
3354 if (!gdk_pixbuf_get_has_alpha (pixbuf))
3355 {
3356 new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE(0), 0, 0, 0);
3357 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3358 pixbuf = new_pixbuf;
3359 }
3360 else if (force_copy)
3361 {
3362 new_pixbuf = gdk_pixbuf_copy (pixbuf);
3363 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3364 pixbuf = new_pixbuf;
3365 }
3366
3367 g_assert (gdk_pixbuf_get_has_alpha (pixbuf))do { if (gdk_pixbuf_get_has_alpha (pixbuf)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 3367, ((const char*) (__func__)), "gdk_pixbuf_get_has_alpha (pixbuf)"
); } while (0)
;
3368
3369 meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
3370
3371 return pixbuf;
3372}
3373
3374static GdkPixbuf*
3375pixbuf_tile (GdkPixbuf *tile,
3376 int width,
3377 int height)
3378{
3379 GdkPixbuf *pixbuf;
3380 int tile_width;
3381 int tile_height;
3382 int i, j;
3383
3384 tile_width = gdk_pixbuf_get_width (tile);
3385 tile_height = gdk_pixbuf_get_height (tile);
3386
3387 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3388 gdk_pixbuf_get_has_alpha (tile),
3389 8, width, height);
3390
3391 i = 0;
3392 while (i < width)
3393 {
3394 j = 0;
3395 while (j < height)
3396 {
3397 int w, h;
3398
3399 w = MIN (tile_width, width - i)(((tile_width) < (width - i)) ? (tile_width) : (width - i)
)
;
3400 h = MIN (tile_height, height - j)(((tile_height) < (height - j)) ? (tile_height) : (height -
j))
;
3401
3402 gdk_pixbuf_copy_area (tile,
3403 0, 0,
3404 w, h,
3405 pixbuf,
3406 i, j);
3407
3408 j += tile_height;
3409 }
3410
3411 i += tile_width;
3412 }
3413
3414 return pixbuf;
3415}
3416
3417static GdkPixbuf *
3418replicate_rows (GdkPixbuf *src,
3419 int src_x,
3420 int src_y,
3421 int width,
3422 int height)
3423{
3424 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3425 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3426 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3427 * n_channels);
3428 unsigned char *dest_pixels;
3429 GdkPixbuf *result;
3430 unsigned int dest_rowstride;
3431 int i;
3432
3433 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3434 width, height);
3435 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3436 dest_pixels = gdk_pixbuf_get_pixels (result);
3437
3438 for (i = 0; i < height; i++)
3439 memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
3440
3441 return result;
3442}
3443
3444static GdkPixbuf *
3445replicate_cols (GdkPixbuf *src,
3446 int src_x,
3447 int src_y,
3448 int width,
3449 int height)
3450{
3451 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3452 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3453 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3454 * n_channels);
3455 unsigned char *dest_pixels;
3456 GdkPixbuf *result;
3457 unsigned int dest_rowstride;
3458 int i, j;
3459
3460 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3461 width, height);
3462 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3463 dest_pixels = gdk_pixbuf_get_pixels (result);
3464
3465 for (i = 0; i < height; i++)
3466 {
3467 unsigned char *p = dest_pixels + dest_rowstride * i;
3468 unsigned char *q = pixels + src_rowstride * i;
3469
3470 unsigned char r = *(q++);
3471 unsigned char g = *(q++);
3472 unsigned char b = *(q++);
3473
3474 if (n_channels == 4)
3475 {
3476 unsigned char a;
3477
3478 a = *(q++);
3479
3480 for (j = 0; j < width; j++)
3481 {
3482 *(p++) = r;
3483 *(p++) = g;
3484 *(p++) = b;
3485 *(p++) = a;
3486 }
3487 }
3488 else
3489 {
3490 for (j = 0; j < width; j++)
3491 {
3492 *(p++) = r;
3493 *(p++) = g;
3494 *(p++) = b;
3495 }
3496 }
3497 }
3498
3499 return result;
3500}
3501
3502static GdkPixbuf*
3503scale_and_alpha_pixbuf (GdkPixbuf *src,
3504 MetaAlphaGradientSpec *alpha_spec,
3505 MetaImageFillType fill_type,
3506 int width,
3507 int height,
3508 gboolean vertical_stripes,
3509 gboolean horizontal_stripes)
3510{
3511 GdkPixbuf *pixbuf;
3512 GdkPixbuf *temp_pixbuf;
3513
3514 pixbuf = NULL((void*)0);
3515
3516 pixbuf = src;
3517
3518 if (gdk_pixbuf_get_width (pixbuf) == width &&
3519 gdk_pixbuf_get_height (pixbuf) == height)
3520 {
3521 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
3522 }
3523 else
3524 {
3525 if (fill_type == META_IMAGE_FILL_TILE)
3526 {
3527 pixbuf = pixbuf_tile (pixbuf, width, height);
3528 }
3529 else
3530 {
3531 int src_h, src_w, dest_h, dest_w;
3532 src_h = gdk_pixbuf_get_height (src);
3533 src_w = gdk_pixbuf_get_width (src);
3534
3535 /* prefer to replicate_cols if possible, as that
3536 * is faster (no memory reads)
3537 */
3538 if (horizontal_stripes)
3539 {
3540 dest_w = gdk_pixbuf_get_width (src);
3541 dest_h = height;
3542 }
3543 else if (vertical_stripes)
3544 {
3545 dest_w = width;
3546 dest_h = gdk_pixbuf_get_height (src);
3547 }
3548
3549 else
3550 {
3551 dest_w = width;
3552 dest_h = height;
3553 }
3554
3555 if (dest_w == src_w && dest_h == src_h)
3556 {
3557 temp_pixbuf = src;
3558 g_object_ref (G_OBJECT (temp_pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2)))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2))))))))))
;
3559 }
3560 else
3561 {
3562 temp_pixbuf = gdk_pixbuf_scale_simple (src,
3563 dest_w, dest_h,
3564 GDK_INTERP_BILINEAR);
3565 }
3566
3567 /* prefer to replicate_cols if possible, as that
3568 * is faster (no memory reads)
3569 */
3570 if (horizontal_stripes)
3571 {
3572 pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
3573 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3574 }
3575 else if (vertical_stripes)
3576 {
3577 pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
3578 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3579 }
3580 else
3581 {
3582 pixbuf = temp_pixbuf;
3583 }
3584 }
3585 }
3586
3587 if (pixbuf)
3588 pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
3589
3590 return pixbuf;
3591}
3592
3593static GdkPixbuf*
3594draw_op_as_pixbuf (const MetaDrawOp *op,
3595 GtkStyleContext *style,
3596 const MetaDrawInfo *info,
3597 int width,
3598 int height)
3599{
3600 /* Try to get the op as a pixbuf, assuming w/h in the op
3601 * matches the width/height passed in. return NULL
3602 * if the op can't be converted to an equivalent pixbuf.
3603 */
3604 GdkPixbuf *pixbuf;
3605
3606 pixbuf = NULL((void*)0);
3607
3608 switch (op->type)
3609 {
3610 case META_DRAW_LINE:
3611 break;
3612
3613 case META_DRAW_RECTANGLE:
3614 if (op->data.rectangle.filled)
3615 {
3616 GdkRGBA color;
3617
3618 meta_color_spec_render (op->data.rectangle.color_spec,
3619 style,
3620 &color);
3621
3622 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3623 FALSE(0),
3624 8, width, height);
3625
3626 gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
);
3627 }
3628 break;
3629
3630 case META_DRAW_ARC:
3631 break;
3632
3633 case META_DRAW_CLIP:
3634 break;
3635
3636 case META_DRAW_TINT:
3637 {
3638 GdkRGBA color;
3639 guint32 rgba;
3640 gboolean has_alpha;
3641
3642 meta_color_spec_render (op->data.rectangle.color_spec,
3643 style,
3644 &color);
3645
3646 has_alpha =
3647 op->data.tint.alpha_spec &&
3648 (op->data.tint.alpha_spec->n_alphas > 1 ||
3649 op->data.tint.alpha_spec->alphas[0] != 0xff);
3650
3651 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3652 has_alpha,
3653 8, width, height);
3654
3655 if (!has_alpha)
3656 {
3657 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3658
3659 gdk_pixbuf_fill (pixbuf, rgba);
3660 }
3661 else if (op->data.tint.alpha_spec->n_alphas == 1)
3662 {
3663 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3664 rgba &= ~0xff;
3665 rgba |= op->data.tint.alpha_spec->alphas[0];
3666
3667 gdk_pixbuf_fill (pixbuf, rgba);
3668 }
3669 else
3670 {
3671 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3672
3673 gdk_pixbuf_fill (pixbuf, rgba);
3674
3675 meta_gradient_add_alpha (pixbuf,
3676 op->data.tint.alpha_spec->alphas,
3677 op->data.tint.alpha_spec->n_alphas,
3678 op->data.tint.alpha_spec->type);
3679 }
3680 }
3681 break;
3682
3683 case META_DRAW_IMAGE:
3684 {
3685 if (op->data.image.colorize_spec)
3686 {
3687 GdkRGBA color;
3688
3689 meta_color_spec_render (op->data.image.colorize_spec,
3690 style, &color);
3691
3692 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3693 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3694 {
3695 if (op->data.image.colorize_cache_pixbuf)
3696 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3697
3698 /* const cast here */
3699 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3700 colorize_pixbuf (op->data.image.pixbuf,
3701 &color);
3702 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3703 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3704 }
3705
3706 if (op->data.image.colorize_cache_pixbuf)
3707 {
3708 pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
3709 op->data.image.alpha_spec,
3710 op->data.image.fill_type,
3711 width, height,
3712 op->data.image.vertical_stripes,
3713 op->data.image.horizontal_stripes);
3714 }
3715 }
3716 else
3717 {
3718 pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
3719 op->data.image.alpha_spec,
3720 op->data.image.fill_type,
3721 width, height,
3722 op->data.image.vertical_stripes,
3723 op->data.image.horizontal_stripes);
3724 }
3725 break;
3726 }
3727
3728 case META_DRAW_GRADIENT:
3729 case META_DRAW_GTK_ARROW:
3730 case META_DRAW_GTK_BOX:
3731 case META_DRAW_GTK_VLINE:
3732 break;
3733
3734 case META_DRAW_ICON:
3735 if (info->mini_icon &&
3736 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3737 height <= gdk_pixbuf_get_height (info->mini_icon))
3738 pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
3739 op->data.icon.alpha_spec,
3740 op->data.icon.fill_type,
3741 width, height,
3742 FALSE(0), FALSE(0));
3743 else if (info->icon)
3744 pixbuf = scale_and_alpha_pixbuf (info->icon,
3745 op->data.icon.alpha_spec,
3746 op->data.icon.fill_type,
3747 width, height,
3748 FALSE(0), FALSE(0));
3749 break;
3750
3751 case META_DRAW_TITLE:
3752 break;
3753
3754 case META_DRAW_OP_LIST:
3755 break;
3756
3757 case META_DRAW_TILE:
3758 break;
3759 }
3760
3761 return pixbuf;
3762}
3763
3764static cairo_surface_t *
3765draw_op_as_surface (const MetaDrawOp *op,
3766 GtkStyleContext *style,
3767 const MetaDrawInfo *info,
3768 gdouble width,
3769 gdouble height)
3770{
3771 cairo_surface_t *surface;
3772
3773 surface = NULL((void*)0);
3774
3775 switch (op->type)
3776 {
3777 case META_DRAW_IMAGE:
3778 {
3779 if (op->data.image.colorize_spec)
3780 {
3781 GdkRGBA color;
3782
3783 meta_color_spec_render (op->data.image.colorize_spec,
3784 style, &color);
3785
3786 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3787 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3788 {
3789 if (op->data.image.colorize_cache_pixbuf)
3790 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3791
3792 /* const cast here */
3793 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3794 colorize_pixbuf (op->data.image.pixbuf,
3795 &color);
3796 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3797 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3798 }
3799
3800 if (op->data.image.colorize_cache_pixbuf)
3801 {
3802 surface = get_surface_from_pixbuf (op->data.image.colorize_cache_pixbuf,
3803 op->data.image.fill_type,
3804 width, height,
3805 op->data.image.vertical_stripes,
3806 op->data.image.horizontal_stripes);
3807 }
3808 }
3809 else
3810 {
3811 surface = get_surface_from_pixbuf (op->data.image.pixbuf,
3812 op->data.image.fill_type,
3813 width, height,
3814 op->data.image.vertical_stripes,
3815 op->data.image.horizontal_stripes);
3816 }
3817 break;
3818 }
3819
3820 case META_DRAW_ICON:
3821 if (info->mini_icon &&
3822 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3823 height <= gdk_pixbuf_get_height (info->mini_icon))
3824 surface = get_surface_from_pixbuf (info->mini_icon, op->data.icon.fill_type,
3825 width, height, FALSE(0), FALSE(0));
3826 else if (info->icon)
3827 surface = get_surface_from_pixbuf (info->icon, op->data.icon.fill_type,
3828 width, height, FALSE(0), FALSE(0));
3829 break;
3830
3831 case META_DRAW_TINT:
3832 case META_DRAW_LINE:
3833 case META_DRAW_RECTANGLE:
3834 case META_DRAW_ARC:
3835 case META_DRAW_CLIP:
3836 case META_DRAW_GRADIENT:
3837 case META_DRAW_GTK_ARROW:
3838 case META_DRAW_GTK_BOX:
3839 case META_DRAW_GTK_VLINE:
3840 case META_DRAW_TITLE:
3841 case META_DRAW_OP_LIST:
3842 case META_DRAW_TILE:
3843 break;
3844
3845 default:
3846 break;
3847 }
3848
3849 return surface;
3850}
3851
3852static void
3853fill_env (MetaPositionExprEnv *env,
3854 const MetaDrawInfo *info,
3855 MetaRectangle logical_region)
3856{
3857 /* FIXME this stuff could be raised into draw_op_list_draw() probably
3858 */
3859 env->rect = logical_region;
3860 env->object_width = -1;
3861 env->object_height = -1;
3862 if (info->fgeom)
3863 {
3864 env->left_width = info->fgeom->borders.visible.left;
3865 env->right_width = info->fgeom->borders.visible.right;
3866 env->top_height = info->fgeom->borders.visible.top;
3867 env->bottom_height = info->fgeom->borders.visible.bottom;
3868 env->frame_x_center = info->fgeom->width / 2 - logical_region.x;
3869 env->frame_y_center = info->fgeom->height / 2 - logical_region.y;
3870 }
3871 else
3872 {
3873 env->left_width = 0;
3874 env->right_width = 0;
3875 env->top_height = 0;
3876 env->bottom_height = 0;
3877 env->frame_x_center = 0;
3878 env->frame_y_center = 0;
3879 }
3880
3881 env->mini_icon_width = info->mini_icon ? gdk_pixbuf_get_width (info->mini_icon) : 0;
3882 env->mini_icon_height = info->mini_icon ? gdk_pixbuf_get_height (info->mini_icon) : 0;
3883 env->icon_width = info->icon ? gdk_pixbuf_get_width (info->icon) : 0;
3884 env->icon_height = info->icon ? gdk_pixbuf_get_height (info->icon) : 0;
3885
3886 env->title_width = info->title_layout_width;
3887 env->title_height = info->title_layout_height;
3888 env->theme = meta_current_theme;
3889}
3890
3891/* This code was originally rendering anti-aliased using X primitives, and
3892 * now has been switched to draw anti-aliased using cairo. In general, the
3893 * closest correspondence between X rendering and cairo rendering is given
3894 * by offsetting the geometry by 0.5 pixels in both directions before rendering
3895 * with cairo. This is because X samples at the upper left corner of the
3896 * pixel while cairo averages over the entire pixel. However, in the cases
3897 * where the X rendering was an exact rectangle with no "jaggies"
3898 * we need to be a bit careful about applying the offset. We want to produce
3899 * the exact same pixel-aligned rectangle, rather than a rectangle with
3900 * fuzz around the edges.
3901 */
3902static void
3903meta_draw_op_draw_with_env (const MetaDrawOp *op,
3904 GtkStyleContext *style_gtk,
3905 cairo_t *cr,
3906 const MetaDrawInfo *info,
3907 MetaRectangle rect,
3908 MetaPositionExprEnv *env)
3909{
3910 GdkRGBA color;
3911
3912 cairo_save (cr);
3913 gtk_style_context_save (style_gtk);
3914
3915 cairo_set_line_width (cr, 1.0);
3916
3917 switch (op->type)
3918 {
3919 case META_DRAW_LINE:
3920 {
3921 int x1, x2, y1, y2;
3922
3923 meta_color_spec_render (op->data.line.color_spec, style_gtk, &color);
3924 gdk_cairo_set_source_rgba (cr, &color);
3925
3926 if (op->data.line.width > 0)
3927 cairo_set_line_width (cr, op->data.line.width);
3928
3929 if (op->data.line.dash_on_length > 0 &&
3930 op->data.line.dash_off_length > 0)
3931 {
3932 double dash_list[2];
3933 dash_list[0] = op->data.line.dash_on_length;
3934 dash_list[1] = op->data.line.dash_off_length;
3935 cairo_set_dash (cr, dash_list, 2, 0);
3936 }
3937
3938 x1 = parse_x_position_unchecked (op->data.line.x1, env);
3939 y1 = parse_y_position_unchecked (op->data.line.y1, env);
3940
3941 if (!op->data.line.x2 &&
3942 !op->data.line.y2 &&
3943 op->data.line.width==0)
3944 {
3945 cairo_rectangle (cr, x1, y1, 1, 1);
3946 cairo_fill (cr);
3947 }
3948 else
3949 {
3950 if (op->data.line.x2)
3951 x2 = parse_x_position_unchecked (op->data.line.x2, env);
3952 else
3953 x2 = x1;
3954
3955 if (op->data.line.y2)
3956 y2 = parse_y_position_unchecked (op->data.line.y2, env);
3957 else
3958 y2 = y1;
3959
3960 /* This is one of the cases where we are matching the exact
3961 * pixel aligned rectangle produced by X; for zero-width lines
3962 * the generic algorithm produces the right result so we don't
3963 * need to handle them here.
3964 */
3965 if ((y1 == y2 || x1 == x2) && op->data.line.width != 0)
3966 {
3967 double offset = op->data.line.width % 2 ? .5 : 0;
3968
3969 if (y1 == y2)
3970 {
3971 cairo_move_to (cr, x1, y1 + offset);
3972 cairo_line_to (cr, x2, y2 + offset);
3973 }
3974 else
3975 {
3976 cairo_move_to (cr, x1 + offset, y1);
3977 cairo_line_to (cr, x2 + offset, y2);
3978 }
3979 }
3980 else
3981 {
3982 /* zero-width lines include both end-points in X, unlike wide lines */
3983 if (op->data.line.width == 0)
3984 cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
3985
3986 cairo_move_to (cr, x1 + .5, y1 + .5);
3987 cairo_line_to (cr, x2 + .5, y2 + .5);
3988 }
3989 cairo_stroke (cr);
3990 }
3991 }
3992 break;
3993
3994 case META_DRAW_RECTANGLE:
3995 {
3996 int rx, ry, rwidth, rheight;
3997
3998 meta_color_spec_render (op->data.rectangle.color_spec, style_gtk, &color);
3999 gdk_cairo_set_source_rgba (cr, &color);
4000
4001 rx = parse_x_position_unchecked (op->data.rectangle.x, env);
4002 ry = parse_y_position_unchecked (op->data.rectangle.y, env);
4003 rwidth = parse_size_unchecked (op->data.rectangle.width, env);
4004 rheight = parse_size_unchecked (op->data.rectangle.height, env);
4005
4006 /* Filled and stroked rectangles are the other cases
4007 * we pixel-align to X rasterization
4008 */
4009 if (op->data.rectangle.filled)
4010 {
4011 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4012 cairo_fill (cr);
4013 }
4014 else
4015 {
4016 cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight);
4017 cairo_stroke (cr);
4018 }
4019 }
4020 break;
4021
4022 case META_DRAW_ARC:
4023 {
4024 int rx, ry, rwidth, rheight;
4025 double start_angle, end_angle;
4026 double center_x, center_y;
4027
4028 meta_color_spec_render (op->data.arc.color_spec, style_gtk, &color);
4029 gdk_cairo_set_source_rgba (cr, &color);
4030
4031 rx = parse_x_position_unchecked (op->data.arc.x, env);
4032 ry = parse_y_position_unchecked (op->data.arc.y, env);
4033 rwidth = parse_size_unchecked (op->data.arc.width, env);
4034 rheight = parse_size_unchecked (op->data.arc.height, env);
4035
4036 start_angle = op->data.arc.start_angle * (M_PI3.14159265358979323846 / 180.)
4037 - (.5 * M_PI3.14159265358979323846); /* start at 12 instead of 3 oclock */
4038 end_angle = start_angle + op->data.arc.extent_angle * (M_PI3.14159265358979323846 / 180.);
4039 center_x = rx + (double)rwidth / 2. + .5;
4040 center_y = ry + (double)rheight / 2. + .5;
4041
4042 cairo_save (cr);
4043
4044 cairo_translate (cr, center_x, center_y);
4045 cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.);
4046
4047 if (op->data.arc.extent_angle >= 0)
4048 cairo_arc (cr, 0, 0, 1, start_angle, end_angle);
4049 else
4050 cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle);
4051
4052 cairo_restore (cr);
4053
4054 if (op->data.arc.filled)
4055 {
4056 cairo_line_to (cr, center_x, center_y);
4057 cairo_fill (cr);
4058 }
4059 else
4060 cairo_stroke (cr);
4061 }
4062 break;
4063
4064 case META_DRAW_CLIP:
4065 break;
4066
4067 case META_DRAW_TINT:
4068 {
4069 int rx, ry, rwidth, rheight;
4070 gboolean needs_alpha;
4071
4072 needs_alpha = op->data.tint.alpha_spec &&
4073 (op->data.tint.alpha_spec->n_alphas > 1 ||
4074 op->data.tint.alpha_spec->alphas[0] != 0xff);
4075
4076 rx = parse_x_position_unchecked (op->data.tint.x, env);
4077 ry = parse_y_position_unchecked (op->data.tint.y, env);
4078 rwidth = parse_size_unchecked (op->data.tint.width, env);
4079 rheight = parse_size_unchecked (op->data.tint.height, env);
4080
4081 if (!needs_alpha)
4082 {
4083 meta_color_spec_render (op->data.tint.color_spec, style_gtk, &color);
4084 gdk_cairo_set_source_rgba (cr, &color);
4085
4086 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4087 cairo_fill (cr);
4088 }
4089 else
4090 {
4091 GdkPixbuf *pixbuf;
4092
4093 pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
4094 rwidth, rheight);
4095
4096 if (pixbuf)
4097 {
4098 gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
4099 cairo_paint (cr);
4100
4101 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
4102 }
4103 }
4104 }
4105 break;
4106
4107 case META_DRAW_GRADIENT:
4108 {
4109 int rx, ry, rwidth, rheight;
4110
4111 rx = parse_x_position_unchecked (op->data.gradient.x, env);
4112 ry = parse_y_position_unchecked (op->data.gradient.y, env);
4113 rwidth = parse_size_unchecked (op->data.gradient.width, env);
4114 rheight = parse_size_unchecked (op->data.gradient.height, env);
4115
4116 meta_gradient_spec_render (op->data.gradient.gradient_spec,
4117 op->data.gradient.alpha_spec,
4118 cr, style_gtk, rx, ry, rwidth, rheight);
4119 }
4120 break;
4121
4122 case META_DRAW_IMAGE:
4123 {
4124 gint scale;
4125 gdouble rx, ry, rwidth, rheight;
4126 cairo_surface_t *surface;
4127
4128 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4129 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4130
4131 if (op->data.image.pixbuf)
4132 {
4133 env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf) / scale;
4134 env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf) / scale;
4135 }
4136
4137 rwidth = parse_size_unchecked (op->data.image.width, env) * scale;
4138 rheight = parse_size_unchecked (op->data.image.height, env) * scale;
4139
4140 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4141
4142 if (surface)
4143 {
4144 rx = parse_x_position_unchecked (op->data.image.x, env) * scale;
4145 ry = parse_y_position_unchecked (op->data.image.y, env) * scale;
4146
4147 cairo_set_source_surface (cr, surface, rx, ry);
4148
4149 if (op->data.image.alpha_spec)
4150 {
4151 cairo_pattern_t *pattern;
4152
4153 cairo_translate (cr, rx, ry);
4154 cairo_scale (cr, rwidth, rheight);
4155
4156 pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec);
4157 cairo_mask (cr, pattern);
4158
4159 cairo_pattern_destroy (pattern);
4160 }
4161 else
4162 {
4163 cairo_paint (cr);
4164 }
4165
4166 cairo_surface_destroy (surface);
4167 }
4168 }
4169 break;
4170
4171 case META_DRAW_GTK_ARROW:
4172 {
4173 int rx, ry, rwidth, rheight;
4174
4175 rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
4176 ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
4177 rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
4178 rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
4179
4180 double size = MAX(rwidth, rheight)(((rwidth) > (rheight)) ? (rwidth) : (rheight)), angle = 0;
4181
4182 switch (op->data.gtk_arrow.arrow)
4183 {
4184 case GTK_ARROW_UP:
4185 angle = 0;
4186 break;
4187 case GTK_ARROW_RIGHT:
4188 angle = M_PI3.14159265358979323846 / 2;
4189 break;
4190 case GTK_ARROW_DOWN:
4191 angle = M_PI3.14159265358979323846;
4192 break;
4193 case GTK_ARROW_LEFT:
4194 angle = 3 * M_PI3.14159265358979323846 / 2;
4195 break;
4196 case GTK_ARROW_NONE:
4197 return;
4198 }
4199
4200 gtk_style_context_set_state (style_gtk, op->data.gtk_arrow.state);
4201 gtk_render_arrow (style_gtk, cr, angle, rx, ry, size);
4202 }
4203 break;
4204
4205 case META_DRAW_GTK_BOX:
4206 {
4207 int rx, ry, rwidth, rheight;
4208
4209 rx = parse_x_position_unchecked (op->data.gtk_box.x, env);
4210 ry = parse_y_position_unchecked (op->data.gtk_box.y, env);
4211 rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
4212 rheight = parse_size_unchecked (op->data.gtk_box.height, env);
4213
4214 gtk_style_context_set_state (style_gtk, op->data.gtk_box.state);
4215 gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight);
4216 gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight);
4217 }
4218 break;
4219
4220 case META_DRAW_GTK_VLINE:
4221 {
4222 int rx, ry1, ry2;
4223
4224 rx = parse_x_position_unchecked (op->data.gtk_vline.x, env);
4225 ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
4226 ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
4227
4228 gtk_style_context_set_state (style_gtk, op->data.gtk_vline.state);
4229 gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2);
4230 }
4231 break;
4232
4233 case META_DRAW_ICON:
4234 {
4235 gint scale;
4236 gdouble rx, ry, rwidth, rheight;
4237 cairo_surface_t *surface;
4238
4239 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4240 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4241
4242 rwidth = parse_size_unchecked (op->data.icon.width, env) * scale;
4243 rheight = parse_size_unchecked (op->data.icon.height, env) * scale;
4244
4245 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4246
4247 if (surface)
4248 {
4249 rx = parse_x_position_unchecked (op->data.icon.x, env) * scale;
4250 ry = parse_y_position_unchecked (op->data.icon.y, env) * scale;
4251
4252 cairo_set_source_surface (cr, surface, rx, ry);
4253
4254 if (op->data.icon.alpha_spec)
4255 {
4256 cairo_pattern_t *pattern;
4257
4258 cairo_translate (cr, rx, ry);
4259 cairo_scale (cr, rwidth, rheight);
4260
4261 pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec);
4262 cairo_mask (cr, pattern);
4263
4264 cairo_pattern_destroy (pattern);
4265 }
4266 else
4267 {
4268 cairo_paint (cr);
4269 }
4270
4271 cairo_surface_destroy (surface);
4272 }
4273 }
4274 break;
4275
4276 case META_DRAW_TITLE:
4277 if (info->title_layout)
4278 {
4279 int rx, ry;
4280 PangoRectangle ink_rect, logical_rect;
4281
4282 meta_color_spec_render (op->data.title.color_spec, style_gtk, &color);
4283 gdk_cairo_set_source_rgba (cr, &color);
4284
4285 rx = parse_x_position_unchecked (op->data.title.x, env);
4286 ry = parse_y_position_unchecked (op->data.title.y, env);
4287
4288 if (op->data.title.ellipsize_width)
4289 {
4290 int ellipsize_width;
4291 int right_bearing;
4292
4293 ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env);
4294 /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */
4295 ellipsize_width -= env->rect.x;
4296
4297 pango_layout_set_width (info->title_layout, -1);
4298 pango_layout_get_pixel_extents (info->title_layout,
4299 &ink_rect, &logical_rect);
4300
4301 /* Pango's idea of ellipsization is with respect to the logical rect.
4302 * correct for this, by reducing the ellipsization width by the overflow
4303 * of the un-ellipsized text on the right... it's always the visual
4304 * right we want regardless of bidi, since since the X we pass in to
4305 * cairo_move_to() is always the left edge of the line.
4306 */
4307 right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width);
4308 right_bearing = MAX (right_bearing, 0)(((right_bearing) > (0)) ? (right_bearing) : (0));
4309
4310 ellipsize_width -= right_bearing;
4311 ellipsize_width = MAX (ellipsize_width, 0)(((ellipsize_width) > (0)) ? (ellipsize_width) : (0));
4312
4313 /* Only ellipsizing when necessary is a performance optimization -
4314 * pango_layout_set_width() will force a relayout if it isn't the
4315 * same as the current width of -1.
4316 */
4317 if (ellipsize_width < logical_rect.width)
4318 pango_layout_set_width (info->title_layout, PANGO_SCALE1024 * ellipsize_width);
4319 }
4320 else if (rx - env->rect.x + env->title_width >= env->rect.width)
4321 {
4322 const double alpha_margin = 30.0;
4323 int text_space = env->rect.x + env->rect.width -
4324 (rx - env->rect.x) - env->right_width;
4325
4326 double startalpha = 1.0 - (alpha_margin/((double)text_space));
4327
4328 cairo_pattern_t *linpat;
4329 linpat = cairo_pattern_create_linear (rx, ry, text_space,
4330 env->title_height);
4331 cairo_pattern_add_color_stop_rgba (linpat, 0, color.red,
4332 color.green,
4333 color.blue,
4334 color.alpha);
4335 cairo_pattern_add_color_stop_rgba (linpat, startalpha,
4336 color.red,
4337 color.green,
4338 color.blue,
4339 color.alpha);
4340 cairo_pattern_add_color_stop_rgba (linpat, 1, color.red,
4341 color.green,
4342 color.blue, 0);
4343 cairo_set_source(cr, linpat);
4344 cairo_pattern_destroy(linpat);
4345 }
4346
4347 cairo_move_to (cr, rx, ry);
4348 pango_cairo_show_layout (cr, info->title_layout);
4349
4350 /* Remove any ellipsization we might have set; will short-circuit
4351 * if the width is already -1 */
4352 pango_layout_set_width (info->title_layout, -1);
4353 }
4354 break;
4355
4356 case META_DRAW_OP_LIST:
4357 {
4358 MetaRectangle d_rect;
4359
4360 d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env);
4361 d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env);
4362 d_rect.width = parse_size_unchecked (op->data.op_list.width, env);
4363 d_rect.height = parse_size_unchecked (op->data.op_list.height, env);
4364
4365 meta_draw_op_list_draw_with_style (op->data.op_list.op_list,
4366 style_gtk,
4367 cr,
4368 info, d_rect);
4369 }
4370 break;
4371
4372 case META_DRAW_TILE:
4373 {
4374 int rx, ry, rwidth, rheight;
4375 int tile_xoffset, tile_yoffset;
4376 MetaRectangle tile;
4377
4378 rx = parse_x_position_unchecked (op->data.tile.x, env);
4379 ry = parse_y_position_unchecked (op->data.tile.y, env);
4380 rwidth = parse_size_unchecked (op->data.tile.width, env);
4381 rheight = parse_size_unchecked (op->data.tile.height, env);
4382
4383 cairo_save (cr);
4384
4385 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4386 cairo_clip (cr);
4387
4388 tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env);
4389 tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env);
4390 /* tile offset should not include x/y */
4391 tile_xoffset -= rect.x;
4392 tile_yoffset -= rect.y;
4393
4394 tile.width = parse_size_unchecked (op->data.tile.tile_width, env);
4395 tile.height = parse_size_unchecked (op->data.tile.tile_height, env);
4396
4397 tile.x = rx - tile_xoffset;
4398
4399 while (tile.x < (rx + rwidth))
4400 {
4401 tile.y = ry - tile_yoffset;
4402 while (tile.y < (ry + rheight))
4403 {
4404 meta_draw_op_list_draw_with_style (op->data.tile.op_list,
4405 style_gtk, cr, info,
4406 tile);
4407
4408 tile.y += tile.height;
4409 }
4410
4411 tile.x += tile.width;
4412 }
4413 cairo_restore (cr);
4414 }
4415 break;
4416 }
4417
4418 cairo_restore (cr);
4419 gtk_style_context_restore (style_gtk);
4420}
4421
4422void
4423meta_draw_op_draw_with_style (const MetaDrawOp *op,
4424 GtkStyleContext *style_gtk,
4425 cairo_t *cr,
4426 const MetaDrawInfo *info,
4427 MetaRectangle logical_region)
4428{
4429 MetaPositionExprEnv env;
4430
4431 fill_env (&env, info, logical_region);
4432
4433 meta_draw_op_draw_with_env (op,
4434 style_gtk,
4435 cr,
4436 info, logical_region,
4437 &env);
4438
4439}
4440
4441void
4442meta_draw_op_draw (const MetaDrawOp *op,
4443 GtkWidget *widget,
4444 cairo_t *cr,
4445 const MetaDrawInfo *info,
4446 MetaRectangle logical_region)
4447{
4448 meta_draw_op_draw_with_style (op,
4449 gtk_widget_get_style_context (widget),
4450 cr,
4451 info, logical_region);
4452}
4453
4454MetaDrawOpList*
4455meta_draw_op_list_new (int n_preallocs)
4456{
4457 MetaDrawOpList *op_list;
4458
4459 g_return_val_if_fail (n_preallocs >= 0, NULL)do { if ((n_preallocs >= 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_preallocs >= 0")
; return (((void*)0)); } } while (0)
;
4460
4461 op_list = g_new (MetaDrawOpList, 1)((MetaDrawOpList *) g_malloc_n ((1), sizeof (MetaDrawOpList))
)
;
4462
4463 op_list->refcount = 1;
4464 op_list->n_allocated = n_preallocs;
4465 op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated)((MetaDrawOp* *) g_malloc_n ((op_list->n_allocated), sizeof
(MetaDrawOp*)))
;
4466 op_list->n_ops = 0;
4467
4468 return op_list;
4469}
4470
4471void
4472meta_draw_op_list_ref (MetaDrawOpList *op_list)
4473{
4474 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4475
4476 op_list->refcount += 1;
4477}
4478
4479void
4480meta_draw_op_list_unref (MetaDrawOpList *op_list)
4481{
4482 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4483 g_return_if_fail (op_list->refcount > 0)do { if ((op_list->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list->refcount > 0"
); return; } } while (0)
;
4484
4485 op_list->refcount -= 1;
4486
4487 if (op_list->refcount == 0)
4488 {
4489 int i;
4490
4491 for (i = 0; i < op_list->n_ops; i++)
4492 meta_draw_op_free (op_list->ops[i]);
4493
4494 g_free (op_list->ops);
4495
4496 DEBUG_FILL_STRUCT (op_list)memset ((op_list), 0xef, sizeof (*(op_list)));
4497 g_free (op_list);
4498 }
4499}
4500
4501void
4502meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
4503 GtkStyleContext *style_gtk,
4504 cairo_t *cr,
4505 const MetaDrawInfo *info,
4506 MetaRectangle rect)
4507{
4508 /* BOOKMARK */
4509
4510 int i;
4511 MetaPositionExprEnv env;
4512
4513 if (op_list->n_ops == 0)
4514 return;
4515
4516 fill_env (&env, info, rect);
4517
4518 /* FIXME this can be optimized, potentially a lot, by
4519 * compressing multiple ops when possible. For example,
4520 * anything convertible to a pixbuf can be composited
4521 * client-side, and putting a color tint over a pixbuf
4522 * can be done without creating the solid-color pixbuf.
4523 *
4524 * To implement this my plan is to have the idea of a
4525 * compiled draw op (with the string expressions already
4526 * evaluated), we make an array of those, and then fold
4527 * adjacent items when possible.
4528 */
4529
4530 cairo_save (cr);
4531
4532 for (i = 0; i < op_list->n_ops; i++)
4533 {
4534 MetaDrawOp *op = op_list->ops[i];
4535
4536 if (op->type == META_DRAW_CLIP)
4537 {
4538 cairo_restore (cr);
4539
4540 cairo_rectangle (cr,
4541 parse_x_position_unchecked (op->data.clip.x, &env),
4542 parse_y_position_unchecked (op->data.clip.y, &env),
4543 parse_size_unchecked (op->data.clip.width, &env),
4544 parse_size_unchecked (op->data.clip.height, &env));
4545 cairo_clip (cr);
4546
4547 cairo_save (cr);
4548 }
4549 else if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
4550 {
4551 meta_draw_op_draw_with_env (op, style_gtk, cr, info, rect, &env);
4552 }
4553 }
4554
4555 cairo_restore (cr);
4556}
4557
4558void
4559meta_draw_op_list_draw (const MetaDrawOpList *op_list,
4560 GtkWidget *widget,
4561 cairo_t *cr,
4562 const MetaDrawInfo *info,
4563 MetaRectangle rect)
4564
4565{
4566 meta_draw_op_list_draw_with_style (op_list,
4567 gtk_widget_get_style_context (widget),
4568 cr,
4569 info, rect);
4570}
4571
4572void
4573meta_draw_op_list_append (MetaDrawOpList *op_list,
4574 MetaDrawOp *op)
4575{
4576 if (op_list->n_ops == op_list->n_allocated)
4577 {
4578 op_list->n_allocated *= 2;
4579 op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated)((MetaDrawOp* *) g_realloc_n (op_list->ops, (op_list->n_allocated
), sizeof (MetaDrawOp*)))
;
4580 }
4581
4582 op_list->ops[op_list->n_ops] = op;
4583 op_list->n_ops += 1;
4584}
4585
4586gboolean
4587meta_draw_op_list_validate (MetaDrawOpList *op_list,
4588 GError **error)
4589{
4590 g_return_val_if_fail (op_list != NULL, FALSE)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
((0)); } } while (0)
;
4591
4592 /* empty lists are OK, nothing else to check really */
4593
4594 return TRUE(!(0));
4595}
4596
4597/* This is not done in validate, since we wouldn't know the name
4598 * of the list to report the error. It might be nice to
4599 * store names inside the list sometime.
4600 */
4601gboolean
4602meta_draw_op_list_contains (MetaDrawOpList *op_list,
4603 MetaDrawOpList *child)
4604{
4605 int i;
4606
4607 /* mmm, huge tree recursion */
4608
4609 for (i = 0; i < op_list->n_ops; i++)
4610 {
4611 if (op_list->ops[i]->type == META_DRAW_OP_LIST)
4612 {
4613 if (op_list->ops[i]->data.op_list.op_list == child)
4614 return TRUE(!(0));
4615
4616 if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list,
4617 child))
4618 return TRUE(!(0));
4619 }
4620 else if (op_list->ops[i]->type == META_DRAW_TILE)
4621 {
4622 if (op_list->ops[i]->data.tile.op_list == child)
4623 return TRUE(!(0));
4624
4625 if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list,
4626 child))
4627 return TRUE(!(0));
4628 }
4629 }
4630
4631 return FALSE(0);
4632}
4633
4634/**
4635 * Constructor for a MetaFrameStyle.
4636 *
4637 * \param parent The parent style. Data not filled in here will be
4638 * looked for in the parent style, and in its parent
4639 * style, and so on.
4640 *
4641 * \return The newly-constructed style.
4642 */
4643MetaFrameStyle*
4644meta_frame_style_new (MetaFrameStyle *parent)
4645{
4646 MetaFrameStyle *style;
4647
4648 style = g_new0 (MetaFrameStyle, 1)((MetaFrameStyle *) g_malloc0_n ((1), sizeof (MetaFrameStyle)
))
;
4649
4650 style->refcount = 1;
4651
4652 /* Default alpha is fully opaque */
4653 style->window_background_alpha = 255;
4654
4655 style->parent = parent;
4656 if (parent)
4657 meta_frame_style_ref (parent);
4658
4659 return style;
4660}
4661
4662/**
4663 * Increases the reference count of a frame style.
4664 * If the style is NULL, this is a no-op.
4665 *
4666 * \param style The style.
4667 */
4668void
4669meta_frame_style_ref (MetaFrameStyle *style)
4670{
4671 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4672
4673 style->refcount += 1;
4674}
4675
4676static void
4677free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
4678{
4679 int i, j;
4680
4681 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4682 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4683 if (op_lists[i][j])
4684 meta_draw_op_list_unref (op_lists[i][j]);
4685}
4686
4687void
4688meta_frame_style_unref (MetaFrameStyle *style)
4689{
4690 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4691 g_return_if_fail (style->refcount > 0)do { if ((style->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->refcount > 0"
); return; } } while (0)
;
4692
4693 style->refcount -= 1;
4694
4695 if (style->refcount == 0)
4696 {
4697 int i;
4698
4699 free_button_ops (style->buttons);
4700
4701 for (i = 0; i < META_FRAME_PIECE_LAST; i++)
4702 if (style->pieces[i])
4703 meta_draw_op_list_unref (style->pieces[i]);
4704
4705 if (style->layout)
4706 meta_frame_layout_unref (style->layout);
4707
4708 if (style->window_background_color)
4709 meta_color_spec_free (style->window_background_color);
4710
4711 /* we hold a reference to any parent style */
4712 if (style->parent)
4713 meta_frame_style_unref (style->parent);
4714
4715 DEBUG_FILL_STRUCT (style)memset ((style), 0xef, sizeof (*(style)));
4716 g_free (style);
4717 }
4718}
4719
4720static MetaButtonState
4721map_button_state (MetaButtonType button_type,
4722 const MetaFrameGeometry *fgeom,
4723 int middle_bg_offset,
4724 MetaButtonState button_states[META_BUTTON_TYPE_LAST])
4725{
4726 MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
4727
4728 switch (button_type)
4729 {
4730 /* First handle functions, which map directly */
4731 case META_BUTTON_TYPE_SHADE:
4732 case META_BUTTON_TYPE_ABOVE:
4733 case META_BUTTON_TYPE_STICK:
4734 case META_BUTTON_TYPE_UNSHADE:
4735 case META_BUTTON_TYPE_UNABOVE:
4736 case META_BUTTON_TYPE_UNSTICK:
4737 case META_BUTTON_TYPE_MENU:
4738 case META_BUTTON_TYPE_APPMENU:
4739 case META_BUTTON_TYPE_MINIMIZE:
4740 case META_BUTTON_TYPE_MAXIMIZE:
4741 case META_BUTTON_TYPE_CLOSE:
4742 return button_states[button_type];
4743
4744 /* Map position buttons to the corresponding function */
4745 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4746 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4747 if (fgeom->n_right_buttons > 0)
4748 function = fgeom->button_layout.right_buttons[0];
4749 break;
4750 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4751 if (fgeom->n_right_buttons > 0)
4752 function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
4753 break;
4754 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4755 if (middle_bg_offset + 1 < fgeom->n_right_buttons)
4756 function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
4757 break;
4758 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4759 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4760 if (fgeom->n_left_buttons > 0)
4761 function = fgeom->button_layout.left_buttons[0];
4762 break;
4763 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4764 if (fgeom->n_left_buttons > 0)
4765 function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
4766 break;
4767 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4768 if (middle_bg_offset + 1 < fgeom->n_left_buttons)
4769 function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
4770 break;
4771 case META_BUTTON_TYPE_LAST:
4772 break;
4773 }
4774
4775 if (function != META_BUTTON_FUNCTION_LAST)
4776 return button_states[map_button_function_to_type (function)];
4777
4778 return META_BUTTON_STATE_LAST;
4779}
4780
4781static MetaDrawOpList*
4782get_button (MetaFrameStyle *style,
4783 MetaButtonType type,
4784 MetaButtonState state)
4785{
4786 MetaDrawOpList *op_list;
4787 MetaFrameStyle *parent;
4788
4789 parent = style;
4790 op_list = NULL((void*)0);
4791 while (parent && op_list == NULL((void*)0))
4792 {
4793 op_list = parent->buttons[type][state];
4794 parent = parent->parent;
4795 }
4796
4797 /* We fall back to the side buttons if we don't have
4798 * single button backgrounds, and to middle button
4799 * backgrounds if we don't have the ones on the sides
4800 */
4801
4802 if (op_list == NULL((void*)0) &&
4803 type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND)
4804 return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state);
4805
4806 if (op_list == NULL((void*)0) &&
4807 type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND)
4808 return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state);
4809
4810 if (op_list == NULL((void*)0) &&
4811 (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
4812 type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
4813 return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
4814 state);
4815
4816 if (op_list == NULL((void*)0) &&
4817 (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND ||
4818 type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND))
4819 return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
4820 state);
4821
4822 /* We fall back to normal if no prelight */
4823 if (op_list == NULL((void*)0) &&
4824 state == META_BUTTON_STATE_PRELIGHT)
4825 return get_button (style, type, META_BUTTON_STATE_NORMAL);
4826
4827 return op_list;
4828}
4829
4830gboolean
4831meta_frame_style_validate (MetaFrameStyle *style,
4832 guint current_theme_version,
4833 GError **error)
4834{
4835 int i, j;
4836
4837 g_return_val_if_fail (style != NULL, FALSE)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
((0)); } } while (0)
;
4838 g_return_val_if_fail (style->layout != NULL, FALSE)do { if ((style->layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->layout != NULL"
); return ((0)); } } while (0)
;
4839
4840 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4841 {
4842 /* for now the "positional" buttons are optional */
4843 if (i >= META_BUTTON_TYPE_CLOSE)
4844 {
4845 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4846 {
4847 if (get_button (style, i, j) == NULL((void*)0) &&
4848 meta_theme_earliest_version_with_button (i) <= current_theme_version
4849 )
4850 {
4851 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
4852 META_THEME_ERROR_FAILED,
4853 _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style")((char *) g_dgettext ("marco", "<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"
))
,
4854 meta_button_type_to_string (i),
4855 meta_button_state_to_string (j));
4856 return FALSE(0);
4857 }
4858 }
4859 }
4860 }
4861
4862 return TRUE(!(0));
4863}
4864
4865static void
4866get_button_rect (MetaButtonType type,
4867 const MetaFrameGeometry *fgeom,
4868 int middle_background_offset,
4869 GdkRectangle *rect)
4870{
4871 switch (type)
4872 {
4873 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4874 *rect = fgeom->left_left_background;
4875 break;
4876
4877 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4878 *rect = fgeom->left_middle_backgrounds[middle_background_offset];
4879 break;
4880
4881 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4882 *rect = fgeom->left_right_background;
4883 break;
4884
4885 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4886 *rect = fgeom->left_single_background;
4887 break;
4888
4889 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4890 *rect = fgeom->right_left_background;
4891 break;
4892
4893 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4894 *rect = fgeom->right_middle_backgrounds[middle_background_offset];
4895 break;
4896
4897 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4898 *rect = fgeom->right_right_background;
4899 break;
4900
4901 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4902 *rect = fgeom->right_single_background;
4903 break;
4904
4905 case META_BUTTON_TYPE_CLOSE:
4906 *rect = fgeom->close_rect.visible;
4907 break;
4908
4909 case META_BUTTON_TYPE_SHADE:
4910 *rect = fgeom->shade_rect.visible;
4911 break;
4912
4913 case META_BUTTON_TYPE_UNSHADE:
4914 *rect = fgeom->unshade_rect.visible;
4915 break;
4916
4917 case META_BUTTON_TYPE_ABOVE:
4918 *rect = fgeom->above_rect.visible;
4919 break;
4920
4921 case META_BUTTON_TYPE_UNABOVE:
4922 *rect = fgeom->unabove_rect.visible;
4923 break;
4924
4925 case META_BUTTON_TYPE_STICK:
4926 *rect = fgeom->stick_rect.visible;
4927 break;
4928
4929 case META_BUTTON_TYPE_UNSTICK:
4930 *rect = fgeom->unstick_rect.visible;
4931 break;
4932
4933 case META_BUTTON_TYPE_MAXIMIZE:
4934 *rect = fgeom->max_rect.visible;
4935 break;
4936
4937 case META_BUTTON_TYPE_MINIMIZE:
4938 *rect = fgeom->min_rect.visible;
4939 break;
4940
4941 case META_BUTTON_TYPE_MENU:
4942 *rect = fgeom->menu_rect.visible;
4943 break;
4944
4945 case META_BUTTON_TYPE_APPMENU:
4946 *rect = fgeom->appmenu_rect.visible;
4947 break;
4948
4949 case META_BUTTON_TYPE_LAST:
4950 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 4950, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
4951 break;
4952 }
4953}
4954
4955void
4956meta_frame_style_draw_with_style (MetaFrameStyle *style,
4957 GtkStyleContext *style_gtk,
4958 cairo_t *cr,
4959 const MetaFrameGeometry *fgeom,
4960 int client_width,
4961 int client_height,
4962 PangoLayout *title_layout,
4963 int text_height,
4964 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
4965 GdkPixbuf *mini_icon,
4966 GdkPixbuf *icon)
4967{
4968 /* BOOKMARK */
4969 int i, j;
4970 GdkRectangle visible_rect;
4971 GdkRectangle titlebar_rect;
4972 GdkRectangle left_titlebar_edge;
4973 GdkRectangle right_titlebar_edge;
4974 GdkRectangle bottom_titlebar_edge;
4975 GdkRectangle top_titlebar_edge;
4976 GdkRectangle left_edge, right_edge, bottom_edge;
4977 PangoRectangle extents;
4978 MetaDrawInfo draw_info;
4979 const MetaFrameBorders *borders;
4980
4981 borders = &fgeom->borders;
4982
4983 visible_rect.x = borders->invisible.left;
4984 visible_rect.y = borders->invisible.top;
4985 visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
4986 visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
4987
4988 titlebar_rect.x = visible_rect.x;
4989 titlebar_rect.y = visible_rect.y;
4990 titlebar_rect.width = visible_rect.width;
4991 titlebar_rect.height = borders->visible.top;
4992
4993 left_titlebar_edge.x = titlebar_rect.x;
4994 left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
4995 left_titlebar_edge.width = fgeom->left_titlebar_edge;
4996 left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
4997
4998 right_titlebar_edge.y = left_titlebar_edge.y;
4999 right_titlebar_edge.height = left_titlebar_edge.height;
5000 right_titlebar_edge.width = fgeom->right_titlebar_edge;
5001 right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
5002
5003 top_titlebar_edge.x = titlebar_rect.x;
5004 top_titlebar_edge.y = titlebar_rect.y;
5005 top_titlebar_edge.width = titlebar_rect.width;
5006 top_titlebar_edge.height = fgeom->top_titlebar_edge;
5007
5008 bottom_titlebar_edge.x = titlebar_rect.x;
5009 bottom_titlebar_edge.width = titlebar_rect.width;
5010 bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
5011 bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
5012
5013 left_edge.x = visible_rect.x;
5014 left_edge.y = visible_rect.y + borders->visible.top;
5015 left_edge.width = borders->visible.left;
5016 left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5017
5018 right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
5019 right_edge.y = visible_rect.y + borders->visible.top;
5020 right_edge.width = borders->visible.right;
5021 right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5022
5023 bottom_edge.x = visible_rect.x;
5024 bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
5025 bottom_edge.width = visible_rect.width;
5026 bottom_edge.height = borders->visible.bottom;
5027
5028 if (title_layout)
5029 pango_layout_get_pixel_extents (title_layout,
5030 NULL((void*)0), &extents);
5031
5032 draw_info.mini_icon = mini_icon;
5033 draw_info.icon = icon;
5034 draw_info.title_layout = title_layout;
5035 draw_info.title_layout_width = title_layout ? extents.width : 0;
5036 draw_info.title_layout_height = title_layout ? extents.height : 0;
5037 draw_info.fgeom = fgeom;
5038
5039 /* The enum is in the order the pieces should be rendered. */
5040 i = 0;
5041 while (i < META_FRAME_PIECE_LAST)
5042 {
5043 GdkRectangle rect;
5044
5045 switch ((MetaFramePiece) i)
5046 {
5047 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
5048 rect = visible_rect;
5049 break;
5050
5051 case META_FRAME_PIECE_TITLEBAR:
5052 rect = titlebar_rect;
5053 break;
5054
5055 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
5056 rect = left_titlebar_edge;
5057 break;
5058
5059 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
5060 rect = right_titlebar_edge;
5061 break;
5062
5063 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
5064 rect = top_titlebar_edge;
5065 break;
5066
5067 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
5068 rect = bottom_titlebar_edge;
5069 break;
5070
5071 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
5072 rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
5073 rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
5074 rect.width = titlebar_rect.width - left_titlebar_edge.width -
5075 right_titlebar_edge.width;
5076 rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
5077 break;
5078
5079 case META_FRAME_PIECE_TITLE:
5080 rect = fgeom->title_rect;
5081 break;
5082
5083 case META_FRAME_PIECE_LEFT_EDGE:
5084 rect = left_edge;
5085 break;
5086
5087 case META_FRAME_PIECE_RIGHT_EDGE:
5088 rect = right_edge;
5089 break;
5090
5091 case META_FRAME_PIECE_BOTTOM_EDGE:
5092 rect = bottom_edge;
5093 break;
5094
5095 case META_FRAME_PIECE_OVERLAY:
5096 rect = visible_rect;
5097 break;
5098
5099 case META_FRAME_PIECE_LAST:
5100 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5100, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5101 break;
5102 }
5103
5104 cairo_save (cr);
5105
5106 gdk_cairo_rectangle (cr, &rect);
5107 cairo_clip (cr);
5108
5109 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5110 {
5111 MetaDrawOpList *op_list;
5112 MetaFrameStyle *parent;
5113
5114 parent = style;
5115 op_list = NULL((void*)0);
5116 while (parent && op_list == NULL((void*)0))
5117 {
5118 op_list = parent->pieces[i];
5119 parent = parent->parent;
5120 }
5121
5122 if (op_list)
5123 {
5124 MetaRectangle m_rect;
5125 m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
5126 meta_draw_op_list_draw_with_style (op_list,
5127 style_gtk,
5128 cr,
5129 &draw_info,
5130 m_rect);
5131 }
5132 }
5133
5134 cairo_restore (cr);
5135
5136 /* Draw buttons just before overlay */
5137 if ((i + 1) == META_FRAME_PIECE_OVERLAY)
5138 {
5139 MetaDrawOpList *op_list;
5140 int middle_bg_offset;
5141
5142 middle_bg_offset = 0;
5143 j = 0;
5144 while (j < META_BUTTON_TYPE_LAST)
5145 {
5146 MetaButtonState button_state;
5147
5148 get_button_rect (j, fgeom, middle_bg_offset, &rect);
5149
5150 button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
5151 op_list = get_button (style, j, button_state);
5152
5153 if (op_list)
5154 {
5155 cairo_save (cr);
5156 gdk_cairo_rectangle (cr, &rect);
5157 cairo_clip (cr);
5158
5159 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5160 {
5161 MetaRectangle m_rect;
5162
5163 m_rect = meta_rect (rect.x, rect.y,
5164 rect.width, rect.height);
5165
5166 meta_draw_op_list_draw_with_style (op_list,
5167 style_gtk,
5168 cr,
5169 &draw_info,
5170 m_rect);
5171 }
5172
5173 cairo_restore (cr);
5174 }
5175
5176 /* MIDDLE_BACKGROUND type may get drawn more than once */
5177 if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
5178 j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
5179 middle_bg_offset < MAX_MIDDLE_BACKGROUNDS(META_BUTTON_FUNCTION_LAST - 2))
5180 {
5181 ++middle_bg_offset;
5182 }
5183 else
5184 {
5185 middle_bg_offset = 0;
5186 ++j;
5187 }
5188 }
5189 }
5190
5191 ++i;
5192 }
5193}
5194
5195void
5196meta_frame_style_draw (MetaFrameStyle *style,
5197 GtkWidget *widget,
5198 cairo_t *cr,
5199 const MetaFrameGeometry *fgeom,
5200 int client_width,
5201 int client_height,
5202 PangoLayout *title_layout,
5203 int text_height,
5204 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5205 GdkPixbuf *mini_icon,
5206 GdkPixbuf *icon)
5207{
5208 meta_frame_style_draw_with_style (style,
5209 gtk_widget_get_style_context (widget),
5210 cr,
5211 fgeom, client_width, client_height,
5212 title_layout, text_height,
5213 button_states, mini_icon, icon);
5214}
5215
5216MetaFrameStyleSet*
5217meta_frame_style_set_new (MetaFrameStyleSet *parent)
5218{
5219 MetaFrameStyleSet *style_set;
5220
5221 style_set = g_new0 (MetaFrameStyleSet, 1)((MetaFrameStyleSet *) g_malloc0_n ((1), sizeof (MetaFrameStyleSet
)))
;
5222
5223 style_set->parent = parent;
5224 if (parent)
5225 meta_frame_style_set_ref (parent);
5226
5227 style_set->refcount = 1;
5228
5229 return style_set;
5230}
5231
5232static void
5233free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST])
5234{
5235 int i;
5236
5237 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5238 if (focus_styles[i])
5239 meta_frame_style_unref (focus_styles[i]);
5240}
5241
5242void
5243meta_frame_style_set_ref (MetaFrameStyleSet *style_set)
5244{
5245 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5246
5247 style_set->refcount += 1;
5248}
5249
5250void
5251meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
5252{
5253 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5254 g_return_if_fail (style_set->refcount > 0)do { if ((style_set->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set->refcount > 0"
); return; } } while (0)
;
5255
5256 style_set->refcount -= 1;
5257
5258 if (style_set->refcount == 0)
5259 {
5260 int i;
5261
5262 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5263 {
5264 free_focus_styles (style_set->normal_styles[i]);
5265 free_focus_styles (style_set->shaded_styles[i]);
5266 }
5267
5268 free_focus_styles (style_set->maximized_styles);
5269 free_focus_styles (style_set->tiled_left_styles);
5270 free_focus_styles (style_set->tiled_right_styles);
5271 free_focus_styles (style_set->maximized_and_shaded_styles);
5272 free_focus_styles (style_set->tiled_left_and_shaded_styles);
5273 free_focus_styles (style_set->tiled_right_and_shaded_styles);
5274
5275 if (style_set->parent)
5276 meta_frame_style_set_unref (style_set->parent);
5277
5278 DEBUG_FILL_STRUCT (style_set)memset ((style_set), 0xef, sizeof (*(style_set)));
5279 g_free (style_set);
5280 }
5281}
5282
5283static MetaFrameStyle*
5284get_style (MetaFrameStyleSet *style_set,
5285 MetaFrameState state,
5286 MetaFrameResize resize,
5287 MetaFrameFocus focus)
5288{
5289 MetaFrameStyle *style;
5290
5291 style = NULL((void*)0);
5292
5293 switch (state)
5294 {
5295 case META_FRAME_STATE_NORMAL:
5296 case META_FRAME_STATE_SHADED:
5297 {
5298 if (state == META_FRAME_STATE_SHADED)
5299 style = style_set->shaded_styles[resize][focus];
5300 else
5301 style = style_set->normal_styles[resize][focus];
5302
5303 /* Try parent if we failed here */
5304 if (style == NULL((void*)0) && style_set->parent)
5305 style = get_style (style_set->parent, state, resize, focus);
5306
5307 /* Allow people to omit the vert/horz/none resize modes */
5308 if (style == NULL((void*)0) &&
5309 resize != META_FRAME_RESIZE_BOTH)
5310 style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
5311 }
5312 break;
5313 default:
5314 {
5315 MetaFrameStyle **styles;
5316
5317 styles = NULL((void*)0);
5318
5319 switch (state)
5320 {
5321 case META_FRAME_STATE_MAXIMIZED:
5322 styles = style_set->maximized_styles;
5323 break;
5324 case META_FRAME_STATE_TILED_LEFT:
5325 styles = style_set->tiled_left_styles;
5326 break;
5327 case META_FRAME_STATE_TILED_RIGHT:
5328 styles = style_set->tiled_right_styles;
5329 break;
5330 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
5331 styles = style_set->maximized_and_shaded_styles;
5332 break;
5333 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
5334 styles = style_set->tiled_left_and_shaded_styles;
5335 break;
5336 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
5337 styles = style_set->tiled_right_and_shaded_styles;
5338 break;
5339 case META_FRAME_STATE_NORMAL:
5340 case META_FRAME_STATE_SHADED:
5341 case META_FRAME_STATE_LAST:
5342 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5342, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5343 break;
5344 }
5345
5346 style = styles[focus];
5347
5348 /* Tiled states are optional, try falling back to non-tiled states */
5349 if (style == NULL((void*)0))
5350 {
5351 if (state == META_FRAME_STATE_TILED_LEFT ||
5352 state == META_FRAME_STATE_TILED_RIGHT)
5353 style = get_style (style_set, META_FRAME_STATE_NORMAL,
5354 resize, focus);
5355 else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED ||
5356 state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED)
5357 style = get_style (style_set, META_FRAME_STATE_SHADED,
5358 resize, focus);
5359 }
5360
5361 /* Try parent if we failed here */
5362 if (style == NULL((void*)0) && style_set->parent)
5363 style = get_style (style_set->parent, state, resize, focus);
5364 }
5365 }
5366
5367 return style;
5368}
5369
5370static gboolean
5371check_state (MetaFrameStyleSet *style_set,
5372 MetaFrameState state,
5373 GError **error)
5374{
5375 int i;
5376
5377 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5378 {
5379 if (get_style (style_set, state,
5380 META_FRAME_RESIZE_NONE, i) == NULL((void*)0))
5381 {
5382 /* Translators: This error occurs when a <frame> tag is missing
5383 * in theme XML. The "<frame ...>" is intended as a noun phrase,
5384 * and the "missing" qualifies it. You should translate "whatever".
5385 */
5386 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5387 META_THEME_ERROR_FAILED,
5388 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5389 meta_frame_state_to_string (state),
5390 meta_frame_resize_to_string (META_FRAME_RESIZE_NONE),
5391 meta_frame_focus_to_string (i));
5392 return FALSE(0);
5393 }
5394 }
5395
5396 return TRUE(!(0));
5397}
5398
5399gboolean
5400meta_frame_style_set_validate (MetaFrameStyleSet *style_set,
5401 GError **error)
5402{
5403 int i, j;
5404
5405 g_return_val_if_fail (style_set != NULL, FALSE)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
((0)); } } while (0)
;
5406
5407 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5408 for (j = 0; j < META_FRAME_FOCUS_LAST; j++)
5409 if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL((void*)0))
5410 {
5411 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5412 META_THEME_ERROR_FAILED,
5413 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5414 meta_frame_state_to_string (META_FRAME_STATE_NORMAL),
5415 meta_frame_resize_to_string (i),
5416 meta_frame_focus_to_string (j));
5417 return FALSE(0);
5418 }
5419
5420 if (!check_state (style_set, META_FRAME_STATE_SHADED, error))
5421 return FALSE(0);
5422
5423 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error))
5424 return FALSE(0);
5425
5426 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error))
5427 return FALSE(0);
5428
5429 return TRUE(!(0));
5430}
5431
5432MetaTheme*
5433meta_theme_get_current (void)
5434{
5435 return meta_current_theme;
5436}
5437
5438void
5439meta_theme_set_current (const char *name,
5440 gboolean force_reload)
5441{
5442 MetaTheme *new_theme;
5443 GError *err;
5444
5445 meta_topicmeta_topic_real (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name);
5446
5447 if (!force_reload &&
5448 meta_current_theme &&
5449 strcmp (name, meta_current_theme->name) == 0)
5450 return;
5451
5452 err = NULL((void*)0);
5453 new_theme = meta_theme_load (name, &err);
5454
5455 if (new_theme == NULL((void*)0))
5456 {
5457 meta_warning (_("Failed to load theme \"%s\": %s\n")((char *) g_dgettext ("marco", "Failed to load theme \"%s\": %s\n"
))
,
5458 name, err->message);
5459 g_error_free (err);
5460 }
5461 else
5462 {
5463 if (meta_current_theme)
5464 meta_theme_free (meta_current_theme);
5465
5466 meta_current_theme = new_theme;
5467
5468 meta_topicmeta_topic_real (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name);
5469 }
5470}
5471
5472MetaTheme*
5473meta_theme_new (void)
5474{
5475 MetaTheme *theme;
5476
5477 theme = g_new0 (MetaTheme, 1)((MetaTheme *) g_malloc0_n ((1), sizeof (MetaTheme)));
5478
5479 theme->images_by_filename =
5480 g_hash_table_new_full (g_str_hash,
5481 g_str_equal,
5482 g_free,
5483 g_object_unref);
5484
5485 theme->layouts_by_name =
5486 g_hash_table_new_full (g_str_hash,
5487 g_str_equal,
5488 g_free,
5489 (GDestroyNotify) meta_frame_layout_unref);
5490
5491 theme->draw_op_lists_by_name =
5492 g_hash_table_new_full (g_str_hash,
5493 g_str_equal,
5494 g_free,
5495 (GDestroyNotify) meta_draw_op_list_unref);
5496
5497 theme->styles_by_name =
5498 g_hash_table_new_full (g_str_hash,
5499 g_str_equal,
5500 g_free,
5501 (GDestroyNotify) meta_frame_style_unref);
5502
5503 theme->style_sets_by_name =
5504 g_hash_table_new_full (g_str_hash,
5505 g_str_equal,
5506 g_free,
5507 (GDestroyNotify) meta_frame_style_set_unref);
5508
5509 /* Create our variable quarks so we can look up variables without
5510 having to strcmp for the names */
5511 theme->quark_width = g_quark_from_static_string ("width");
5512 theme->quark_height = g_quark_from_static_string ("height");
5513 theme->quark_object_width = g_quark_from_static_string ("object_width");
5514 theme->quark_object_height = g_quark_from_static_string ("object_height");
5515 theme->quark_left_width = g_quark_from_static_string ("left_width");
5516 theme->quark_right_width = g_quark_from_static_string ("right_width");
5517 theme->quark_top_height = g_quark_from_static_string ("top_height");
5518 theme->quark_bottom_height = g_quark_from_static_string ("bottom_height");
5519 theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width");
5520 theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height");
5521 theme->quark_icon_width = g_quark_from_static_string ("icon_width");
5522 theme->quark_icon_height = g_quark_from_static_string ("icon_height");
5523 theme->quark_title_width = g_quark_from_static_string ("title_width");
5524 theme->quark_title_height = g_quark_from_static_string ("title_height");
5525 theme->quark_frame_x_center = g_quark_from_static_string ("frame_x_center");
5526 theme->quark_frame_y_center = g_quark_from_static_string ("frame_y_center");
5527 return theme;
5528}
5529
5530void
5531meta_theme_free (MetaTheme *theme)
5532{
5533 int i;
5534
5535 g_return_if_fail (theme != NULL)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
; } } while (0)
;
5536
5537 g_free (theme->name);
5538 g_free (theme->dirname);
5539 g_free (theme->filename);
5540 g_free (theme->readable_name);
5541 g_free (theme->date);
5542 g_free (theme->description);
5543 g_free (theme->author);
5544 g_free (theme->copyright);
5545
5546 /* be more careful when destroying the theme hash tables,
5547 since they are only constructed as needed, and may be NULL. */
5548 if (theme->integer_constants)
5549 g_hash_table_destroy (theme->integer_constants);
5550 if (theme->images_by_filename)
5551 g_hash_table_destroy (theme->images_by_filename);
5552 if (theme->layouts_by_name)
5553 g_hash_table_destroy (theme->layouts_by_name);
5554 if (theme->draw_op_lists_by_name)
5555 g_hash_table_destroy (theme->draw_op_lists_by_name);
5556 if (theme->styles_by_name)
5557 g_hash_table_destroy (theme->styles_by_name);
5558 if (theme->style_sets_by_name)
5559 g_hash_table_destroy (theme->style_sets_by_name);
5560
5561 for (i = 0; i < META_FRAME_TYPE_LAST; i++)
5562 if (theme->style_sets_by_type[i])
5563 meta_frame_style_set_unref (theme->style_sets_by_type[i]);
5564
5565 DEBUG_FILL_STRUCT (theme)memset ((theme), 0xef, sizeof (*(theme)));
5566 g_free (theme);
5567}
5568
5569gboolean
5570meta_theme_validate (MetaTheme *theme,
5571 GError **error)
5572{
5573 int i;
5574
5575 g_return_val_if_fail (theme != NULL, FALSE)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
((0)); } } while (0)
;
5576
5577 /* FIXME what else should be checked? */
5578
5579 g_assert (theme->name)do { if (theme->name) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 5579, ((const char*) (__func__)), "theme->name"
); } while (0)
;
5580
5581 if (theme->readable_name == NULL((void*)0))
5582 {
5583 /* Translators: This error means that a necessary XML tag (whose name
5584 * is given in angle brackets) was not found in a given theme (whose
5585 * name is given second, in quotation marks).
5586 */
5587 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5588 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "name", theme->name);
5589 return FALSE(0);
5590 }
5591
5592 if (theme->author == NULL((void*)0))
5593 {
5594 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5595 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "author", theme->name);
5596 return FALSE(0);
5597 }
5598
5599 if (theme->date == NULL((void*)0))
5600 {
5601 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5602 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "date", theme->name);
5603 return FALSE(0);
5604 }
5605
5606 if (theme->description == NULL((void*)0))
5607 {
5608 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5609 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "description", theme->name);
5610 return FALSE(0);
5611 }
5612
5613 if (theme->copyright == NULL((void*)0))
5614 {
5615 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5616 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "copyright", theme->name);
5617 return FALSE(0);
5618 }
5619
5620 for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
5621 if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL((void*)0))
5622 {
5623 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5624 _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element")((char *) g_dgettext ("marco", "No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"
))
,
5625 meta_frame_type_to_string (i),
5626 theme->name,
5627 meta_frame_type_to_string (i));
5628
5629 return FALSE(0);
5630 }
5631
5632 return TRUE(!(0));
5633}
5634
5635GdkPixbuf*
5636meta_theme_load_image (MetaTheme *theme,
5637 const char *filename,
5638 guint size_of_theme_icons,
5639 GError **error)
5640{
5641 GdkPixbuf *pixbuf;
5642 int scale;
5643
5644 pixbuf = g_hash_table_lookup (theme->images_by_filename,
5645 filename);
5646
5647 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
5648
5649 if (pixbuf == NULL((void*)0))
5650 {
5651
5652 if (g_str_has_prefix (filename, "theme:")(__builtin_constant_p ("theme:")? __extension__ ({ const char
* const __str = (filename); const char * const __prefix = ("theme:"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (filename, "theme:") )
&&
5653 META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES)(theme->format_version >= 2))
5654 {
5655 pixbuf = gtk_icon_theme_load_icon_for_scale (
5656 gtk_icon_theme_get_default (),
5657 filename+6,
5658 size_of_theme_icons,
5659 scale,
5660 0,
5661 error);
5662 if (pixbuf == NULL((void*)0)) return NULL((void*)0);
5663 }
5664 else
5665 {
5666 char *full_path;
5667 full_path = g_build_filename (theme->dirname, filename, NULL((void*)0));
5668
5669 gint width, height;
5670
5671 if (gdk_pixbuf_get_file_info (full_path, &width, &height) == NULL((void*)0))
5672 {
5673 g_free (full_path);
5674 return NULL((void*)0);
5675 }
5676
5677 width *= scale;
5678 height *= scale;
5679
5680 pixbuf = gdk_pixbuf_new_from_file_at_size (full_path, width, height, error);
5681
5682 if (pixbuf == NULL((void*)0))
5683 {
5684 g_free (full_path);
5685 return NULL((void*)0);
5686 }
5687
5688 g_free (full_path);
5689 }
5690 g_hash_table_replace (theme->images_by_filename,
5691 g_strdup (filename)g_strdup_inline (filename),
5692 pixbuf);
5693 }
5694
5695 g_assert (pixbuf)do { if (pixbuf) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 5695, ((const char*) (__func__)), "pixbuf"); } while (0)
;
5696
5697 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
5698
5699 return pixbuf;
5700}
5701
5702static MetaFrameStyle*
5703theme_get_style (MetaTheme *theme,
5704 MetaFrameType type,
5705 MetaFrameFlags flags)
5706{
5707 MetaFrameState state;
5708 MetaFrameResize resize;
5709 MetaFrameFocus focus;
5710 MetaFrameStyle *style;
5711 MetaFrameStyleSet *style_set;
5712
5713 style_set = theme->style_sets_by_type[type];
5714
5715 if (style_set == NULL((void*)0) && type == META_FRAME_TYPE_ATTACHED)
5716 style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER];
5717
5718 /* Right now the parser forces a style set for all other types,
5719 * but this fallback code is here in case I take that out.
5720 */
5721 if (style_set == NULL((void*)0))
5722 style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL];
5723 if (style_set == NULL((void*)0))
5724 return NULL((void*)0);
5725
5726 switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT))
5727 {
5728 case 0:
5729 state = META_FRAME_STATE_NORMAL;
5730 break;
5731 case META_FRAME_MAXIMIZED:
5732 state = META_FRAME_STATE_MAXIMIZED;
5733 break;
5734 case META_FRAME_TILED_LEFT:
5735 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_LEFT):
5736 state = META_FRAME_STATE_TILED_LEFT;
5737 break;
5738 case META_FRAME_TILED_RIGHT:
5739 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_RIGHT):
5740 state = META_FRAME_STATE_TILED_RIGHT;
5741 break;
5742 case META_FRAME_SHADED:
5743 state = META_FRAME_STATE_SHADED;
5744 break;
5745 case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
5746 state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
5747 break;
5748 case (META_FRAME_TILED_LEFT | META_FRAME_SHADED):
5749 state = META_FRAME_STATE_TILED_LEFT_AND_SHADED;
5750 break;
5751 case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED):
5752 state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
5753 break;
5754 default:
5755 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5755, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5756 state = META_FRAME_STATE_LAST; /* compiler */
5757 break;
5758 }
5759
5760 switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
5761 {
5762 case 0:
5763 resize = META_FRAME_RESIZE_NONE;
5764 break;
5765 case META_FRAME_ALLOWS_VERTICAL_RESIZE:
5766 resize = META_FRAME_RESIZE_VERTICAL;
5767 break;
5768 case META_FRAME_ALLOWS_HORIZONTAL_RESIZE:
5769 resize = META_FRAME_RESIZE_HORIZONTAL;
5770 break;
5771 case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE):
5772 resize = META_FRAME_RESIZE_BOTH;
5773 break;
5774 default:
5775 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5775, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5776 resize = META_FRAME_RESIZE_LAST; /* compiler */
5777 break;
5778 }
5779
5780 /* re invert the styles used for focus/unfocussed while flashing a frame */
5781 if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
5782 || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
5783 focus = META_FRAME_FOCUS_YES;
5784 else
5785 focus = META_FRAME_FOCUS_NO;
5786
5787 style = get_style (style_set, state, resize, focus);
5788
5789 return style;
5790}
5791
5792MetaFrameStyle*
5793meta_theme_get_frame_style (MetaTheme *theme,
5794 MetaFrameType type,
5795 MetaFrameFlags flags)
5796{
5797 MetaFrameStyle *style;
5798
5799 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (((void*)0)); } } while (0)
;
5800
5801 style = theme_get_style (theme, type, flags);
5802
5803 return style;
5804}
5805
5806double
5807meta_theme_get_title_scale (MetaTheme *theme,
5808 MetaFrameType type,
5809 MetaFrameFlags flags)
5810{
5811 MetaFrameStyle *style;
5812
5813 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (1.0); } } while (0)
;
5814
5815 style = theme_get_style (theme, type, flags);
5816
5817 /* Parser is not supposed to allow this currently */
5818 if (style == NULL((void*)0))
5819 return 1.0;
5820
5821 return style->layout->title_scale;
5822}
5823
5824void
5825meta_theme_draw_frame (MetaTheme *theme,
5826 GtkStyleContext *style_gtk,
5827 cairo_t *cr,
5828 MetaFrameType type,
5829 MetaFrameFlags flags,
5830 int client_width,
5831 int client_height,
5832 PangoLayout *title_layout,
5833 int text_height,
5834 const MetaButtonLayout *button_layout,
5835 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5836 GdkPixbuf *mini_icon,
5837 GdkPixbuf *icon)
5838{
5839 MetaFrameGeometry fgeom;
5840 MetaFrameStyle *style;
5841
5842 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5843
5844 style = theme_get_style (theme, type, flags);
5845
5846 /* Parser is not supposed to allow this currently */
5847 if (style == NULL((void*)0))
5848 return;
5849
5850 meta_frame_layout_calc_geometry (style->layout,
5851 text_height,
5852 flags,
5853 client_width, client_height,
5854 button_layout,
5855 &fgeom,
5856 theme);
5857
5858 meta_frame_style_draw_with_style (style,
5859 style_gtk,
5860 cr,
5861 &fgeom,
5862 client_width, client_height,
5863 title_layout,
5864 text_height,
5865 button_states,
5866 mini_icon, icon);
5867}
5868
5869void
5870meta_theme_draw_frame_by_name (MetaTheme *theme,
5871 GtkWidget *widget,
5872 cairo_t *cr,
5873 const gchar *style_name,
5874 MetaFrameFlags flags,
5875 int client_width,
5876 int client_height,
5877 PangoLayout *title_layout,
5878 int text_height,
5879 const MetaButtonLayout *button_layout,
5880 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5881 GdkPixbuf *mini_icon,
5882 GdkPixbuf *icon)
5883{
5884 MetaFrameGeometry fgeom;
5885 MetaFrameStyle *style;
5886
5887 style = meta_theme_lookup_style (theme, style_name);
5888
5889 /* Parser is not supposed to allow this currently */
5890 if (style == NULL((void*)0))
5891 return;
5892
5893 meta_frame_layout_calc_geometry (style->layout,
5894 text_height,
5895 flags,
5896 client_width, client_height,
5897 button_layout,
5898 &fgeom,
5899 theme);
5900
5901 meta_frame_style_draw (style,
5902 widget,
5903 cr,
5904 &fgeom,
5905 client_width, client_height,
5906 title_layout,
5907 text_height,
5908 button_states,
5909 mini_icon, icon);
5910}
5911
5912void
5913meta_theme_get_frame_borders (MetaTheme *theme,
5914 MetaFrameType type,
5915 int text_height,
5916 MetaFrameFlags flags,
5917 MetaFrameBorders *borders)
5918{
5919 MetaFrameStyle *style;
5920
5921 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5922
5923 style = theme_get_style (theme, type, flags);
5924
5925 meta_frame_borders_clear (borders);
5926
5927 /* Parser is not supposed to allow this currently */
5928 if (style == NULL((void*)0))
5929 return;
5930
5931 meta_frame_layout_get_borders (style->layout,
5932 text_height,
5933 flags,
5934 borders);
5935}
5936
5937void
5938meta_theme_calc_geometry (MetaTheme *theme,
5939 MetaFrameType type,
5940 int text_height,
5941 MetaFrameFlags flags,
5942 int client_width,
5943 int client_height,
5944 const MetaButtonLayout *button_layout,
5945 MetaFrameGeometry *fgeom)
5946{
5947 MetaFrameStyle *style;
5948
5949 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5950
5951 style = theme_get_style (theme, type, flags);
5952
5953 /* Parser is not supposed to allow this currently */
5954 if (style == NULL((void*)0))
5955 return;
5956
5957 meta_frame_layout_calc_geometry (style->layout,
5958 text_height,
5959 flags,
5960 client_width, client_height,
5961 button_layout,
5962 fgeom,
5963 theme);
5964}
5965
5966MetaFrameLayout*
5967meta_theme_lookup_layout (MetaTheme *theme,
5968 const char *name)
5969{
5970 return g_hash_table_lookup (theme->layouts_by_name, name);
5971}
5972
5973void
5974meta_theme_insert_layout (MetaTheme *theme,
5975 const char *name,
5976 MetaFrameLayout *layout)
5977{
5978 meta_frame_layout_ref (layout);
5979 g_hash_table_replace (theme->layouts_by_name, g_strdup (name)g_strdup_inline (name), layout);
5980}
5981
5982MetaDrawOpList*
5983meta_theme_lookup_draw_op_list (MetaTheme *theme,
5984 const char *name)
5985{
5986 return g_hash_table_lookup (theme->draw_op_lists_by_name, name);
5987}
5988
5989void
5990meta_theme_insert_draw_op_list (MetaTheme *theme,
5991 const char *name,
5992 MetaDrawOpList *op_list)
5993{
5994 meta_draw_op_list_ref (op_list);
5995 g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name)g_strdup_inline (name), op_list);
5996}
5997
5998MetaFrameStyle*
5999meta_theme_lookup_style (MetaTheme *theme,
6000 const char *name)
6001{
6002 return g_hash_table_lookup (theme->styles_by_name, name);
6003}
6004
6005void
6006meta_theme_insert_style (MetaTheme *theme,
6007 const char *name,
6008 MetaFrameStyle *style)
6009{
6010 meta_frame_style_ref (style);
6011 g_hash_table_replace (theme->styles_by_name, g_strdup (name)g_strdup_inline (name), style);
6012}
6013
6014MetaFrameStyleSet*
6015meta_theme_lookup_style_set (MetaTheme *theme,
6016 const char *name)
6017{
6018 return g_hash_table_lookup (theme->style_sets_by_name, name);
6019}
6020
6021void
6022meta_theme_insert_style_set (MetaTheme *theme,
6023 const char *name,
6024 MetaFrameStyleSet *style_set)
6025{
6026 meta_frame_style_set_ref (style_set);
6027 g_hash_table_replace (theme->style_sets_by_name, g_strdup (name)g_strdup_inline (name), style_set);
6028}
6029
6030static gboolean
6031first_uppercase (const char *str)
6032{
6033 return g_ascii_isupper (*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_UPPER) != 0);
6034}
6035
6036gboolean
6037meta_theme_define_int_constant (MetaTheme *theme,
6038 const char *name,
6039 int value,
6040 GError **error)
6041{
6042 if (theme->integer_constants == NULL((void*)0))
6043 theme->integer_constants = g_hash_table_new_full (g_str_hash,
6044 g_str_equal,
6045 g_free,
6046 NULL((void*)0));
6047
6048 if (!first_uppercase (name))
6049 {
6050 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6051 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6052 name);
6053 return FALSE(0);
6054 }
6055
6056 if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL((void*)0), NULL((void*)0)))
6057 {
6058 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6059 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6060 name);
6061
6062 return FALSE(0);
6063 }
6064
6065 g_hash_table_insert (theme->integer_constants,
6066 g_strdup (name)g_strdup_inline (name),
6067 GINT_TO_POINTER (value)((gpointer) (glong) (value)));
6068
6069 return TRUE(!(0));
6070}
6071
6072gboolean
6073meta_theme_lookup_int_constant (MetaTheme *theme,
6074 const char *name,
6075 int *value)
6076{
6077 gpointer old_value;
6078
6079 *value = 0;
6080
6081 if (theme->integer_constants == NULL((void*)0))
6082 return FALSE(0);
6083
6084 if (g_hash_table_lookup_extended (theme->integer_constants,
6085 name, NULL((void*)0), &old_value))
6086 {
6087 *value = GPOINTER_TO_INT (old_value)((gint) (glong) (old_value));
6088 return TRUE(!(0));
6089 }
6090 else
6091 {
6092 return FALSE(0);
6093 }
6094}
6095
6096gboolean
6097meta_theme_define_float_constant (MetaTheme *theme,
6098 const char *name,
6099 double value,
6100 GError **error)
6101{
6102 double *d;
6103
6104 if (theme->float_constants == NULL((void*)0))
6105 theme->float_constants = g_hash_table_new_full (g_str_hash,
6106 g_str_equal,
6107 g_free,
6108 g_free);
6109
6110 if (!first_uppercase (name))
6111 {
6112 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6113 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6114 name);
6115 return FALSE(0);
6116 }
6117
6118 if (g_hash_table_lookup_extended (theme->float_constants, name, NULL((void*)0), NULL((void*)0)))
6119 {
6120 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6121 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6122 name);
6123
6124 return FALSE(0);
6125 }
6126
6127 d = g_new (double, 1)((double *) g_malloc_n ((1), sizeof (double)));
6128 *d = value;
6129
6130 g_hash_table_insert (theme->float_constants,
6131 g_strdup (name)g_strdup_inline (name), d);
6132
6133 return TRUE(!(0));
6134}
6135
6136gboolean
6137meta_theme_lookup_float_constant (MetaTheme *theme,
6138 const char *name,
6139 double *value)
6140{
6141 double *d;
6142
6143 *value = 0.0;
6144
6145 if (theme->float_constants == NULL((void*)0))
6146 return FALSE(0);
6147
6148 d = g_hash_table_lookup (theme->float_constants, name);
6149
6150 if (d)
6151 {
6152 *value = *d;
6153 return TRUE(!(0));
6154 }
6155 else
6156 {
6157 return FALSE(0);
6158 }
6159}
6160
6161gboolean
6162meta_theme_define_color_constant (MetaTheme *theme,
6163 const char *name,
6164 const char *value,
6165 GError **error)
6166{
6167 if (theme->color_constants == NULL((void*)0))
6168 theme->color_constants = g_hash_table_new_full (g_str_hash,
6169 g_str_equal,
6170 g_free,
6171 NULL((void*)0));
6172
6173 if (!first_uppercase (name))
6174 {
6175 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6176 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6177 name);
6178 return FALSE(0);
6179 }
6180
6181 if (g_hash_table_lookup_extended (theme->color_constants, name, NULL((void*)0), NULL((void*)0)))
6182 {
6183 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6184 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6185 name);
6186
6187 return FALSE(0);
6188 }
6189
6190 g_hash_table_insert (theme->color_constants,
6191 g_strdup (name)g_strdup_inline (name),
6192 g_strdup (value)g_strdup_inline (value));
6193
6194 return TRUE(!(0));
6195}
6196
6197/**
6198 * Looks up a colour constant.
6199 *
6200 * \param theme the theme containing the constant
6201 * \param name the name of the constant
6202 * \param value [out] the string representation of the colour, or NULL if it
6203 * doesn't exist
6204 * \return TRUE if it exists, FALSE otherwise
6205 */
6206gboolean
6207meta_theme_lookup_color_constant (MetaTheme *theme,
6208 const char *name,
6209 char **value)
6210{
6211 char *result;
6212
6213 *value = NULL((void*)0);
6214
6215 if (theme->color_constants == NULL((void*)0))
6216 return FALSE(0);
6217
6218 result = g_hash_table_lookup (theme->color_constants, name);
6219
6220 if (result)
6221 {
6222 *value = result;
6223 return TRUE(!(0));
6224 }
6225 else
6226 {
6227 return FALSE(0);
6228 }
6229}
6230
6231PangoFontDescription*
6232meta_gtk_widget_get_font_desc (GtkWidget *widget,
6233 double scale,
6234 const PangoFontDescription *override)
6235{
6236 PangoFontDescription *font_desc;
6237 gint font_size;
6238
6239 GtkStyleContext *style = gtk_widget_get_style_context (widget);
6240 GtkStateFlags state = gtk_widget_get_state_flags (widget);
6241 gtk_style_context_get(style, state, GTK_STYLE_PROPERTY_FONT"font", &font_desc, NULL((void*)0));
6242
6243 if (override)
6244 pango_font_description_merge (font_desc, override, TRUE(!(0)));
6245
6246 font_size = pango_font_description_get_size (font_desc);
6247 pango_font_description_set_size (font_desc,
6248 MAX ((gint) (scale * (double) font_size), 1)((((gint) (scale * (double) font_size)) > (1)) ? ((gint) (
scale * (double) font_size)) : (1))
);
6249
6250 return font_desc;
6251}
6252
6253/**
6254 * Returns the height of the letters in a particular font.
6255 *
6256 * \param font_desc the font
6257 * \param context the context of the font
6258 * \return the height of the letters
6259 */
6260int
6261meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
6262 PangoContext *context)
6263{
6264 PangoFontMetrics *metrics;
6265 PangoLanguage *lang;
6266 int retval;
6267
6268 lang = pango_context_get_language (context);
6269 metrics = pango_context_get_metrics (context, font_desc, lang);
6270
6271 retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
6272 pango_font_metrics_get_descent (metrics))(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
;
6273
6274 pango_font_metrics_unref (metrics);
6275
6276 return retval;
6277}
6278
6279MetaGtkColorComponent
6280meta_color_component_from_string (const char *str)
6281{
6282 if (strcmp ("fg", str) == 0)
6283 return META_GTK_COLOR_FG;
6284 else if (strcmp ("bg", str) == 0)
6285 return META_GTK_COLOR_BG;
6286 else if (strcmp ("light", str) == 0)
6287 return META_GTK_COLOR_LIGHT;
6288 else if (strcmp ("dark", str) == 0)
6289 return META_GTK_COLOR_DARK;
6290 else if (strcmp ("mid", str) == 0)
6291 return META_GTK_COLOR_MID;
6292 else if (strcmp ("text", str) == 0)
6293 return META_GTK_COLOR_TEXT;
6294 else if (strcmp ("base", str) == 0)
6295 return META_GTK_COLOR_BASE;
6296 else if (strcmp ("text_aa", str) == 0)
6297 return META_GTK_COLOR_TEXT_AA;
6298 else
6299 return META_GTK_COLOR_LAST;
6300}
6301
6302const char*
6303meta_color_component_to_string (MetaGtkColorComponent component)
6304{
6305 switch (component)
6306 {
6307 case META_GTK_COLOR_FG:
6308 return "fg";
6309 case META_GTK_COLOR_BG:
6310 return "bg";
6311 case META_GTK_COLOR_LIGHT:
6312 return "light";
6313 case META_GTK_COLOR_DARK:
6314 return "dark";
6315 case META_GTK_COLOR_MID:
6316 return "mid";
6317 case META_GTK_COLOR_TEXT:
6318 return "text";
6319 case META_GTK_COLOR_BASE:
6320 return "base";
6321 case META_GTK_COLOR_TEXT_AA:
6322 return "text_aa";
6323 case META_GTK_COLOR_LAST:
6324 break;
6325 }
6326
6327 return "<unknown>";
6328}
6329
6330MetaButtonState
6331meta_button_state_from_string (const char *str)
6332{
6333 if (strcmp ("normal", str) == 0)
6334 return META_BUTTON_STATE_NORMAL;
6335 else if (strcmp ("pressed", str) == 0)
6336 return META_BUTTON_STATE_PRESSED;
6337 else if (strcmp ("prelight", str) == 0)
6338 return META_BUTTON_STATE_PRELIGHT;
6339 else
6340 return META_BUTTON_STATE_LAST;
6341}
6342
6343const char*
6344meta_button_state_to_string (MetaButtonState state)
6345{
6346 switch (state)
6347 {
6348 case META_BUTTON_STATE_NORMAL:
6349 return "normal";
6350 case META_BUTTON_STATE_PRESSED:
6351 return "pressed";
6352 case META_BUTTON_STATE_PRELIGHT:
6353 return "prelight";
6354 case META_BUTTON_STATE_LAST:
6355 break;
6356 }
6357
6358 return "<unknown>";
6359}
6360
6361MetaButtonType
6362meta_button_type_from_string (const char *str, MetaTheme *theme)
6363{
6364 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
6365 {
6366 if (strcmp ("shade", str) == 0)
6367 return META_BUTTON_TYPE_SHADE;
6368 else if (strcmp ("above", str) == 0)
6369 return META_BUTTON_TYPE_ABOVE;
6370 else if (strcmp ("stick", str) == 0)
6371 return META_BUTTON_TYPE_STICK;
6372 else if (strcmp ("unshade", str) == 0)
6373 return META_BUTTON_TYPE_UNSHADE;
6374 else if (strcmp ("unabove", str) == 0)
6375 return META_BUTTON_TYPE_UNABOVE;
6376 else if (strcmp ("unstick", str) == 0)
6377 return META_BUTTON_TYPE_UNSTICK;
6378 }
6379
6380 if (strcmp ("close", str) == 0)
6381 return META_BUTTON_TYPE_CLOSE;
6382 else if (strcmp ("maximize", str) == 0)
6383 return META_BUTTON_TYPE_MAXIMIZE;
6384 else if (strcmp ("minimize", str) == 0)
6385 return META_BUTTON_TYPE_MINIMIZE;
6386 else if (strcmp ("menu", str) == 0)
6387 return META_BUTTON_TYPE_MENU;
6388 else if (strcmp ("appmenu", str) == 0)
6389 return META_BUTTON_TYPE_APPMENU;
6390 else if (strcmp ("left_left_background", str) == 0)
6391 return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
6392 else if (strcmp ("left_middle_background", str) == 0)
6393 return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
6394 else if (strcmp ("left_right_background", str) == 0)
6395 return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
6396 else if (strcmp ("left_single_background", str) == 0)
6397 return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND;
6398 else if (strcmp ("right_left_background", str) == 0)
6399 return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
6400 else if (strcmp ("right_middle_background", str) == 0)
6401 return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
6402 else if (strcmp ("right_right_background", str) == 0)
6403 return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
6404 else if (strcmp ("right_single_background", str) == 0)
6405 return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND;
6406 else
6407 return META_BUTTON_TYPE_LAST;
6408}
6409
6410const char*
6411meta_button_type_to_string (MetaButtonType type)
6412{
6413 switch (type)
6414 {
6415 case META_BUTTON_TYPE_CLOSE:
6416 return "close";
6417 case META_BUTTON_TYPE_MAXIMIZE:
6418 return "maximize";
6419 case META_BUTTON_TYPE_MINIMIZE:
6420 return "minimize";
6421 case META_BUTTON_TYPE_SHADE:
6422 return "shade";
6423 case META_BUTTON_TYPE_ABOVE:
6424 return "above";
6425 case META_BUTTON_TYPE_STICK:
6426 return "stick";
6427 case META_BUTTON_TYPE_UNSHADE:
6428 return "unshade";
6429 case META_BUTTON_TYPE_UNABOVE:
6430 return "unabove";
6431 case META_BUTTON_TYPE_UNSTICK:
6432 return "unstick";
6433 case META_BUTTON_TYPE_MENU:
6434 return "menu";
6435 case META_BUTTON_TYPE_APPMENU:
6436 return "appmenu";
6437 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
6438 return "left_left_background";
6439 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
6440 return "left_middle_background";
6441 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
6442 return "left_right_background";
6443 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
6444 return "left_single_background";
6445 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
6446 return "right_left_background";
6447 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
6448 return "right_middle_background";
6449 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
6450 return "right_right_background";
6451 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
6452 return "right_single_background";
6453 case META_BUTTON_TYPE_LAST:
6454 break;
6455 }
6456
6457 return "<unknown>";
6458}
6459
6460MetaFramePiece
6461meta_frame_piece_from_string (const char *str)
6462{
6463 if (strcmp ("entire_background", str) == 0)
6464 return META_FRAME_PIECE_ENTIRE_BACKGROUND;
6465 else if (strcmp ("titlebar", str) == 0)
6466 return META_FRAME_PIECE_TITLEBAR;
6467 else if (strcmp ("titlebar_middle", str) == 0)
6468 return META_FRAME_PIECE_TITLEBAR_MIDDLE;
6469 else if (strcmp ("left_titlebar_edge", str) == 0)
6470 return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE;
6471 else if (strcmp ("right_titlebar_edge", str) == 0)
6472 return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE;
6473 else if (strcmp ("top_titlebar_edge", str) == 0)
6474 return META_FRAME_PIECE_TOP_TITLEBAR_EDGE;
6475 else if (strcmp ("bottom_titlebar_edge", str) == 0)
6476 return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE;
6477 else if (strcmp ("title", str) == 0)
6478 return META_FRAME_PIECE_TITLE;
6479 else if (strcmp ("left_edge", str) == 0)
6480 return META_FRAME_PIECE_LEFT_EDGE;
6481 else if (strcmp ("right_edge", str) == 0)
6482 return META_FRAME_PIECE_RIGHT_EDGE;
6483 else if (strcmp ("bottom_edge", str) == 0)
6484 return META_FRAME_PIECE_BOTTOM_EDGE;
6485 else if (strcmp ("overlay", str) == 0)
6486 return META_FRAME_PIECE_OVERLAY;
6487 else
6488 return META_FRAME_PIECE_LAST;
6489}
6490
6491const char*
6492meta_frame_piece_to_string (MetaFramePiece piece)
6493{
6494 switch (piece)
6495 {
6496 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
6497 return "entire_background";
6498 case META_FRAME_PIECE_TITLEBAR:
6499 return "titlebar";
6500 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
6501 return "titlebar_middle";
6502 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
6503 return "left_titlebar_edge";
6504 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
6505 return "right_titlebar_edge";
6506 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
6507 return "top_titlebar_edge";
6508 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
6509 return "bottom_titlebar_edge";
6510 case META_FRAME_PIECE_TITLE:
6511 return "title";
6512 case META_FRAME_PIECE_LEFT_EDGE:
6513 return "left_edge";
6514 case META_FRAME_PIECE_RIGHT_EDGE:
6515 return "right_edge";
6516 case META_FRAME_PIECE_BOTTOM_EDGE:
6517 return "bottom_edge";
6518 case META_FRAME_PIECE_OVERLAY:
6519 return "overlay";
6520 case META_FRAME_PIECE_LAST:
6521 break;
6522 }
6523
6524 return "<unknown>";
6525}
6526
6527MetaFrameState
6528meta_frame_state_from_string (const char *str)
6529{
6530 if (strcmp ("normal", str) == 0)
6531 return META_FRAME_STATE_NORMAL;
6532 else if (strcmp ("maximized", str) == 0)
6533 return META_FRAME_STATE_MAXIMIZED;
6534 else if (strcmp ("tiled_left", str) == 0)
6535 return META_FRAME_STATE_TILED_LEFT;
6536 else if (strcmp ("tiled_right", str) == 0)
6537 return META_FRAME_STATE_TILED_RIGHT;
6538 else if (strcmp ("shaded", str) == 0)
6539 return META_FRAME_STATE_SHADED;
6540 else if (strcmp ("maximized_and_shaded", str) == 0)
6541 return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
6542 else if (strcmp ("tiled_left_and_shaded", str) == 0)
6543 return META_FRAME_STATE_TILED_LEFT_AND_SHADED;
6544 else if (strcmp ("tiled_right_and_shaded", str) == 0)
6545 return META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
6546 else
6547 return META_FRAME_STATE_LAST;
6548}
6549
6550const char*
6551meta_frame_state_to_string (MetaFrameState state)
6552{
6553 switch (state)
6554 {
6555 case META_FRAME_STATE_NORMAL:
6556 return "normal";
6557 case META_FRAME_STATE_MAXIMIZED:
6558 return "maximized";
6559 case META_FRAME_STATE_TILED_LEFT:
6560 return "tiled_left";
6561 case META_FRAME_STATE_TILED_RIGHT:
6562 return "tiled_right";
6563 case META_FRAME_STATE_SHADED:
6564 return "shaded";
6565 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
6566 return "maximized_and_shaded";
6567 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
6568 return "tiled_left_and_shaded";
6569 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
6570 return "tiled_right_and_shaded";
6571 case META_FRAME_STATE_LAST:
6572 break;
6573 }
6574
6575 return "<unknown>";
6576}
6577
6578MetaFrameResize
6579meta_frame_resize_from_string (const char *str)
6580{
6581 if (strcmp ("none", str) == 0)
6582 return META_FRAME_RESIZE_NONE;
6583 else if (strcmp ("vertical", str) == 0)
6584 return META_FRAME_RESIZE_VERTICAL;
6585 else if (strcmp ("horizontal", str) == 0)
6586 return META_FRAME_RESIZE_HORIZONTAL;
6587 else if (strcmp ("both", str) == 0)
6588 return META_FRAME_RESIZE_BOTH;
6589 else
6590 return META_FRAME_RESIZE_LAST;
6591}
6592
6593const char*
6594meta_frame_resize_to_string (MetaFrameResize resize)
6595{
6596 switch (resize)
6597 {
6598 case META_FRAME_RESIZE_NONE:
6599 return "none";
6600 case META_FRAME_RESIZE_VERTICAL:
6601 return "vertical";
6602 case META_FRAME_RESIZE_HORIZONTAL:
6603 return "horizontal";
6604 case META_FRAME_RESIZE_BOTH:
6605 return "both";
6606 case META_FRAME_RESIZE_LAST:
6607 break;
6608 }
6609
6610 return "<unknown>";
6611}
6612
6613MetaFrameFocus
6614meta_frame_focus_from_string (const char *str)
6615{
6616 if (strcmp ("no", str) == 0)
6617 return META_FRAME_FOCUS_NO;
6618 else if (strcmp ("yes", str) == 0)
6619 return META_FRAME_FOCUS_YES;
6620 else
6621 return META_FRAME_FOCUS_LAST;
6622}
6623
6624const char*
6625meta_frame_focus_to_string (MetaFrameFocus focus)
6626{
6627 switch (focus)
6628 {
6629 case META_FRAME_FOCUS_NO:
6630 return "no";
6631 case META_FRAME_FOCUS_YES:
6632 return "yes";
6633 case META_FRAME_FOCUS_LAST:
6634 break;
6635 }
6636
6637 return "<unknown>";
6638}
6639
6640MetaFrameType
6641meta_frame_type_from_string (const char *str)
6642{
6643 if (strcmp ("normal", str) == 0)
6644 return META_FRAME_TYPE_NORMAL;
6645 else if (strcmp ("dialog", str) == 0)
6646 return META_FRAME_TYPE_DIALOG;
6647 else if (strcmp ("modal_dialog", str) == 0)
6648 return META_FRAME_TYPE_MODAL_DIALOG;
6649 else if (strcmp ("utility", str) == 0)
6650 return META_FRAME_TYPE_UTILITY;
6651 else if (strcmp ("menu", str) == 0)
6652 return META_FRAME_TYPE_MENU;
6653 else if (strcmp ("border", str) == 0)
6654 return META_FRAME_TYPE_BORDER;
6655 else if (strcmp ("attached", str) == 0)
6656 return META_FRAME_TYPE_ATTACHED;
6657#if 0
6658 else if (strcmp ("toolbar", str) == 0)
6659 return META_FRAME_TYPE_TOOLBAR;
6660#endif
6661 else
6662 return META_FRAME_TYPE_LAST;
6663}
6664
6665const char*
6666meta_frame_type_to_string (MetaFrameType type)
6667{
6668 switch (type)
6669 {
6670 case META_FRAME_TYPE_NORMAL:
6671 return "normal";
6672 case META_FRAME_TYPE_DIALOG:
6673 return "dialog";
6674 case META_FRAME_TYPE_MODAL_DIALOG:
6675 return "modal_dialog";
6676 case META_FRAME_TYPE_UTILITY:
6677 return "utility";
6678 case META_FRAME_TYPE_MENU:
6679 return "menu";
6680 case META_FRAME_TYPE_BORDER:
6681 return "border";
6682 case META_FRAME_TYPE_ATTACHED:
6683 return "attached";
6684#if 0
6685 case META_FRAME_TYPE_TOOLBAR:
6686 return "toolbar";
6687#endif
6688 case META_FRAME_TYPE_LAST:
6689 break;
6690 }
6691
6692 return "<unknown>";
6693}
6694
6695MetaGradientType
6696meta_gradient_type_from_string (const char *str)
6697{
6698 if (strcmp ("vertical", str) == 0)
6699 return META_GRADIENT_VERTICAL;
6700 else if (strcmp ("horizontal", str) == 0)
6701 return META_GRADIENT_HORIZONTAL;
6702 else if (strcmp ("diagonal", str) == 0)
6703 return META_GRADIENT_DIAGONAL;
6704 else
6705 return META_GRADIENT_LAST;
6706}
6707
6708const char*
6709meta_gradient_type_to_string (MetaGradientType type)
6710{
6711 switch (type)
6712 {
6713 case META_GRADIENT_VERTICAL:
6714 return "vertical";
6715 case META_GRADIENT_HORIZONTAL:
6716 return "horizontal";
6717 case META_GRADIENT_DIAGONAL:
6718 return "diagonal";
6719 case META_GRADIENT_LAST:
6720 break;
6721 }
6722
6723 return "<unknown>";
6724}
6725
6726GtkStateFlags
6727meta_gtk_state_from_string (const char *str)
6728{
6729 if (g_ascii_strcasecmp ("normal", str) == 0)
6730 return GTK_STATE_FLAG_NORMAL;
6731 else if (g_ascii_strcasecmp ("prelight", str) == 0)
6732 return GTK_STATE_FLAG_PRELIGHT;
6733 else if (g_ascii_strcasecmp ("active", str) == 0)
6734 return GTK_STATE_FLAG_ACTIVE;
6735 else if (g_ascii_strcasecmp ("selected", str) == 0)
6736 return GTK_STATE_FLAG_SELECTED;
6737 else if (g_ascii_strcasecmp ("insensitive", str) == 0)
6738 return GTK_STATE_FLAG_INSENSITIVE;
6739 else if (g_ascii_strcasecmp ("inconsistent", str) == 0)
6740 return GTK_STATE_FLAG_INCONSISTENT;
6741 else if (g_ascii_strcasecmp ("focused", str) == 0)
6742 return GTK_STATE_FLAG_FOCUSED;
6743 else if (g_ascii_strcasecmp ("backdrop", str) == 0)
6744 return GTK_STATE_FLAG_BACKDROP;
6745 else
6746 return -1; /* hack */
6747}
6748
6749GtkShadowType
6750meta_gtk_shadow_from_string (const char *str)
6751{
6752 if (strcmp ("none", str) == 0)
6753 return GTK_SHADOW_NONE;
6754 else if (strcmp ("in", str) == 0)
6755 return GTK_SHADOW_IN;
6756 else if (strcmp ("out", str) == 0)
6757 return GTK_SHADOW_OUT;
6758 else if (strcmp ("etched_in", str) == 0)
6759 return GTK_SHADOW_ETCHED_IN;
6760 else if (strcmp ("etched_out", str) == 0)
6761 return GTK_SHADOW_ETCHED_OUT;
6762 else
6763 return -1;
6764}
6765
6766const char*
6767meta_gtk_shadow_to_string (GtkShadowType shadow)
6768{
6769 switch (shadow)
6770 {
6771 case GTK_SHADOW_NONE:
6772 return "none";
6773 case GTK_SHADOW_IN:
6774 return "in";
6775 case GTK_SHADOW_OUT:
6776 return "out";
6777 case GTK_SHADOW_ETCHED_IN:
6778 return "etched_in";
6779 case GTK_SHADOW_ETCHED_OUT:
6780 return "etched_out";
6781 }
6782
6783 return "<unknown>";
This statement is never executed
6784}
6785
6786GtkArrowType
6787meta_gtk_arrow_from_string (const char *str)
6788{
6789 if (strcmp ("up", str) == 0)
6790 return GTK_ARROW_UP;
6791 else if (strcmp ("down", str) == 0)
6792 return GTK_ARROW_DOWN;
6793 else if (strcmp ("left", str) == 0)
6794 return GTK_ARROW_LEFT;
6795 else if (strcmp ("right", str) == 0)
6796 return GTK_ARROW_RIGHT;
6797 else if (strcmp ("none", str) == 0)
6798 return GTK_ARROW_NONE;
6799 else
6800 return -1;
6801}
6802
6803const char*
6804meta_gtk_arrow_to_string (GtkArrowType arrow)
6805{
6806 switch (arrow)
6807 {
6808 case GTK_ARROW_UP:
6809 return "up";
6810 case GTK_ARROW_DOWN:
6811 return "down";
6812 case GTK_ARROW_LEFT:
6813 return "left";
6814 case GTK_ARROW_RIGHT:
6815 return "right";
6816 case GTK_ARROW_NONE:
6817 return "none";
6818 }
6819
6820 return "<unknown>";
6821}
6822
6823/**
6824 * Returns a fill_type from a string. The inverse of
6825 * meta_image_fill_type_to_string().
6826 *
6827 * \param str a string representing a fill_type
6828 * \result the fill_type, or -1 if it represents no fill_type.
6829 */
6830MetaImageFillType
6831meta_image_fill_type_from_string (const char *str)
6832{
6833 if (strcmp ("tile", str) == 0)
6834 return META_IMAGE_FILL_TILE;
6835 else if (strcmp ("scale", str) == 0)
6836 return META_IMAGE_FILL_SCALE;
6837 else
6838 return -1;
6839}
6840
6841/**
6842 * Returns a string representation of a fill_type. The inverse of
6843 * meta_image_fill_type_from_string().
6844 *
6845 * \param fill_type the fill type
6846 * \result a string representing that type
6847 */
6848const char*
6849meta_image_fill_type_to_string (MetaImageFillType fill_type)
6850{
6851 switch (fill_type)
6852 {
6853 case META_IMAGE_FILL_TILE:
6854 return "tile";
6855 case META_IMAGE_FILL_SCALE:
6856 return "scale";
6857 }
6858
6859 return "<unknown>";
6860}
6861
6862/**
6863 * Takes a colour "a", scales the lightness and saturation by a certain amount,
6864 * and sets "b" to the resulting colour.
6865 * gtkstyle.c cut-and-pastage.
6866 *
6867 * \param a the starting colour
6868 * \param b [out] the resulting colour
6869 * \param k amount to scale lightness and saturation by
6870 */
6871static void
6872gtk_style_shade (GdkRGBA *a,
6873 GdkRGBA *b,
6874 gdouble k)
6875{
6876 gdouble red;
6877 gdouble green;
6878 gdouble blue;
6879
6880 red = a->red;
6881 green = a->green;
6882 blue = a->blue;
6883
6884 rgb_to_hls (&red, &green, &blue);
6885
6886 green *= k;
6887 if (green > 1.0)
6888 green = 1.0;
6889 else if (green < 0.0)
6890 green = 0.0;
6891
6892 blue *= k;
6893 if (blue > 1.0)
6894 blue = 1.0;
6895 else if (blue < 0.0)
6896 blue = 0.0;
6897
6898 hls_to_rgb (&red, &green, &blue);
6899
6900 b->red = red;
6901 b->green = green;
6902 b->blue = blue;
6903}
6904
6905/**
6906 * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
6907 *
6908 * \param r on input, red; on output, hue
6909 * \param g on input, green; on output, lightness
6910 * \param b on input, blue; on output, saturation
6911 */
6912static void
6913rgb_to_hls (gdouble *r,
6914 gdouble *g,
6915 gdouble *b)
6916{
6917 gdouble min;
6918 gdouble max;
6919 gdouble red;
6920 gdouble green;
6921 gdouble blue;
6922 gdouble h, l, s;
6923 gdouble delta;
6924
6925 red = *r;
6926 green = *g;
6927 blue = *b;
6928
6929 if (red > green)
6930 {
6931 if (red > blue)
6932 max = red;
6933 else
6934 max = blue;
6935
6936 if (green < blue)
6937 min = green;
6938 else
6939 min = blue;
6940 }
6941 else
6942 {
6943 if (green > blue)
6944 max = green;
6945 else
6946 max = blue;
6947
6948 if (red < blue)
6949 min = red;
6950 else
6951 min = blue;
6952 }
6953
6954 l = (max + min) / 2;
6955 s = 0;
6956 h = 0;
6957
6958 if (max != min)
6959 {
6960 if (l <= 0.5)
6961 s = (max - min) / (max + min);
6962 else
6963 s = (max - min) / (2 - max - min);
6964
6965 delta = max -min;
6966 if (red == max)
6967 h = (green - blue) / delta;
6968 else if (green == max)
6969 h = 2 + (blue - red) / delta;
6970 else if (blue == max)
6971 h = 4 + (red - green) / delta;
6972
6973 h *= 60;
6974 if (h < 0.0)
6975 h += 360;
6976 }
6977
6978 *r = h;
6979 *g = l;
6980 *b = s;
6981}
6982
6983/**
6984 * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
6985 *
6986 * \param h on input, hue; on output, red
6987 * \param l on input, lightness; on output, green
6988 * \param s on input, saturation; on output, blue
6989 */
6990static void
6991hls_to_rgb (gdouble *h,
6992 gdouble *l,
6993 gdouble *s)
6994{
6995 gdouble hue;
6996 gdouble lightness;
6997 gdouble saturation;
6998 gdouble m1, m2;
6999 gdouble r, g, b;
7000
7001 lightness = *l;
7002 saturation = *s;
7003
7004 if (lightness <= 0.5)
7005 m2 = lightness * (1 + saturation);
7006 else
7007 m2 = lightness + saturation - lightness * saturation;
7008 m1 = 2 * lightness - m2;
7009
7010 if (saturation == 0)
7011 {
7012 *h = lightness;
7013 *l = lightness;
7014 *s = lightness;
7015 }
7016 else
7017 {
7018 hue = *h + 120;
7019 while (hue > 360)
7020 hue -= 360;
7021 while (hue < 0)
7022 hue += 360;
7023
7024 if (hue < 60)
7025 r = m1 + (m2 - m1) * hue / 60;
7026 else if (hue < 180)
7027 r = m2;
7028 else if (hue < 240)
7029 r = m1 + (m2 - m1) * (240 - hue) / 60;
7030 else
7031 r = m1;
7032
7033 hue = *h;
7034 while (hue > 360)
7035 hue -= 360;
7036 while (hue < 0)
7037 hue += 360;
7038
7039 if (hue < 60)
7040 g = m1 + (m2 - m1) * hue / 60;
7041 else if (hue < 180)
7042 g = m2;
7043 else if (hue < 240)
7044 g = m1 + (m2 - m1) * (240 - hue) / 60;
7045 else
7046 g = m1;
7047
7048 hue = *h - 120;
7049 while (hue > 360)
7050 hue -= 360;
7051 while (hue < 0)
7052 hue += 360;
7053
7054 if (hue < 60)
7055 b = m1 + (m2 - m1) * hue / 60;
7056 else if (hue < 180)
7057 b = m2;
7058 else if (hue < 240)
7059 b = m1 + (m2 - m1) * (240 - hue) / 60;
7060 else
7061 b = m1;
7062
7063 *h = r;
7064 *l = g;
7065 *s = b;
7066 }
7067}
7068
7069#if 0
7070/* These are some functions I'm saving to use in optimizing
7071 * MetaDrawOpList, namely to pre-composite pixbufs on client side
7072 * prior to rendering to the server
7073 */
7074static void
7075draw_bg_solid_composite (const MetaTextureSpec *bg,
7076 const MetaTextureSpec *fg,
7077 double alpha,
7078 GtkWidget *widget,
7079 GdkDrawable *drawable,
7080 const GdkRectangle *clip,
7081 MetaTextureDrawMode mode,
7082 double xalign,
7083 double yalign,
7084 int x,
7085 int y,
7086 int width,
7087 int height)
7088{
7089 GdkColor bg_color;
7090
7091 g_assert (bg->type == META_TEXTURE_SOLID)do { if (bg->type == META_TEXTURE_SOLID) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7091, ((const char*) (__func__)), "bg->type == META_TEXTURE_SOLID"
); } while (0)
;
7092 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7092, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7093 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7093, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7094
7095 meta_color_spec_render (bg->data.solid.color_spec,
7096 widget,
7097 &bg_color);
7098
7099 switch (fg->type)
7100 {
7101 case META_TEXTURE_SOLID:
7102 {
7103 GdkColor fg_color;
7104
7105 meta_color_spec_render (fg->data.solid.color_spec,
7106 widget,
7107 &fg_color);
7108
7109 color_composite (&bg_color, &fg_color,
7110 alpha, &fg_color);
7111
7112 draw_color_rectangle (widget, drawable, &fg_color, clip,
7113 x, y, width, height);
7114 }
7115 break;
7116
7117 case META_TEXTURE_GRADIENT:
7118 /* FIXME I think we could just composite all the colors in
7119 * the gradient prior to generating the gradient?
7120 */
7121 /* FALL THRU */
7122 case META_TEXTURE_IMAGE:
7123 {
7124 GdkPixbuf *pixbuf;
7125 GdkPixbuf *composited;
7126
7127 pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7128 width, height);
7129
7130 if (pixbuf == NULL((void*)0))
7131 return;
7132
7133 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7134 gdk_pixbuf_get_has_alpha (pixbuf), 8,
7135 gdk_pixbuf_get_width (pixbuf),
7136 gdk_pixbuf_get_height (pixbuf));
7137
7138 if (composited == NULL((void*)0))
7139 {
7140 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7141 return;
7142 }
7143
7144 gdk_pixbuf_composite_color (pixbuf,
7145 composited,
7146 0, 0,
7147 gdk_pixbuf_get_width (pixbuf),
7148 gdk_pixbuf_get_height (pixbuf),
7149 0.0, 0.0, /* offsets */
7150 1.0, 1.0, /* scale */
7151 GDK_INTERP_BILINEAR,
7152 255 * alpha,
7153 0, 0, /* check offsets */
7154 0, /* check size */
7155 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
,
7156 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
);
7157
7158 /* Need to draw background since pixbuf is not
7159 * necessarily covering the whole thing
7160 */
7161 draw_color_rectangle (widget, drawable, &bg_color, clip,
7162 x, y, width, height);
7163
7164 render_pixbuf_aligned (drawable, clip, composited,
7165 xalign, yalign,
7166 x, y, width, height);
7167
7168 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7169 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7170 }
7171 break;
7172
7173 case META_TEXTURE_BLANK:
7174 case META_TEXTURE_COMPOSITE:
7175 case META_TEXTURE_SHAPE_LIST:
7176 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7176, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7177 break;
7178 }
7179}
7180
7181static void
7182draw_bg_gradient_composite (const MetaTextureSpec *bg,
7183 const MetaTextureSpec *fg,
7184 double alpha,
7185 GtkWidget *widget,
7186 GdkDrawable *drawable,
7187 const GdkRectangle *clip,
7188 MetaTextureDrawMode mode,
7189 double xalign,
7190 double yalign,
7191 int x,
7192 int y,
7193 int width,
7194 int height)
7195{
7196 g_assert (bg->type == META_TEXTURE_GRADIENT)do { if (bg->type == META_TEXTURE_GRADIENT) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7196, ((const char*) (__func__)), "bg->type == META_TEXTURE_GRADIENT"
); } while (0)
;
7197 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7197, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7198 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7198, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7199
7200 switch (fg->type)
7201 {
7202 case META_TEXTURE_SOLID:
7203 case META_TEXTURE_GRADIENT:
7204 case META_TEXTURE_IMAGE:
7205 {
7206 GdkPixbuf *bg_pixbuf;
7207 GdkPixbuf *fg_pixbuf;
7208 GdkPixbuf *composited;
7209 int fg_width, fg_height;
7210
7211 bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255,
7212 width, height);
7213
7214 if (bg_pixbuf == NULL((void*)0))
7215 return;
7216
7217 fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7218 width, height);
7219
7220 if (fg_pixbuf == NULL((void*)0))
7221 {
7222 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7223 return;
7224 }
7225
7226 /* gradients always fill the entire target area */
7227 g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width)do { if (gdk_pixbuf_get_width (bg_pixbuf) == width) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7227, ((const char*) (__func__)), "gdk_pixbuf_get_width (bg_pixbuf) == width"
); } while (0)
;
7228 g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height)do { if (gdk_pixbuf_get_height (bg_pixbuf) == height) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7228, ((const char*) (__func__)), "gdk_pixbuf_get_height (bg_pixbuf) == height"
); } while (0)
;
7229
7230 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7231 gdk_pixbuf_get_has_alpha (bg_pixbuf), 8,
7232 gdk_pixbuf_get_width (bg_pixbuf),
7233 gdk_pixbuf_get_height (bg_pixbuf));
7234
7235 if (composited == NULL((void*)0))
7236 {
7237 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7238 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7239 return;
7240 }
7241
7242 fg_width = gdk_pixbuf_get_width (fg_pixbuf);
7243 fg_height = gdk_pixbuf_get_height (fg_pixbuf);
7244
7245 /* If we wanted to be all cool we could deal with the
7246 * offsets and try to composite only in the clip rectangle,
7247 * but I just don't care enough to figure it out.
7248 */
7249
7250 gdk_pixbuf_composite (fg_pixbuf,
7251 composited,
7252 x + (width - fg_width) * xalign,
7253 y + (height - fg_height) * yalign,
7254 gdk_pixbuf_get_width (fg_pixbuf),
7255 gdk_pixbuf_get_height (fg_pixbuf),
7256 0.0, 0.0, /* offsets */
7257 1.0, 1.0, /* scale */
7258 GDK_INTERP_BILINEAR,
7259 255 * alpha);
7260
7261 gdk_cairo_set_source_pixbuf (cr, composited, x, y);
7262 cairo_paint (cr);
7263
7264 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7265 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7266 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7267 }
7268 break;
7269
7270 case META_TEXTURE_BLANK:
7271 case META_TEXTURE_SHAPE_LIST:
7272 case META_TEXTURE_COMPOSITE:
7273 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7273, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7274 break;
7275 }
7276}
7277#endif
7278
7279/**
7280 * Returns the earliest version of the theme format which required support
7281 * for a particular button. (For example, "shade" first appeared in v2, and
7282 * "close" in v1.)
7283 *
7284 * \param type the button type
7285 * \return the number of the theme format
7286 */
7287guint
7288meta_theme_earliest_version_with_button (MetaButtonType type)
7289{
7290 switch (type)
7291 {
7292 case META_BUTTON_TYPE_CLOSE:
7293 case META_BUTTON_TYPE_MAXIMIZE:
7294 case META_BUTTON_TYPE_MINIMIZE:
7295 case META_BUTTON_TYPE_MENU:
7296 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
7297 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
7298 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
7299 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
7300 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
7301 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
7302 return 1000;
7303
7304 case META_BUTTON_TYPE_SHADE:
7305 case META_BUTTON_TYPE_ABOVE:
7306 case META_BUTTON_TYPE_STICK:
7307 case META_BUTTON_TYPE_UNSHADE:
7308 case META_BUTTON_TYPE_UNABOVE:
7309 case META_BUTTON_TYPE_UNSTICK:
7310 return 2000;
7311
7312 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
7313 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
7314 return 3003;
7315
7316 case META_BUTTON_TYPE_APPMENU:
7317 return 3005;
7318
7319 default:
7320 meta_warning("Unknown button %d\n", type);
7321 return 1000;
7322 }
7323}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-dac1a9.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-dac1a9.html new file mode 100644 index 00000000..ca6be004 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-dac1a9.html @@ -0,0 +1,9762 @@ + + + +core/window.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/window.c
Warning:line 1625, column 18
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'copy')
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name window.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/window.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco X managed windows */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington, Anders Carlsson
7 * Copyright (C) 2002, 2003 Red Hat, Inc.
8 * Copyright (C) 2003 Rob Adams
9 * Copyright (C) 2004-2006 Elijah Newren
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * 02110-1301, USA.
25 */
26
27#include <config.h>
28#include <glib/gi18n-lib.h>
29
30#include "window-private.h"
31#include "edge-resistance.h"
32#include "util.h"
33#include "frame-private.h"
34#include "errors.h"
35#include "workspace.h"
36#include "stack.h"
37#include "keybindings.h"
38#include "ui.h"
39#include "place.h"
40#include "session.h"
41#include "effects.h"
42#include "prefs.h"
43#include "resizepopup.h"
44#include "xprops.h"
45#include "group.h"
46#include "window-props.h"
47#include "constraints.h"
48#include "compositor.h"
49#include "effects.h"
50
51#include <X11/Xatom.h>
52#include <X11/Xlibint.h> /* For display->resource_mask */
53#include <string.h>
54
55#ifdef HAVE_SHAPE
56#include <X11/extensions/shape.h>
57#endif
58
59static int destroying_windows_disallowed = 0;
60
61static void update_sm_hints (MetaWindow *window);
62static void update_net_frame_extents (MetaWindow *window);
63static void recalc_window_type (MetaWindow *window);
64static void recalc_window_features (MetaWindow *window);
65static void invalidate_work_areas (MetaWindow *window);
66static void recalc_window_type (MetaWindow *window);
67static void set_wm_state (MetaWindow *window,
68 int state);
69static void set_net_wm_state (MetaWindow *window);
70static void set_allowed_actions_hint (MetaWindow *window);
71static void send_configure_notify (MetaWindow *window);
72static gboolean process_property_notify (MetaWindow *window,
73 XPropertyEvent *event);
74static void meta_window_show (MetaWindow *window);
75static void meta_window_hide (MetaWindow *window);
76
77static gboolean meta_window_same_client (MetaWindow *window,
78 MetaWindow *other_window);
79
80static void meta_window_save_rect (MetaWindow *window);
81static void save_user_window_placement (MetaWindow *window);
82static void force_save_user_window_placement (MetaWindow *window);
83
84static void meta_window_move_resize_internal (MetaWindow *window,
85 MetaMoveResizeFlags flags,
86 int resize_gravity,
87 int root_x_nw,
88 int root_y_nw,
89 int w,
90 int h);
91
92static void ensure_mru_position_after (MetaWindow *window,
93 MetaWindow *after_this_one);
94
95static void meta_window_move_resize_now (MetaWindow *window);
96
97static void meta_window_unqueue (MetaWindow *window, guint queuebits);
98
99static void update_move (MetaWindow *window,
100 gboolean snap,
101 int x,
102 int y);
103static gboolean update_move_timeout (gpointer data);
104static void update_resize (MetaWindow *window,
105 gboolean snap,
106 int x,
107 int y,
108 gboolean force);
109
110static MetaTileMode calculate_tiling_mode(int x,
111 int y,
112 MetaWindow *window,
113 const MetaXineramaScreenInfo *monitor,
114 MetaRectangle work_area,
115 int shake_threshold);
116
117static void meta_window_transform_to_monitor (MetaRectangle *target_rect,
118 const MetaRectangle *from_monitor,
119 const MetaRectangle *to_monitor);
120
121static gboolean update_resize_timeout (gpointer data);
122
123static void meta_window_flush_calc_showing (MetaWindow *window);
124
125static gboolean queue_calc_showing_func (MetaWindow *window,
126 void *data);
127
128static void meta_window_apply_session_info (MetaWindow *window,
129 const MetaWindowSessionInfo *info);
130
131static void unmaximize_window_before_freeing (MetaWindow *window);
132static void unminimize_window_and_all_transient_parents (MetaWindow *window);
133
134/* Idle handlers for the three queues. The "data" parameter in each case
135 * will be a GINT_TO_POINTER of the index into the queue arrays to use.
136 *
137 * TODO: Possibly there is still some code duplication among these, which we
138 * need to sort out at some point.
139 */
140static gboolean idle_calc_showing (gpointer data);
141static gboolean idle_move_resize (gpointer data);
142static gboolean idle_update_icon (gpointer data);
143
144G_DEFINE_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT)static void meta_window_init (MetaWindow *self); static void meta_window_class_init
(MetaWindowClass *klass); static GType meta_window_get_type_once
(void); static gpointer meta_window_parent_class = ((void*)0
); static gint MetaWindow_private_offset; static void meta_window_class_intern_init
(gpointer klass) { meta_window_parent_class = g_type_class_peek_parent
(klass); if (MetaWindow_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MetaWindow_private_offset); meta_window_class_init
((MetaWindowClass*) klass); } __attribute__ ((__unused__)) static
inline gpointer meta_window_get_instance_private (MetaWindow
*self) { return (((gpointer) ((guint8*) (self) + (glong) (MetaWindow_private_offset
)))); } GType meta_window_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = meta_window_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType meta_window_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("MetaWindow"
), sizeof (MetaWindowClass), (GClassInitFunc)(void (*)(void))
meta_window_class_intern_init, sizeof (MetaWindow), (GInstanceInitFunc
)(void (*)(void)) meta_window_init, (GTypeFlags) 0); { {{};} }
return g_define_type_id; }
145
146#ifdef WITH_VERBOSE_MODE1
147static const char*
148wm_state_to_string (int state)
149{
150 switch (state)
151 {
152 case NormalState1:
153 return "NormalState";
154 case IconicState3:
155 return "IconicState";
156 case WithdrawnState0:
157 return "WithdrawnState";
158 }
159
160 return "Unknown";
161}
162#endif
163
164static gboolean
165is_desktop_or_dock_foreach (MetaWindow *window,
166 void *data)
167{
168 gboolean *result = data;
169
170 *result =
171 window->type == META_WINDOW_DESKTOP ||
172 window->type == META_WINDOW_DOCK;
173 if (*result)
174 return FALSE(0); /* stop as soon as we find one */
175 else
176 return TRUE(!(0));
177}
178
179/* window is the window that's newly mapped provoking
180 * the possible change
181 */
182static void
183maybe_leave_show_desktop_mode (MetaWindow *window)
184{
185 gboolean is_desktop_or_dock;
186
187 if (!window->screen->active_workspace->showing_desktop)
188 return;
189
190 /* If the window is a transient for the dock or desktop, don't
191 * leave show desktop mode when the window opens. That's
192 * so you can e.g. hide all windows, manipulate a file on
193 * the desktop via a dialog, then unshow windows again.
194 */
195 is_desktop_or_dock = FALSE(0);
196 is_desktop_or_dock_foreach (window,
197 &is_desktop_or_dock);
198
199 meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
200 &is_desktop_or_dock);
201
202 if (!is_desktop_or_dock)
203 {
204 meta_screen_minimize_all_on_active_workspace_except (window->screen,
205 window);
206 meta_screen_unshow_desktop (window->screen);
207 }
208}
209
210MetaWindow*
211meta_window_new (MetaDisplay *display,
212 Window xwindow,
213 gboolean must_be_viewable)
214{
215 XWindowAttributes attrs;
216 MetaWindow *window;
217
218 meta_display_grab (display);
219 meta_error_trap_push (display); /* Push a trap over all of window
220 * creation, to reduce XSync() calls
221 */
222
223 meta_error_trap_push (display);
224
225 if (XGetWindowAttributes (display->xdisplay,xwindow, &attrs))
226 {
227 if(meta_error_trap_pop_with_return (display, TRUE(!(0))) != Success0)
228 {
229 meta_verbosemeta_verbose_real ("Failed to get attributes for window 0x%lx\n",
230 xwindow);
231 meta_error_trap_pop (display, TRUE(!(0)));
232 meta_display_ungrab (display);
233 return NULL((void*)0);
234 }
235 window = meta_window_new_with_attrs (display, xwindow,
236 must_be_viewable, &attrs);
237 }
238 else
239 {
240 meta_error_trap_pop_with_return (display, TRUE(!(0)));
241 meta_verbosemeta_verbose_real ("Failed to get attributes for window 0x%lx\n",
242 xwindow);
243 meta_error_trap_pop (display, TRUE(!(0)));
244 meta_display_ungrab (display);
245 return NULL((void*)0);
246 }
247
248 meta_error_trap_pop (display, FALSE(0));
249 meta_display_ungrab (display);
250
251 return window;
252}
253
254MetaWindow*
255meta_window_new_with_attrs (MetaDisplay *display,
256 Window xwindow,
257 gboolean must_be_viewable,
258 XWindowAttributes *attrs)
259{
260 MetaWindow *window;
261 GSList *tmp;
262 MetaWorkspace *space;
263 gulong existing_wm_state;
264 gulong event_mask;
265 MetaMoveResizeFlags flags;
266#define N_INITIAL_PROPS22 22
267 Atom initial_props[N_INITIAL_PROPS22];
268 int i;
269 gboolean has_shape;
270
271 g_assert (attrs != NULL)do { if (attrs != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/window.c", 271, ((const char*) (__func__)), "attrs != NULL"
); } while (0)
;
272 g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props))do { if (22 == (int) (sizeof (initial_props) / sizeof ((initial_props
)[0]))) ; else g_assertion_message_expr ("marco", "core/window.c"
, 272, ((const char*) (__func__)), "N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props)"
); } while (0)
;
273
274 meta_verbosemeta_verbose_real ("Attempting to manage 0x%lx\n", xwindow);
275
276 if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
277 {
278 meta_verbosemeta_verbose_real ("Not managing no_focus_window 0x%lx\n",
279 xwindow);
280 return NULL((void*)0);
281 }
282
283 if (attrs->override_redirect)
284 {
285 meta_verbosemeta_verbose_real ("Deciding not to manage override_redirect window 0x%lx\n", xwindow);
286 return NULL((void*)0);
287 }
288
289 /* Grab server */
290 meta_display_grab (display);
291 meta_error_trap_push (display); /* Push a trap over all of window
292 * creation, to reduce XSync() calls
293 */
294
295 meta_verbosemeta_verbose_real ("must_be_viewable = %d attrs->map_state = %d (%s)\n",
296 must_be_viewable,
297 attrs->map_state,
298 (attrs->map_state == IsUnmapped0) ?
299 "IsUnmapped" :
300 (attrs->map_state == IsViewable2) ?
301 "IsViewable" :
302 (attrs->map_state == IsUnviewable1) ?
303 "IsUnviewable" :
304 "(unknown)");
305
306 existing_wm_state = WithdrawnState0;
307 if (must_be_viewable && attrs->map_state != IsViewable2)
308 {
309 /* Only manage if WM_STATE is IconicState or NormalState */
310 gulong state;
311
312 /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
313 if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
314 display->atom_WM_STATE,
315 display->atom_WM_STATE,
316 &state) &&
317 (state == IconicState3 || state == NormalState1)))
318 {
319 meta_verbosemeta_verbose_real ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
320 meta_error_trap_pop (display, TRUE(!(0)));
321 meta_display_ungrab (display);
322 return NULL((void*)0);
323 }
324
325 existing_wm_state = state;
326 meta_verbosemeta_verbose_real ("WM_STATE of %lx = %s\n", xwindow,
327 wm_state_to_string (existing_wm_state));
328 }
329
330 meta_error_trap_push (display);
331
332 XAddToSaveSet (display->xdisplay, xwindow);
333
334 event_mask =
335 PropertyChangeMask(1L<<22) | EnterWindowMask(1L<<4) | LeaveWindowMask(1L<<5) |
336 FocusChangeMask(1L<<21) | ColormapChangeMask(1L<<23);
337
338 XSelectInput (display->xdisplay, xwindow, event_mask);
339
340 has_shape = FALSE(0);
341#ifdef HAVE_SHAPE
342 if (META_DISPLAY_HAS_SHAPE (display)((display)->have_shape))
343 {
344 int x_bounding, y_bounding, x_clip, y_clip;
345 unsigned w_bounding, h_bounding, w_clip, h_clip;
346 int bounding_shaped, clip_shaped;
347
348 XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask(1L << 0));
349
350 XShapeQueryExtents (display->xdisplay, xwindow,
351 &bounding_shaped, &x_bounding, &y_bounding,
352 &w_bounding, &h_bounding,
353 &clip_shaped, &x_clip, &y_clip,
354 &w_clip, &h_clip);
355
356 has_shape = bounding_shaped != FALSE(0);
357
358 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
359 "Window has_shape = %d extents %d,%d %u x %u\n",
360 has_shape, x_bounding, y_bounding,
361 w_bounding, h_bounding);
362 }
363#endif
364
365 /* Get rid of any borders */
366 if (attrs->border_width != 0)
367 XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
368
369 /* Get rid of weird gravities */
370 if (attrs->win_gravity != NorthWestGravity1)
371 {
372 XSetWindowAttributes set_attrs;
373
374 set_attrs.win_gravity = NorthWestGravity1;
375
376 XChangeWindowAttributes (display->xdisplay,
377 xwindow,
378 CWWinGravity(1L<<5),
379 &set_attrs);
380 }
381
382 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
383 {
384 meta_verbosemeta_verbose_real ("Window 0x%lx disappeared just as we tried to manage it\n",
385 xwindow);
386 meta_error_trap_pop (display, FALSE(0));
387 meta_display_ungrab (display);
388 return NULL((void*)0);
389 }
390
391 g_assert (!attrs->override_redirect)do { if (!attrs->override_redirect) ; else g_assertion_message_expr
("marco", "core/window.c", 391, ((const char*) (__func__)), "!attrs->override_redirect"
); } while (0)
;
392
393 window = g_object_new (META_TYPE_WINDOWmeta_window_get_type (), NULL((void*)0));
394
395 window->constructing = TRUE(!(0));
396
397 window->dialog_pid = -1;
398
399 window->xwindow = xwindow;
400
401 /* this is in window->screen->display, but that's too annoying to
402 * type
403 */
404 window->display = display;
405 window->workspace = NULL((void*)0);
406
407#ifdef HAVE_XSYNC
408 window->sync_request_counter = None0L;
409 window->sync_request_serial = 0;
410 window->sync_request_time = 0;
411#endif
412
413 window->screen = NULL((void*)0);
414 tmp = display->screens;
415 while (tmp != NULL((void*)0))
416 {
417 MetaScreen *scr = tmp->data;
418
419 if (scr->xroot == attrs->root)
420 {
421 window->screen = tmp->data;
422 break;
423 }
424
425 tmp = tmp->next;
426 }
427
428 g_assert (window->screen)do { if (window->screen) ; else g_assertion_message_expr (
"marco", "core/window.c", 428, ((const char*) (__func__)), "window->screen"
); } while (0)
;
429
430 window->desc = g_strdup_printf ("0x%lx", window->xwindow);
431
432 /* avoid tons of stack updates */
433 meta_stack_freeze (window->screen->stack);
434
435 window->has_shape = (has_shape != FALSE(0));
436
437 window->rect.x = attrs->x;
438 window->rect.y = attrs->y;
439 window->rect.width = attrs->width;
440 window->rect.height = attrs->height;
441
442 /* And border width, size_hints are the "request" */
443 window->border_width = attrs->border_width;
444 window->size_hints.x = attrs->x;
445 window->size_hints.y = attrs->y;
446 window->size_hints.width = attrs->width;
447 window->size_hints.height = attrs->height;
448 /* initialize the remaining size_hints as if size_hints.flags were zero */
449 meta_set_normal_hints (window, NULL((void*)0));
450
451 window->has_custom_frame_extents = FALSE(0);
452 window->custom_frame_extents.left = 0;
453 window->custom_frame_extents.right = 0;
454 window->custom_frame_extents.top = 0;
455 window->custom_frame_extents.bottom = 0;
456
457 /* And this is our unmaximized size */
458 window->saved_rect = window->rect;
459 window->user_rect = window->rect;
460
461 window->depth = attrs->depth;
462 window->xvisual = attrs->visual;
463 window->colormap = attrs->colormap;
464
465 window->title = NULL((void*)0);
466 window->icon_name = NULL((void*)0);
467 window->icon = NULL((void*)0);
468 window->mini_icon = NULL((void*)0);
469 meta_icon_cache_init (&window->icon_cache);
470 window->wm_hints_pixmap = None0L;
471 window->wm_hints_mask = None0L;
472
473 window->frame = NULL((void*)0);
474 window->has_focus = FALSE(0);
475
476 window->maximized_horizontally = FALSE(0);
477 window->maximized_vertically = FALSE(0);
478 window->maximize_horizontally_after_placement = FALSE(0);
479 window->maximize_vertically_after_placement = FALSE(0);
480 window->minimize_after_placement = FALSE(0);
481 window->move_after_placement = FALSE(0);
482 window->fullscreen = FALSE(0);
483 window->fullscreen_after_placement = FALSE(0);
484 window->fullscreen_monitors[0] = -1;
485 window->require_fully_onscreen = TRUE(!(0));
486 window->require_on_single_xinerama = TRUE(!(0));
487 window->require_titlebar_visible = TRUE(!(0));
488 window->on_all_workspaces = FALSE(0);
489 window->tile_mode = META_TILE_NONE;
490 window->tile_resized = FALSE(0);
491 window->tile_monitor_number = -1;
492 window->shaded = FALSE(0);
493 window->initially_iconic = FALSE(0);
494 window->minimized = FALSE(0);
495 window->was_minimized = FALSE(0);
496 window->tab_unminimized = FALSE(0);
497 window->iconic = FALSE(0);
498 window->mapped = attrs->map_state != IsUnmapped0;
499 /* if already mapped, no need to worry about focus-on-first-time-showing */
500 window->showing_for_first_time = !window->mapped;
501 /* if already mapped we don't want to do the placement thing */
502 window->placed = window->mapped;
503 if (window->placed)
504 meta_topicmeta_topic_real (META_DEBUG_PLACEMENT,
505 "Not placing window 0x%lx since it's already mapped\n",
506 xwindow);
507 window->force_save_user_rect = TRUE(!(0));
508 window->denied_focus_and_not_transient = FALSE(0);
509 window->unmanaging = FALSE(0);
510 window->is_in_queues = 0;
511 window->keys_grabbed = FALSE(0);
512 window->grab_on_frame = FALSE(0);
513 window->all_keys_grabbed = FALSE(0);
514 window->withdrawn = FALSE(0);
515 window->initial_workspace_set = FALSE(0);
516 window->initial_timestamp_set = FALSE(0);
517 window->net_wm_user_time_set = FALSE(0);
518 window->user_time_window = None0L;
519 window->take_focus = FALSE(0);
520 window->input = TRUE(!(0));
521 window->calc_placement = FALSE(0);
522 window->shaken_loose = FALSE(0);
523 window->have_focus_click_grab = FALSE(0);
524 window->disable_sync = FALSE(0);
525 window->frame_bounds = NULL((void*)0);
526
527 window->unmaps_pending = 0;
528
529 window->mwm_decorated = TRUE(!(0));
530 window->mwm_border_only = FALSE(0);
531 window->mwm_has_close_func = TRUE(!(0));
532 window->mwm_has_minimize_func = TRUE(!(0));
533 window->mwm_has_maximize_func = TRUE(!(0));
534 window->mwm_has_move_func = TRUE(!(0));
535 window->mwm_has_resize_func = TRUE(!(0));
536
537 window->decorated = TRUE(!(0));
538 window->has_close_func = TRUE(!(0));
539 window->has_minimize_func = TRUE(!(0));
540 window->has_maximize_func = TRUE(!(0));
541 window->has_move_func = TRUE(!(0));
542 window->has_resize_func = TRUE(!(0));
543
544 window->has_shade_func = TRUE(!(0));
545
546 window->has_fullscreen_func = TRUE(!(0));
547
548 window->always_sticky = FALSE(0);
549
550 window->wm_state_modal = FALSE(0);
551 window->skip_taskbar = FALSE(0);
552 window->skip_pager = FALSE(0);
553 window->wm_state_skip_taskbar = FALSE(0);
554 window->wm_state_skip_pager = FALSE(0);
555 window->wm_state_above = FALSE(0);
556 window->wm_state_below = FALSE(0);
557 window->wm_state_demands_attention = FALSE(0);
558
559 window->res_class = NULL((void*)0);
560 window->res_name = NULL((void*)0);
561 window->role = NULL((void*)0);
562 window->sm_client_id = NULL((void*)0);
563 window->wm_client_machine = NULL((void*)0);
564 window->startup_id = NULL((void*)0);
565 window->gtk_theme_variant = NULL((void*)0);
566 window->gtk_application_id = NULL((void*)0);
567 window->bamf_desktop_file = NULL((void*)0);
568
569 window->net_wm_pid = -1;
570
571 window->xtransient_for = None0L;
572 window->xclient_leader = None0L;
573 window->transient_parent_is_root_window = FALSE(0);
574
575 window->type = META_WINDOW_NORMAL;
576 window->type_atom = None0L;
577
578 window->struts = NULL((void*)0);
579
580 window->using_net_wm_name = FALSE(0);
581 window->using_net_wm_visible_name = FALSE(0);
582 window->using_net_wm_icon_name = FALSE(0);
583 window->using_net_wm_visible_icon_name = FALSE(0);
584
585 window->need_reread_icon = TRUE(!(0));
586
587 window->layer = META_LAYER_LAST; /* invalid value */
588 window->stack_position = -1;
589 window->initial_workspace = 0; /* not used */
590 window->initial_timestamp = 0; /* not used */
591
592 meta_display_register_x_window (display, &window->xwindow, window);
593
594 /* assign the window to its group, or create a new group if needed
595 */
596 window->group = NULL((void*)0);
597 window->xgroup_leader = None0L;
598 meta_window_compute_group (window);
599
600 /* Fill these in the order we want them to be gotten. we want to
601 * get window name and class first so we can use them in error
602 * messages and such. However, name is modified depending on
603 * wm_client_machine, so push it slightly sooner.
604 */
605 i = 0;
606 initial_props[i++] = display->atom_WM_CLIENT_MACHINE;
607 initial_props[i++] = display->atom__NET_WM_PID;
608 initial_props[i++] = display->atom__NET_WM_NAME;
609 initial_props[i++] = XA_WM_CLASS((Atom) 67);
610 initial_props[i++] = XA_WM_NAME((Atom) 39);
611 initial_props[i++] = display->atom__NET_WM_ICON_NAME;
612 initial_props[i++] = XA_WM_ICON_NAME((Atom) 37);
613 initial_props[i++] = display->atom__NET_WM_DESKTOP;
614 initial_props[i++] = display->atom__NET_STARTUP_ID;
615 initial_props[i++] = display->atom__NET_WM_SYNC_REQUEST_COUNTER;
616 initial_props[i++] = XA_WM_NORMAL_HINTS((Atom) 40);
617 initial_props[i++] = display->atom_WM_PROTOCOLS;
618 initial_props[i++] = XA_WM_HINTS((Atom) 35);
619 initial_props[i++] = display->atom__NET_WM_USER_TIME;
620 initial_props[i++] = display->atom__NET_WM_STATE;
621 initial_props[i++] = display->atom__MOTIF_WM_HINTS;
622 initial_props[i++] = XA_WM_TRANSIENT_FOR((Atom) 68);
623 initial_props[i++] = display->atom__NET_WM_USER_TIME_WINDOW;
624 initial_props[i++] = display->atom__NET_WM_FULLSCREEN_MONITORS;
625 initial_props[i++] = display->atom__GTK_THEME_VARIANT;
626 initial_props[i++] = display->atom__GTK_APPLICATION_ID;
627 initial_props[i++] = display->atom__BAMF_DESKTOP_FILE;
628 g_assert (N_INITIAL_PROPS == i)do { if (22 == i) ; else g_assertion_message_expr ("marco", "core/window.c"
, 628, ((const char*) (__func__)), "N_INITIAL_PROPS == i"); }
while (0)
;
629
630 meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS22, TRUE(!(0)));
631
632 update_sm_hints (window); /* must come after transient_for */
633 meta_window_update_role (window);
634 meta_window_update_net_wm_type (window);
635 meta_window_update_icon_now (window);
636
637 if (window->initially_iconic)
638 {
639 /* WM_HINTS said minimized */
640 window->minimized = TRUE(!(0));
641 meta_verbosemeta_verbose_real ("Window %s asked to start out minimized\n", window->desc);
642 }
643
644 if (existing_wm_state == IconicState3)
645 {
646 /* WM_STATE said minimized */
647 window->minimized = TRUE(!(0));
648 meta_verbosemeta_verbose_real ("Window %s had preexisting WM_STATE = IconicState, minimizing\n",
649 window->desc);
650
651 /* Assume window was previously placed, though perhaps it's
652 * been iconic its whole life, we have no way of knowing.
653 */
654 window->placed = TRUE(!(0));
655 }
656
657 /* Apply any window attributes such as initial workspace
658 * based on startup notification
659 */
660 meta_screen_apply_startup_properties (window->screen, window);
661
662 /* Try to get a "launch timestamp" for the window. If the window is
663 * a transient, we'd like to be able to get a last-usage timestamp
664 * from the parent window. If the window has no parent, there isn't
665 * much we can do...except record the current time so that any children
666 * can use this time as a fallback.
667 */
668 if (!window->net_wm_user_time_set) {
669 MetaWindow *parent = NULL((void*)0);
670 if (window->xtransient_for)
671 parent = meta_display_lookup_x_window (window->display,
672 window->xtransient_for);
673
674 /* First, maybe the app was launched with startup notification using an
675 * obsolete version of the spec; use that timestamp if it exists.
676 */
677 if (window->initial_timestamp_set)
678 /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
679 * being recorded as a fallback for potential transients
680 */
681 window->net_wm_user_time = window->initial_timestamp;
682 else if (parent != NULL((void*)0))
683 meta_window_set_user_time(window, parent->net_wm_user_time);
684 else
685 /* NOTE: Do NOT toggle net_wm_user_time_set to true; this is just
686 * being recorded as a fallback for potential transients
687 */
688 window->net_wm_user_time =
689 meta_display_get_current_time_roundtrip (window->display);
690 }
691
692 if (window->decorated)
693 meta_window_ensure_frame (window);
694
695 meta_window_grab_keys (window);
696 if (window->type != META_WINDOW_DOCK)
697 {
698 meta_display_grab_window_buttons (window->display, window->xwindow);
699 meta_display_grab_focus_window_button (window->display, window);
700 }
701
702 if (window->type == META_WINDOW_DESKTOP ||
703 window->type == META_WINDOW_DOCK)
704 {
705 /* Change the default, but don't enforce this if the user
706 * focuses the dock/desktop and unsticks it using key shortcuts.
707 * Need to set this before adding to the workspaces so the MRU
708 * lists will be updated.
709 */
710 window->on_all_workspaces = TRUE(!(0));
711 }
712
713 /* For the workspace, first honor hints,
714 * if that fails put transients with parents,
715 * otherwise put window on active space
716 */
717
718 if (window->initial_workspace_set)
719 {
720 if (window->initial_workspace == (int) 0xFFFFFFFF)
721 {
722 meta_topicmeta_topic_real (META_DEBUG_PLACEMENT,
723 "Window %s is initially on all spaces\n",
724 window->desc);
725
726 /* need to set on_all_workspaces first so that it will be
727 * added to all the MRU lists
728 */
729 window->on_all_workspaces = TRUE(!(0));
730 meta_workspace_add_window (window->screen->active_workspace, window);
731 }
732 else
733 {
734 meta_topicmeta_topic_real (META_DEBUG_PLACEMENT,
735 "Window %s is initially on space %d\n",
736 window->desc, window->initial_workspace);
737
738 space =
739 meta_screen_get_workspace_by_index (window->screen,
740 window->initial_workspace);
741
742 if (space)
743 meta_workspace_add_window (space, window);
744 }
745 }
746
747 if (window->workspace == NULL((void*)0) &&
748 window->xtransient_for != None0L)
749 {
750 /* Try putting dialog on parent's workspace */
751 MetaWindow *parent;
752
753 parent = meta_display_lookup_x_window (window->display,
754 window->xtransient_for);
755
756 if (parent && parent->workspace)
757 {
758 meta_topicmeta_topic_real (META_DEBUG_PLACEMENT,
759 "Putting window %s on same workspace as parent %s\n",
760 window->desc, parent->desc);
761
762 if (parent->on_all_workspaces)
763 window->on_all_workspaces = TRUE(!(0));
764
765 /* this will implicitly add to the appropriate MRU lists
766 */
767 meta_workspace_add_window (parent->workspace, window);
768 }
769 }
770
771 if (window->workspace == NULL((void*)0))
772 {
773 meta_topicmeta_topic_real (META_DEBUG_PLACEMENT,
774 "Putting window %s on active workspace\n",
775 window->desc);
776
777 space = window->screen->active_workspace;
778
779 meta_workspace_add_window (space, window);
780 }
781
782 /* for the various on_all_workspaces = TRUE possible above */
783 meta_window_set_current_workspace_hint (window);
784
785 meta_window_update_struts (window);
786
787 /* Must add window to stack before doing move/resize, since the
788 * window might have fullscreen size (i.e. should have been
789 * fullscreen'd; acrobat is one such braindead case; it withdraws
790 * and remaps its window whenever trying to become fullscreen...)
791 * and thus constraints may try to auto-fullscreen it which also
792 * means restacking it.
793 */
794 meta_stack_add (window->screen->stack,
795 window);
796
797 /* Put our state back where it should be,
798 * passing TRUE for is_configure_request, ICCCM says
799 * initial map is handled same as configure request
800 */
801 flags =
802 META_IS_CONFIGURE_REQUEST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
803 meta_window_move_resize_internal (window,
804 flags,
805 window->size_hints.win_gravity,
806 window->size_hints.x,
807 window->size_hints.y,
808 window->size_hints.width,
809 window->size_hints.height);
810
811 /* Now try applying saved stuff from the session */
812 {
813 const MetaWindowSessionInfo *info;
814
815 info = meta_window_lookup_saved_state (window);
816
817 if (info)
818 {
819 meta_window_apply_session_info (window, info);
820 meta_window_release_saved_state (info);
821 }
822 }
823
824 /* FIXME we have a tendency to set this then immediately
825 * change it again.
826 */
827 set_wm_state (window, window->iconic ? IconicState3 : NormalState1);
828 set_net_wm_state (window);
829
830 /* Sync stack changes */
831 meta_stack_thaw (window->screen->stack);
832
833 /* disable show desktop mode unless we're a desktop component */
834 maybe_leave_show_desktop_mode (window);
835
836 meta_window_queue (window, META_QUEUE_CALC_SHOWING);
837 /* See bug 303284; a transient of the given window can already exist, in which
838 * case we think it should probably be shown.
839 */
840 meta_window_foreach_transient (window,
841 queue_calc_showing_func,
842 NULL((void*)0));
843 /* See bug 334899; the window may have minimized ancestors
844 * which need to be shown.
845 *
846 * However, we shouldn't unminimize windows here when opening
847 * a new display because that breaks passing _NET_WM_STATE_HIDDEN
848 * between window managers when replacing them; see bug 358042.
849 *
850 * And we shouldn't unminimize windows if they were initially
851 * iconic.
852 */
853 if (!display->display_opening && !window->initially_iconic)
854 unminimize_window_and_all_transient_parents (window);
855
856 meta_error_trap_pop (display, FALSE(0)); /* pop the XSync()-reducing trap */
857 meta_display_ungrab (display);
858
859 window->constructing = FALSE(0);
860
861 return window;
862}
863
864/* This function should only be called from the end of meta_window_new_with_attrs () */
865static void
866meta_window_apply_session_info (MetaWindow *window,
867 const MetaWindowSessionInfo *info)
868{
869 if (info->stack_position_set)
870 {
871 meta_topicmeta_topic_real (META_DEBUG_SM,
872 "Restoring stack position %d for window %s\n",
873 info->stack_position, window->desc);
874
875 /* FIXME well, I'm not sure how to do this. */
876 }
877
878 if (info->minimized_set)
879 {
880 meta_topicmeta_topic_real (META_DEBUG_SM,
881 "Restoring minimized state %d for window %s\n",
882 info->minimized, window->desc);
883
884 if (window->has_minimize_func && info->minimized)
885 meta_window_minimize (window);
886 }
887
888 if (info->maximized_set)
889 {
890 meta_topicmeta_topic_real (META_DEBUG_SM,
891 "Restoring maximized state %d for window %s\n",
892 info->maximized, window->desc);
893
894 if (window->has_maximize_func && info->maximized)
895 {
896 meta_window_maximize (window,
897 META_MAXIMIZE_HORIZONTAL |
898 META_MAXIMIZE_VERTICAL);
899
900 if (info->saved_rect_set)
901 {
902 meta_topicmeta_topic_real (META_DEBUG_SM,
903 "Restoring saved rect %d,%d %dx%d for window %s\n",
904 info->saved_rect.x,
905 info->saved_rect.y,
906 info->saved_rect.width,
907 info->saved_rect.height,
908 window->desc);
909
910 window->saved_rect.x = info->saved_rect.x;
911 window->saved_rect.y = info->saved_rect.y;
912 window->saved_rect.width = info->saved_rect.width;
913 window->saved_rect.height = info->saved_rect.height;
914 }
915 }
916 }
917
918 if (info->on_all_workspaces_set)
919 {
920 window->on_all_workspaces = info->on_all_workspaces;
921 meta_topicmeta_topic_real (META_DEBUG_SM,
922 "Restoring sticky state %d for window %s\n",
923 window->on_all_workspaces, window->desc);
924 }
925
926 if (info->workspace_indices)
927 {
928 GSList *tmp;
929 GSList *spaces;
930
931 spaces = NULL((void*)0);
932
933 tmp = info->workspace_indices;
934 while (tmp != NULL((void*)0))
935 {
936 MetaWorkspace *space;
937
938 space =
939 meta_screen_get_workspace_by_index (window->screen,
940 GPOINTER_TO_INT (tmp->data)((gint) (glong) (tmp->data)));
941
942 if (space)
943 spaces = g_slist_prepend (spaces, space);
944
945 tmp = tmp->next;
946 }
947
948 if (spaces)
949 {
950 /* This briefly breaks the invariant that we are supposed
951 * to always be on some workspace. But we paranoically
952 * ensured that one of the workspaces from the session was
953 * indeed valid, so we know we'll go right back to one.
954 */
955 if (window->workspace)
956 meta_workspace_remove_window (window->workspace, window);
957
958 /* Only restore to the first workspace if the window
959 * happened to be on more than one, since we have replaces
960 * window->workspaces with window->workspace
961 */
962 meta_workspace_add_window (spaces->data, window);
963
964 meta_topicmeta_topic_real (META_DEBUG_SM,
965 "Restoring saved window %s to workspace %d\n",
966 window->desc,
967 meta_workspace_index (spaces->data));
968
969 g_slist_free (spaces);
970 }
971 }
972
973 if (info->geometry_set)
974 {
975 int x, y, w, h;
976 MetaMoveResizeFlags flags;
977
978 window->placed = TRUE(!(0)); /* don't do placement algorithms later */
979
980 x = info->rect.x;
981 y = info->rect.y;
982
983 w = window->size_hints.base_width +
984 info->rect.width * window->size_hints.width_inc;
985 h = window->size_hints.base_height +
986 info->rect.height * window->size_hints.height_inc;
987
988 /* Force old gravity, ignoring anything now set */
989 window->size_hints.win_gravity = info->gravity;
990
991 meta_topicmeta_topic_real (META_DEBUG_SM,
992 "Restoring pos %d,%d size %d x %d for %s\n",
993 x, y, w, h, window->desc);
994
995 flags = META_DO_GRAVITY_ADJUST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
996 meta_window_move_resize_internal (window,
997 flags,
998 window->size_hints.win_gravity,
999 x, y, w, h);
1000 }
1001}
1002
1003void
1004meta_window_free (MetaWindow *window,
1005 guint32 timestamp)
1006{
1007 GList *tmp;
1008
1009 meta_verbosemeta_verbose_real ("Unmanaging 0x%lx\n", window->xwindow);
1010
1011 if (window->display->compositor)
1012 meta_compositor_free_window (window->display->compositor, window);
1013
1014 if (window->display->window_with_menu == window)
1015 {
1016 meta_ui_window_menu_free (window->display->window_menu);
1017 window->display->window_menu = NULL((void*)0);
1018 window->display->window_with_menu = NULL((void*)0);
1019 }
1020
1021 if (destroying_windows_disallowed > 0)
1022 meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
1023 window->desc);
1024
1025 window->unmanaging = TRUE(!(0));
1026
1027 if (window->fullscreen)
1028 {
1029 MetaGroup *group;
1030
1031 /* If the window is fullscreen, it may be forcing
1032 * other windows in its group to a higher layer
1033 */
1034
1035 meta_stack_freeze (window->screen->stack);
1036 group = meta_window_get_group (window);
1037 if (group)
1038 meta_group_update_layers (group);
1039 meta_stack_thaw (window->screen->stack);
1040 }
1041
1042 meta_window_shutdown_group (window); /* safe to do this early as
1043 * group.c won't re-add to the
1044 * group if window->unmanaging
1045 */
1046
1047 /* If we have the focus, focus some other window.
1048 * This is done first, so that if the unmap causes
1049 * an EnterNotify the EnterNotify will have final say
1050 * on what gets focused, maintaining sloppy focus
1051 * invariants.
1052 */
1053 if (window->has_focus)
1054 {
1055 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1056 "Focusing default window since we're unmanaging %s\n",
1057 window->desc);
1058 meta_workspace_focus_default_window (window->screen->active_workspace,
1059 window,
1060 timestamp);
1061 }
1062 else if (window->display->expected_focus_window == window)
1063 {
1064 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1065 "Focusing default window since expected focus window freed %s\n",
1066 window->desc);
1067 window->display->expected_focus_window = NULL((void*)0);
1068 meta_workspace_focus_default_window (window->screen->active_workspace,
1069 window,
1070 timestamp);
1071 }
1072 else
1073 {
1074 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1075 "Unmanaging window %s which doesn't currently have focus\n",
1076 window->desc);
1077 }
1078
1079 if (window->struts)
1080 {
1081 g_slist_free_full (window->struts, g_free);
1082 window->struts = NULL((void*)0);
1083
1084 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
1085 "Unmanaging window %s which has struts, so invalidating work areas\n",
1086 window->desc);
1087 invalidate_work_areas (window);
1088 }
1089
1090 if (window->display->grab_window == window)
1091 meta_display_end_grab_op (window->display, timestamp);
1092
1093 g_assert (window->display->grab_window != window)do { if (window->display->grab_window != window) ; else
g_assertion_message_expr ("marco", "core/window.c", 1093, ((
const char*) (__func__)), "window->display->grab_window != window"
); } while (0)
;
1094
1095 if (window->display->focus_window == window)
1096 {
1097 window->display->focus_window = NULL((void*)0);
1098 meta_compositor_set_active_window (window->display->compositor,
1099 window->screen, NULL((void*)0));
1100 }
1101
1102 if (window->maximized_horizontally || window->maximized_vertically)
1103 unmaximize_window_before_freeing (window);
1104
1105 /* The XReparentWindow call in meta_window_destroy_frame() moves the
1106 * window so we need to send a configure notify; see bug 399552. (We
1107 * also do this just in case a window got unmaximized.)
1108 */
1109 send_configure_notify (window);
1110
1111 meta_window_unqueue (window, META_QUEUE_CALC_SHOWING |
1112 META_QUEUE_MOVE_RESIZE |
1113 META_QUEUE_UPDATE_ICON);
1114 meta_window_free_delete_dialog (window);
1115
1116 if (window->workspace)
1117 meta_workspace_remove_window (window->workspace, window);
1118
1119 g_assert (window->workspace == NULL)do { if (window->workspace == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/window.c", 1119, ((const char*) (__func__)),
"window->workspace == NULL"); } while (0)
;
1120
1121#ifndef G_DISABLE_CHECKS
1122 tmp = window->screen->workspaces;
1123 while (tmp != NULL((void*)0))
1124 {
1125 MetaWorkspace *workspace = tmp->data;
1126
1127 g_assert (g_list_find (workspace->windows, window) == NULL)do { if (g_list_find (workspace->windows, window) == ((void
*)0)) ; else g_assertion_message_expr ("marco", "core/window.c"
, 1127, ((const char*) (__func__)), "g_list_find (workspace->windows, window) == NULL"
); } while (0)
;
1128 g_assert (g_list_find (workspace->mru_list, window) == NULL)do { if (g_list_find (workspace->mru_list, window) == ((void
*)0)) ; else g_assertion_message_expr ("marco", "core/window.c"
, 1128, ((const char*) (__func__)), "g_list_find (workspace->mru_list, window) == NULL"
); } while (0)
;
1129
1130 tmp = tmp->next;
1131 }
1132#endif
1133
1134 meta_stack_remove (window->screen->stack, window);
1135
1136 if (window->frame)
1137 meta_window_destroy_frame (window);
1138
1139 if (window->withdrawn)
1140 {
1141 /* We need to clean off the window's state so it
1142 * won't be restored if the app maps it again.
1143 */
1144 meta_error_trap_push (window->display);
1145 meta_verbosemeta_verbose_real ("Cleaning state from window %s\n", window->desc);
1146 XDeleteProperty (window->display->xdisplay,
1147 window->xwindow,
1148 window->display->atom__NET_WM_DESKTOP);
1149 XDeleteProperty (window->display->xdisplay,
1150 window->xwindow,
1151 window->display->atom__NET_WM_STATE);
1152 XDeleteProperty (window->display->xdisplay,
1153 window->xwindow,
1154 window->display->atom__NET_WM_FULLSCREEN_MONITORS);
1155 set_wm_state (window, WithdrawnState0);
1156 meta_error_trap_pop (window->display, FALSE(0));
1157 }
1158 else
1159 {
1160 /* We need to put WM_STATE so that others will understand it on
1161 * restart.
1162 */
1163 if (!window->minimized)
1164 {
1165 meta_error_trap_push (window->display);
1166 set_wm_state (window, NormalState1);
1167 meta_error_trap_pop (window->display, FALSE(0));
1168 }
1169
1170 /* And we need to be sure the window is mapped so other WMs
1171 * know that it isn't Withdrawn
1172 */
1173 meta_error_trap_push (window->display);
1174 XMapWindow (window->display->xdisplay,
1175 window->xwindow);
1176 meta_error_trap_pop (window->display, FALSE(0));
1177 }
1178
1179 meta_window_ungrab_keys (window);
1180 meta_display_ungrab_window_buttons (window->display, window->xwindow);
1181 meta_display_ungrab_focus_window_button (window->display, window);
1182
1183 meta_display_unregister_x_window (window->display, window->xwindow);
1184
1185 meta_error_trap_push (window->display);
1186
1187 /* Put back anything we messed up */
1188 if (window->border_width != 0)
1189 XSetWindowBorderWidth (window->display->xdisplay,
1190 window->xwindow,
1191 window->border_width);
1192
1193 /* No save set */
1194 XRemoveFromSaveSet (window->display->xdisplay,
1195 window->xwindow);
1196
1197 /* Don't get events on not-managed windows */
1198 XSelectInput (window->display->xdisplay,
1199 window->xwindow,
1200 NoEventMask0L);
1201
1202 /* Stop getting events for the window's _NET_WM_USER_TIME_WINDOW too */
1203 if (window->user_time_window != None0L)
1204 {
1205 meta_display_unregister_x_window (window->display,
1206 window->user_time_window);
1207 XSelectInput (window->display->xdisplay,
1208 window->user_time_window,
1209 NoEventMask0L);
1210 window->user_time_window = None0L;
1211 }
1212
1213#ifdef HAVE_SHAPE
1214 if (META_DISPLAY_HAS_SHAPE (window->display)((window->display)->have_shape))
1215 XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask0L);
1216#endif
1217
1218 meta_error_trap_pop (window->display, FALSE(0));
1219
1220 g_object_unref (window);
1221}
1222
1223static void
1224set_wm_state (MetaWindow *window,
1225 int state)
1226{
1227 unsigned long data[2];
1228
1229 meta_verbosemeta_verbose_real ("Setting wm state %s on %s\n",
1230 wm_state_to_string (state), window->desc);
1231
1232 /* Marco doesn't use icon windows, so data[1] should be None
1233 * according to the ICCCM 2.0 Section 4.1.3.1.
1234 */
1235 data[0] = state;
1236 data[1] = None0L;
1237
1238 meta_error_trap_push (window->display);
1239 XChangeProperty (window->display->xdisplay, window->xwindow,
1240 window->display->atom_WM_STATE,
1241 window->display->atom_WM_STATE,
1242 32, PropModeReplace0, (guchar*) data, 2);
1243 meta_error_trap_pop (window->display, FALSE(0));
1244}
1245
1246static void
1247set_net_wm_state (MetaWindow *window)
1248{
1249 int i;
1250 unsigned long data[13];
1251
1252 i = 0;
1253 if (window->shaded)
1254 {
1255 data[i] = window->display->atom__NET_WM_STATE_SHADED;
1256 ++i;
1257 }
1258 if (window->wm_state_modal)
1259 {
1260 data[i] = window->display->atom__NET_WM_STATE_MODAL;
1261 ++i;
1262 }
1263 if (window->skip_pager)
1264 {
1265 data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER;
1266 ++i;
1267 }
1268 if (window->skip_taskbar)
1269 {
1270 data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR;
1271 ++i;
1272 }
1273 if (window->maximized_horizontally)
1274 {
1275 data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ;
1276 ++i;
1277 }
1278 if (window->maximized_vertically)
1279 {
1280 data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT;
1281 ++i;
1282 }
1283 if (window->fullscreen)
1284 {
1285 data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN;
1286 ++i;
1287 }
1288 if (!meta_window_showing_on_its_workspace (window) || window->shaded)
1289 {
1290 data[i] = window->display->atom__NET_WM_STATE_HIDDEN;
1291 ++i;
1292 }
1293 if (window->wm_state_above)
1294 {
1295 data[i] = window->display->atom__NET_WM_STATE_ABOVE;
1296 ++i;
1297 }
1298 if (window->wm_state_below)
1299 {
1300 data[i] = window->display->atom__NET_WM_STATE_BELOW;
1301 ++i;
1302 }
1303 if (window->wm_state_demands_attention)
1304 {
1305 data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION;
1306 ++i;
1307 }
1308 if (window->on_all_workspaces)
1309 {
1310 data[i] = window->display->atom__NET_WM_STATE_STICKY;
1311 ++i;
1312 }
1313 if (meta_window_appears_focused (window))
1314 {
1315 data[i] = window->display->atom__NET_WM_STATE_FOCUSED;
1316 ++i;
1317 }
1318
1319 meta_verbosemeta_verbose_real ("Setting _NET_WM_STATE with %d atoms\n", i);
1320
1321 meta_error_trap_push (window->display);
1322 XChangeProperty (window->display->xdisplay, window->xwindow,
1323 window->display->atom__NET_WM_STATE,
1324 XA_ATOM((Atom) 4),
1325 32, PropModeReplace0, (guchar*) data, i);
1326 meta_error_trap_pop (window->display, FALSE(0));
1327
1328 if (window->fullscreen)
1329 {
1330 data[0] = window->fullscreen_monitors[0];
1331 data[1] = window->fullscreen_monitors[1];
1332 data[2] = window->fullscreen_monitors[2];
1333 data[3] = window->fullscreen_monitors[3];
1334
1335 meta_verbosemeta_verbose_real ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
1336 meta_error_trap_push (window->display);
1337 XChangeProperty (window->display->xdisplay,
1338 window->xwindow,
1339 window->display->atom__NET_WM_FULLSCREEN_MONITORS,
1340 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
1341 (guchar*) data, 4);
1342 meta_error_trap_pop (window->display, FALSE(0));
1343 }
1344}
1345
1346gboolean
1347meta_window_located_on_workspace (MetaWindow *window,
1348 MetaWorkspace *workspace)
1349{
1350 return (window->on_all_workspaces && window->screen == workspace->screen) ||
1351 (window->workspace == workspace);
1352}
1353
1354static gboolean
1355is_minimized_foreach (MetaWindow *window,
1356 void *data)
1357{
1358 gboolean *result = data;
1359
1360 *result = window->minimized;
1361 if (*result)
1362 return FALSE(0); /* stop as soon as we find one */
1363 else
1364 return TRUE(!(0));
1365}
1366
1367static gboolean
1368ancestor_is_minimized (MetaWindow *window)
1369{
1370 gboolean is_minimized;
1371
1372 is_minimized = FALSE(0);
1373
1374 meta_window_foreach_ancestor (window, is_minimized_foreach, &is_minimized);
1375
1376 return is_minimized;
1377}
1378
1379gboolean
1380meta_window_showing_on_its_workspace (MetaWindow *window)
1381{
1382 gboolean showing;
1383 gboolean is_desktop_or_dock;
1384 MetaWorkspace* workspace_of_window;
1385
1386 showing = TRUE(!(0));
1387
1388 /* 1. See if we're minimized */
1389 if (window->minimized)
1390 showing = FALSE(0);
1391
1392 /* 2. See if we're in "show desktop" mode */
1393 is_desktop_or_dock = FALSE(0);
1394 is_desktop_or_dock_foreach (window,
1395 &is_desktop_or_dock);
1396
1397 meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
1398 &is_desktop_or_dock);
1399
1400 if (window->on_all_workspaces)
1401 workspace_of_window = window->screen->active_workspace;
1402 else if (window->workspace)
1403 workspace_of_window = window->workspace;
1404 else /* This only seems to be needed for startup */
1405 workspace_of_window = NULL((void*)0);
1406
1407 if (showing &&
1408 workspace_of_window && workspace_of_window->showing_desktop &&
1409 !is_desktop_or_dock)
1410 {
1411 meta_verbosemeta_verbose_real ("We're showing the desktop on the workspace(s) that window %s is on\n",
1412 window->desc);
1413 showing = FALSE(0);
1414 }
1415
1416 /* 3. See if an ancestor is minimized (note that
1417 * ancestor's "mapped" field may not be up to date
1418 * since it's being computed in this same idle queue)
1419 */
1420
1421 if (showing)
1422 {
1423 if (ancestor_is_minimized (window))
1424 showing = FALSE(0);
1425 }
1426
1427#if 0
1428 /* 4. See if we're drawing wireframe
1429 */
1430 if (window->display->grab_window == window &&
1431 window->display->grab_wireframe_active)
1432 showing = FALSE(0);
1433#endif
1434
1435 return showing;
1436}
1437
1438gboolean
1439meta_window_should_be_showing (MetaWindow *window)
1440{
1441 gboolean on_workspace;
1442
1443 meta_verbosemeta_verbose_real ("Should be showing for window %s\n", window->desc);
1444
1445 /* See if we're on the workspace */
1446 on_workspace = meta_window_located_on_workspace (window,
1447 window->screen->active_workspace);
1448
1449 if (!on_workspace)
1450 meta_verbosemeta_verbose_real ("Window %s is not on workspace %d\n",
1451 window->desc,
1452 meta_workspace_index (window->screen->active_workspace));
1453 else
1454 meta_verbosemeta_verbose_real ("Window %s is on the active workspace %d\n",
1455 window->desc,
1456 meta_workspace_index (window->screen->active_workspace));
1457
1458 if (window->on_all_workspaces)
1459 meta_verbosemeta_verbose_real ("Window %s is on all workspaces\n", window->desc);
1460
1461 return on_workspace && meta_window_showing_on_its_workspace (window);
1462}
1463
1464static void
1465finish_minimize (gpointer data)
1466{
1467 MetaWindow *window = data;
1468 /* FIXME: It really sucks to put timestamp pinging here; it'd
1469 * probably make more sense in implement_showing() so that it's at
1470 * least not duplicated in meta_window_show; but since
1471 * finish_minimize is a callback making things just slightly icky, I
1472 * haven't done that yet.
1473 */
1474 guint32 timestamp = meta_display_get_current_time_roundtrip (window->display);
1475
1476 meta_window_hide (window);
1477 if (window->has_focus)
1478 {
1479 meta_workspace_focus_default_window (window->screen->active_workspace,
1480 window,
1481 timestamp);
1482 }
1483}
1484
1485static void
1486implement_showing (MetaWindow *window,
1487 gboolean showing)
1488{
1489 /* Actually show/hide the window */
1490 meta_verbosemeta_verbose_real ("Implement showing = %d for window %s\n",
1491 showing, window->desc);
1492
1493 if (!showing)
1494 {
1495 gboolean on_workspace;
1496
1497 on_workspace = meta_window_located_on_workspace (window,
1498 window->screen->active_workspace);
1499
1500 /* Really this effects code should probably
1501 * be in meta_window_hide so the window->mapped
1502 * test isn't duplicated here. Anyhow, we animate
1503 * if we are mapped now, we are supposed to
1504 * be minimized, and we are on the current workspace.
1505 */
1506 if (on_workspace && window->minimized && window->mapped &&
1507 !meta_prefs_get_reduced_resources ())
1508 {
1509 MetaRectangle icon_rect, window_rect;
1510 gboolean result;
1511
1512 /* Check if the window has an icon geometry */
1513 result = meta_window_get_icon_geometry (window, &icon_rect);
1514
1515 if (!result)
1516 {
1517 /* just animate into the corner somehow - maybe
1518 * not a good idea...
1519 */
1520 icon_rect.x = window->screen->rect.width;
1521 icon_rect.y = window->screen->rect.height;
1522 icon_rect.width = 1;
1523 icon_rect.height = 1;
1524 }
1525
1526 meta_window_get_outer_rect (window, &window_rect);
1527
1528 meta_effect_run_minimize (window,
1529 &window_rect,
1530 &icon_rect,
1531 finish_minimize,
1532 window);
1533 }
1534 else
1535 {
1536 finish_minimize (window);
1537 }
1538 }
1539 else
1540 {
1541 meta_window_show (window);
1542 }
1543}
1544
1545void
1546meta_window_calc_showing (MetaWindow *window)
1547{
1548 implement_showing (window, meta_window_should_be_showing (window));
1549}
1550
1551static guint queue_idle[NUMBER_OF_QUEUES3] = {0, 0, 0};
1552static GSList *queue_pending[NUMBER_OF_QUEUES3] = {NULL((void*)0), NULL((void*)0), NULL((void*)0)};
1553
1554static int
1555stackcmp (gconstpointer a, gconstpointer b)
1556{
1557 MetaWindow *aw = (gpointer) a;
1558 MetaWindow *bw = (gpointer) b;
1559
1560 if (aw->screen != bw->screen)
1561 return 0; /* don't care how they sort with respect to each other */
1562 else
1563 return meta_stack_windows_cmp (aw->screen->stack,
1564 aw, bw);
1565}
1566
1567static gboolean
1568idle_calc_showing (gpointer data)
1569{
1570 GSList *tmp;
1571 GSList *copy;
1572 GSList *should_show;
1573 GSList *should_hide;
1574 GSList *unplaced;
1575 MetaWindow *first_window;
1576 guint queue_index = GPOINTER_TO_INT (data)((gint) (glong) (data));
1577
1578 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
1579 "Clearing the calc_showing queue\n");
1580
1581 /* Work with a copy, for reentrancy. The allowed reentrancy isn't
1582 * complete; destroying a window while we're in here would result in
1583 * badness. But it's OK to queue/unqueue calc_showings.
1584 */
1585 copy = g_slist_copy (queue_pending[queue_index]);
1
Value assigned to 'copy'
1586 g_slist_free (queue_pending[queue_index]);
1587 queue_pending[queue_index] = NULL((void*)0);
1588 queue_idle[queue_index] = 0;
1589
1590 destroying_windows_disallowed += 1;
1591
1592 /* We map windows from top to bottom and unmap from bottom to
1593 * top, to avoid extra expose events. The exception is
1594 * for unplaced windows, which have to be mapped from bottom to
1595 * top so placement works.
1596 */
1597 should_show = NULL((void*)0);
1598 should_hide = NULL((void*)0);
1599 unplaced = NULL((void*)0);
1600
1601 tmp = copy;
1602 while (tmp != NULL((void*)0))
2
Assuming 'tmp' is equal to NULL
3
Loop condition is false. Execution continues on line 1619
1603 {
1604 MetaWindow *window;
1605
1606 window = tmp->data;
1607
1608 if (!window->placed)
1609 unplaced = g_slist_prepend (unplaced, window);
1610 else if (meta_window_should_be_showing (window))
1611 should_show = g_slist_prepend (should_show, window);
1612 else
1613 should_hide = g_slist_prepend (should_hide, window);
1614
1615 tmp = tmp->next;
1616 }
1617
1618 /* bottom to top */
1619 unplaced = g_slist_sort (unplaced, stackcmp);
1620 should_hide = g_slist_sort (should_hide, stackcmp);
1621 /* top to bottom */
1622 should_show = g_slist_sort (should_show, stackcmp);
1623 should_show = g_slist_reverse (should_show);
1624
1625 first_window = copy->data;
4
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'copy')
1626
1627 meta_display_grab (first_window->display);
1628
1629 tmp = unplaced;
1630 while (tmp != NULL((void*)0))
1631 {
1632 MetaWindow *window;
1633
1634 window = tmp->data;
1635
1636 meta_window_calc_showing (window);
1637
1638 tmp = tmp->next;
1639 }
1640
1641 tmp = should_show;
1642 while (tmp != NULL((void*)0))
1643 {
1644 MetaWindow *window;
1645
1646 window = tmp->data;
1647
1648 implement_showing (window, TRUE(!(0)));
1649
1650 tmp = tmp->next;
1651 }
1652
1653 tmp = should_hide;
1654 while (tmp != NULL((void*)0))
1655 {
1656 MetaWindow *window;
1657
1658 window = tmp->data;
1659
1660 implement_showing (window, FALSE(0));
1661
1662 tmp = tmp->next;
1663 }
1664
1665 tmp = copy;
1666 while (tmp != NULL((void*)0))
1667 {
1668 MetaWindow *window;
1669
1670 window = tmp->data;
1671
1672 /* important to set this here for reentrancy -
1673 * if we queue a window again while it's in "copy",
1674 * then queue_calc_showing will just return since
1675 * we are still in the calc_showing queue
1676 */
1677 window->is_in_queues &= ~META_QUEUE_CALC_SHOWING;
1678
1679 tmp = tmp->next;
1680 }
1681
1682 if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK)
1683 {
1684 /* When display->mouse_mode is false, we want to ignore
1685 * EnterNotify events unless they come from mouse motion. To do
1686 * that, we set a sentinel property on the root window if we're
1687 * not in mouse_mode.
1688 */
1689 tmp = should_show;
1690 while (tmp != NULL((void*)0))
1691 {
1692 MetaWindow *window = tmp->data;
1693
1694 if (!window->display->mouse_mode)
1695 meta_display_increment_focus_sentinel (window->display);
1696
1697 tmp = tmp->next;
1698 }
1699 }
1700
1701 meta_display_ungrab (first_window->display);
1702
1703 g_slist_free (copy);
1704
1705 g_slist_free (unplaced);
1706 g_slist_free (should_show);
1707 g_slist_free (should_hide);
1708
1709 destroying_windows_disallowed -= 1;
1710
1711 return FALSE(0);
1712}
1713
1714#ifdef WITH_VERBOSE_MODE1
1715static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES3] =
1716 {"calc_showing", "move_resize", "update_icon"};
1717#endif
1718
1719static void
1720meta_window_unqueue (MetaWindow *window, guint queuebits)
1721{
1722 gint queuenum;
1723
1724 for (queuenum=0; queuenum<NUMBER_OF_QUEUES3; queuenum++)
1725 {
1726 if ((queuebits & 1<<queuenum) /* they have asked to unqueue */
1727 &&
1728 (window->is_in_queues & 1<<queuenum)) /* it's in the queue */
1729 {
1730
1731 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
1732 "Removing %s from the %s queue\n",
1733 window->desc,
1734 meta_window_queue_names[queuenum]);
1735
1736 /* Note that window may not actually be in the queue
1737 * because it may have been in "copy" inside the idle handler
1738 */
1739 queue_pending[queuenum] = g_slist_remove (queue_pending[queuenum], window);
1740 window->is_in_queues &= ~(1<<queuenum);
1741
1742 /* Okay, so maybe we've used up all the entries in the queue.
1743 * In that case, we should kill the function that deals with
1744 * the queue, because there's nothing left for it to do.
1745 */
1746 if (queue_pending[queuenum] == NULL((void*)0) && queue_idle[queuenum] != 0)
1747 {
1748 g_source_remove (queue_idle[queuenum]);
1749 queue_idle[queuenum] = 0;
1750 }
1751 }
1752 }
1753}
1754
1755static void
1756meta_window_flush_calc_showing (MetaWindow *window)
1757{
1758 if (window->is_in_queues & META_QUEUE_CALC_SHOWING)
1759 {
1760 meta_window_unqueue (window, META_QUEUE_CALC_SHOWING);
1761 meta_window_calc_showing (window);
1762 }
1763}
1764
1765void
1766meta_window_queue (MetaWindow *window, guint queuebits)
1767{
1768 guint queuenum;
1769
1770 for (queuenum=0; queuenum<NUMBER_OF_QUEUES3; queuenum++)
1771 {
1772 if (queuebits & 1<<queuenum)
1773 {
1774 /* Data which varies between queues.
1775 * Yes, these do look a lot like associative arrays:
1776 * I seem to be turning into a Perl programmer.
1777 */
1778
1779 const gint window_queue_idle_priority[NUMBER_OF_QUEUES3] =
1780 {
1781 G_PRIORITY_DEFAULT_IDLE200, /* CALC_SHOWING */
1782 META_PRIORITY_RESIZE(100 + 15), /* MOVE_RESIZE */
1783 G_PRIORITY_DEFAULT_IDLE200 /* UPDATE_ICON */
1784 };
1785
1786 const GSourceFunc window_queue_idle_handler[NUMBER_OF_QUEUES3] =
1787 {
1788 idle_calc_showing,
1789 idle_move_resize,
1790 idle_update_icon,
1791 };
1792
1793 /* If we're about to drop the window, there's no point in putting
1794 * it on a queue.
1795 */
1796 if (window->unmanaging)
1797 break;
1798
1799 /* If the window already claims to be in that queue, there's no
1800 * point putting it in the queue.
1801 */
1802 if (window->is_in_queues & 1<<queuenum)
1803 break;
1804
1805 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
1806 "Putting %s in the %s queue\n",
1807 window->desc,
1808 meta_window_queue_names[queuenum]);
1809
1810 /* So, mark it as being in this queue. */
1811 window->is_in_queues |= 1<<queuenum;
1812
1813 /* There's not a lot of point putting things into a queue if
1814 * nobody's on the other end pulling them out. Therefore,
1815 * let's check to see whether an idle handler exists to do
1816 * that. If not, we'll create one.
1817 */
1818
1819 if (queue_idle[queuenum] == 0)
1820 queue_idle[queuenum] = g_idle_add_full
1821 (
1822 window_queue_idle_priority[queuenum],
1823 window_queue_idle_handler[queuenum],
1824 GUINT_TO_POINTER(queuenum)((gpointer) (gulong) (queuenum)),
1825 NULL((void*)0)
1826 );
1827
1828 /* And now we actually put it on the queue. */
1829 queue_pending[queuenum] = g_slist_prepend (queue_pending[queuenum],
1830 window);
1831 }
1832 }
1833}
1834
1835static gboolean
1836intervening_user_event_occurred (MetaWindow *window)
1837{
1838 guint32 compare;
1839 MetaWindow *focus_window;
1840
1841 focus_window = window->display->focus_window;
1842
1843 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1844 "COMPARISON:\n"
1845 " net_wm_user_time_set : %d\n"
1846 " net_wm_user_time : %u\n"
1847 " initial_timestamp_set: %d\n"
1848 " initial_timestamp : %u\n",
1849 window->net_wm_user_time_set,
1850 window->net_wm_user_time,
1851 window->initial_timestamp_set,
1852 window->initial_timestamp);
1853 if (focus_window != NULL((void*)0))
1854 {
1855 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1856 "COMPARISON (continued):\n"
1857 " focus_window : %s\n"
1858 " fw->net_wm_user_time_set : %d\n"
1859 " fw->net_wm_user_time : %u\n",
1860 focus_window->desc,
1861 focus_window->net_wm_user_time_set,
1862 focus_window->net_wm_user_time);
1863 }
1864
1865 /* We expect the most common case for not focusing a new window
1866 * to be when a hint to not focus it has been set. Since we can
1867 * deal with that case rapidly, we use special case it--this is
1868 * merely a preliminary optimization. :)
1869 */
1870 if ((window->net_wm_user_time_set && (window->net_wm_user_time == 0)) ||
1871 (window->initial_timestamp_set && (window->initial_timestamp == 0)))
1872 {
1873 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1874 "window %s explicitly requested no focus\n",
1875 window->desc);
1876 return TRUE(!(0));
1877 }
1878
1879 if (!window->net_wm_user_time_set && !window->initial_timestamp_set)
1880 {
1881 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1882 "no information about window %s found\n",
1883 window->desc);
1884 return FALSE(0);
1885 }
1886
1887 if (focus_window != NULL((void*)0) &&
1888 !focus_window->net_wm_user_time_set)
1889 {
1890 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1891 "focus window, %s, doesn't have a user time set yet!\n",
1892 window->desc);
1893 return FALSE(0);
1894 }
1895
1896 /* To determine the "launch" time of an application,
1897 * startup-notification can set the TIMESTAMP and the
1898 * application (usually via its toolkit such as gtk or qt) can
1899 * set the _NET_WM_USER_TIME. If both are set, we need to be
1900 * using the newer of the two values.
1901 *
1902 * See http://bugzilla.gnome.org/show_bug.cgi?id=573922
1903 */
1904 compare = 0;
1905 if (window->net_wm_user_time_set &&
1906 window->initial_timestamp_set)
1907 compare =
1908 XSERVER_TIME_IS_BEFORE (window->net_wm_user_time,( (window->net_wm_user_time) == 0 || (( (( (window->net_wm_user_time
) < (window->initial_timestamp) ) && ( (window->
initial_timestamp) - (window->net_wm_user_time) < ((guint32
)-1)/2 )) || (( (window->net_wm_user_time) > (window->
initial_timestamp) ) && ( (window->net_wm_user_time
) - (window->initial_timestamp) > ((guint32)-1)/2 )) ) &&
(window->initial_timestamp) != 0) )
1909 window->initial_timestamp)( (window->net_wm_user_time) == 0 || (( (( (window->net_wm_user_time
) < (window->initial_timestamp) ) && ( (window->
initial_timestamp) - (window->net_wm_user_time) < ((guint32
)-1)/2 )) || (( (window->net_wm_user_time) > (window->
initial_timestamp) ) && ( (window->net_wm_user_time
) - (window->initial_timestamp) > ((guint32)-1)/2 )) ) &&
(window->initial_timestamp) != 0) )
?
1910 window->initial_timestamp : window->net_wm_user_time;
1911 else if (window->net_wm_user_time_set)
1912 compare = window->net_wm_user_time;
1913 else if (window->initial_timestamp_set)
1914 compare = window->initial_timestamp;
1915
1916 if ((focus_window != NULL((void*)0)) &&
1917 XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time)( (compare) == 0 || (( (( (compare) < (focus_window->net_wm_user_time
) ) && ( (focus_window->net_wm_user_time) - (compare
) < ((guint32)-1)/2 )) || (( (compare) > (focus_window->
net_wm_user_time) ) && ( (compare) - (focus_window->
net_wm_user_time) > ((guint32)-1)/2 )) ) && (focus_window
->net_wm_user_time) != 0) )
)
1918 {
1919 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1920 "window %s focus prevented by other activity; %u < %u\n",
1921 window->desc,
1922 compare,
1923 focus_window->net_wm_user_time);
1924 return TRUE(!(0));
1925 }
1926 else
1927 {
1928 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
1929 "new window %s with no intervening events\n",
1930 window->desc);
1931 return FALSE(0);
1932 }
1933}
1934
1935/* This function is an ugly hack. It's experimental in nature and ought to be
1936 * replaced by a real hint from the app to the WM if we decide the experimental
1937 * behavior is worthwhile. The basic idea is to get more feedback about how
1938 * usage scenarios of "strict" focus users and what they expect. See #326159.
1939 */
1940gboolean
1941__window_is_terminal (MetaWindow *window)
1942{
1943 if (window == NULL((void*)0) || window->res_class == NULL((void*)0))
1944 return FALSE(0);
1945
1946 /*
1947 * Compare res_class, which is not user-settable, and thus theoretically
1948 * a more-reliable indication of term-ness.
1949 */
1950
1951 /* mate-terminal -- if you couldn't guess */
1952 if (strcmp (window->res_class, "Mate-terminal") == 0)
1953 return TRUE(!(0));
1954 /* xterm, rxvt, aterm */
1955 else if (strcmp (window->res_class, "XTerm") == 0)
1956 return TRUE(!(0));
1957 /* konsole, KDE's terminal program */
1958 else if (strcmp (window->res_class, "Konsole") == 0)
1959 return TRUE(!(0));
1960 /* rxvt-unicode */
1961 else if (strcmp (window->res_class, "URxvt") == 0)
1962 return TRUE(!(0));
1963 /* eterm */
1964 else if (strcmp (window->res_class, "Eterm") == 0)
1965 return TRUE(!(0));
1966 /* KTerm -- some terminal not KDE based; so not like Konsole */
1967 else if (strcmp (window->res_class, "KTerm") == 0)
1968 return TRUE(!(0));
1969 /* Multi-mate-terminal */
1970 else if (strcmp (window->res_class, "Multi-mate-terminal") == 0)
1971 return TRUE(!(0));
1972 /* mlterm ("multi lingual terminal emulator on X") */
1973 else if (strcmp (window->res_class, "mlterm") == 0)
1974 return TRUE(!(0));
1975 /* Terminal -- XFCE Terminal */
1976 else if (strcmp (window->res_class, "Terminal") == 0)
1977 return TRUE(!(0));
1978
1979 return FALSE(0);
1980}
1981
1982/* This function determines what state the window should have assuming that it
1983 * and the focus_window have no relation
1984 */
1985static void
1986window_state_on_map (MetaWindow *window,
1987 gboolean *takes_focus,
1988 gboolean *places_on_top)
1989{
1990 gboolean intervening_events;
1991
1992 intervening_events = intervening_user_event_occurred (window);
1993
1994 *takes_focus = !intervening_events;
1995 *places_on_top = *takes_focus;
1996
1997 /* don't initially focus windows that are intended to not accept
1998 * focus
1999 */
2000 if (!(window->input || window->take_focus))
2001 {
2002 *takes_focus = FALSE(0);
2003 return;
2004 }
2005
2006 /* Terminal usage may be different; some users intend to launch
2007 * many apps in quick succession or to just view things in the new
2008 * window while still interacting with the terminal. In that case,
2009 * apps launched from the terminal should not take focus. This
2010 * isn't quite the same as not allowing focus to transfer from
2011 * terminals due to new window map, but the latter is a much easier
2012 * approximation to enforce so we do that.
2013 */
2014 if (*takes_focus &&
2015 meta_prefs_get_focus_new_windows () == META_FOCUS_NEW_WINDOWS_STRICT &&
2016 !window->display->allow_terminal_deactivation &&
2017 __window_is_terminal (window->display->focus_window) &&
2018 !meta_window_is_ancestor_of_transient (window->display->focus_window,
2019 window))
2020 {
2021 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
2022 "focus_window is terminal; not focusing new window.\n");
2023 *takes_focus = FALSE(0);
2024 *places_on_top = FALSE(0);
2025 }
2026
2027 switch (window->type)
2028 {
2029 case META_WINDOW_UTILITY:
2030 case META_WINDOW_TOOLBAR:
2031 *takes_focus = FALSE(0);
2032 *places_on_top = FALSE(0);
2033 break;
2034 case META_WINDOW_DOCK:
2035 case META_WINDOW_DESKTOP:
2036 case META_WINDOW_SPLASHSCREEN:
2037 case META_WINDOW_MENU:
2038 /* don't focus any of these; places_on_top may be irrelevant for some of
2039 * these (e.g. dock)--but you never know--the focus window might also be
2040 * of the same type in some weird situation...
2041 */
2042 *takes_focus = FALSE(0);
2043 break;
2044 case META_WINDOW_NORMAL:
2045 case META_WINDOW_DIALOG:
2046 case META_WINDOW_MODAL_DIALOG:
2047 /* The default is correct for these */
2048 break;
2049 }
2050}
2051
2052static gboolean
2053windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
2054{
2055 if (w1->minimized || w2->minimized)
2056 return FALSE(0);
2057
2058 MetaRectangle w1rect, w2rect;
2059 meta_window_get_outer_rect (w1, &w1rect);
2060 meta_window_get_outer_rect (w2, &w2rect);
2061 return meta_rectangle_overlap (&w1rect, &w2rect);
2062}
2063
2064/* Returns whether a new window would be covered by any
2065 * existing window on the same workspace that is set
2066 * to be "above" ("always on top"). A window that is not
2067 * set "above" would be underneath the new window anyway.
2068 *
2069 * We take "covered" to mean even partially covered, but
2070 * some people might prefer entirely covered. I think it
2071 * is more useful to behave this way if any part of the
2072 * window is covered, because a partial coverage could be
2073 * (say) ninety per cent and almost indistinguishable from total.
2074 */
2075static gboolean
2076window_would_be_covered (const MetaWindow *newbie)
2077{
2078 MetaWorkspace *workspace;
2079 GList *tmp, *windows;
2080
2081 workspace = meta_window_get_workspace ((MetaWindow *) newbie);
2082 windows = meta_workspace_list_windows (workspace);
2083
2084 tmp = windows;
2085 while (tmp != NULL((void*)0))
2086 {
2087 MetaWindow *w = tmp->data;
2088
2089 if (w->wm_state_above && w != newbie)
2090 {
2091 /* We have found a window that is "above". Perhaps it overlaps. */
2092 if (windows_overlap (w, newbie))
2093 {
2094 g_list_free (windows); /* clean up... */
2095 return TRUE(!(0)); /* yes, it does */
2096 }
2097 }
2098
2099 tmp = tmp->next;
2100 }
2101
2102 g_list_free (windows);
2103 return FALSE(0); /* none found */
2104}
2105
2106/* XXX META_EFFECT_*_MAP */
2107void
2108meta_window_show (MetaWindow *window)
2109{
2110 gboolean did_show;
2111 gboolean takes_focus_on_map;
2112 gboolean place_on_top_on_map;
2113 gboolean needs_stacking_adjustment;
2114 gboolean will_be_covered;
2115 MetaWindow *focus_window;
2116 guint32 timestamp;
2117
2118 /* FIXME: It really sucks to put timestamp pinging here; it'd
2119 * probably make more sense in implement_showing() so that it's at
2120 * least not duplicated in finish_minimize. *shrug*
2121 */
2122 timestamp = meta_display_get_current_time_roundtrip (window->display);
2123
2124 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2125 "Showing window %s, shaded: %d iconic: %d placed: %d\n",
2126 window->desc, window->shaded, window->iconic, window->placed);
2127
2128 focus_window = window->display->focus_window; /* May be NULL! */
2129 did_show = FALSE(0);
2130 window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
2131 needs_stacking_adjustment = FALSE(0);
2132 will_be_covered = window_would_be_covered (window);
2133
2134 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2135 "Window %s %s focus on map, and %s place on top on map.\n",
2136 window->desc,
2137 takes_focus_on_map ? "does" : "does not",
2138 place_on_top_on_map ? "does" : "does not");
2139
2140 /* Now, in some rare cases we should *not* put a new window on top.
2141 * These cases include certain types of windows showing for the first
2142 * time, and any window which would be covered because of another window
2143 * being set "above" ("always on top").
2144 *
2145 * FIXME: Although "place_on_top_on_map" and "takes_focus_on_map" are
2146 * generally based on the window type, there is a special case when the
2147 * focus window is a terminal for them both to be false; this should
2148 * probably rather be a term in the "if" condition below.
2149 */
2150
2151 if ( focus_window != NULL((void*)0) && window->showing_for_first_time &&
2152 ( (!place_on_top_on_map && !takes_focus_on_map) ||
2153 will_be_covered )
2154 ) {
2155 if (!meta_window_is_ancestor_of_transient (focus_window, window))
2156 {
2157 needs_stacking_adjustment = TRUE(!(0));
2158 if (!window->placed)
2159 window->denied_focus_and_not_transient = TRUE(!(0));
2160 }
2161 }
2162
2163 if (!window->placed)
2164 {
2165 /* We have to recalc the placement here since other windows may
2166 * have been mapped/placed since we last did constrain_position
2167 */
2168
2169 /* calc_placement is an efficiency hack to avoid
2170 * multiple placement calculations before we finally
2171 * show the window.
2172 */
2173 window->calc_placement = TRUE(!(0));
2174 meta_window_move_resize_now (window);
2175 window->calc_placement = FALSE(0);
2176
2177 /* don't ever do the initial position constraint thing again.
2178 * This is toggled here so that initially-iconified windows
2179 * still get placed when they are ultimately shown.
2180 */
2181 window->placed = TRUE(!(0));
2182
2183 /* Don't want to accidentally reuse the fact that we had been denied
2184 * focus in any future constraints unless we're denied focus again.
2185 */
2186 window->denied_focus_and_not_transient = FALSE(0);
2187 }
2188
2189 if (needs_stacking_adjustment)
2190 {
2191 gboolean overlap;
2192
2193 /* This window isn't getting focus on map. We may need to do some
2194 * special handing with it in regards to
2195 * - the stacking of the window
2196 * - the MRU position of the window
2197 * - the demands attention setting of the window
2198 *
2199 * Firstly, set the flag so we don't give the window focus anyway
2200 * and confuse people.
2201 */
2202
2203 takes_focus_on_map = FALSE(0);
2204
2205 overlap = windows_overlap (window, focus_window);
2206
2207 /* We want alt tab to go to the denied-focus window */
2208 ensure_mru_position_after (window, focus_window);
2209
2210 /* We don't want the denied-focus window to obscure the focus
2211 * window, and if we're in both click-to-focus mode and
2212 * raise-on-click mode then we want to maintain the invariant
2213 * that MRU order == stacking order. The need for this if
2214 * comes from the fact that in sloppy/mouse focus the focus
2215 * window may not overlap other windows and also can be
2216 * considered "below" them; this combination means that
2217 * placing the denied-focus window "below" the focus window
2218 * in the stack when it doesn't overlap it confusingly places
2219 * that new window below a lot of other windows.
2220 */
2221 if (!will_be_covered && (overlap ||
2222 (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK &&
2223 meta_prefs_get_raise_on_click ())))
2224 meta_window_stack_just_below (window, focus_window);
2225
2226 /* If the window will be obscured by the focus window or a window set to
2227 * always on top, then the user might not notice the window appearing so
2228 * set the demands attention hint.
2229 *
2230 * We set the hint ourselves rather than calling
2231 * meta_window_set_demands_attention() because that would cause
2232 * a recalculation of overlap, and a call to set_net_wm_state()
2233 * which we are going to call ourselves here a few lines down.
2234 */
2235 if (overlap || will_be_covered)
2236 window->wm_state_demands_attention = TRUE(!(0));
2237 }
2238
2239 /* Shaded means the frame is mapped but the window is not */
2240
2241 if (window->frame && !window->frame->mapped)
2242 {
2243 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2244 "Frame actually needs map\n");
2245 window->frame->mapped = TRUE(!(0));
2246 meta_ui_map_frame (window->screen->ui, window->frame->xwindow);
2247 did_show = TRUE(!(0));
2248 }
2249
2250 if (window->shaded)
2251 {
2252 if (window->mapped)
2253 {
2254 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2255 "%s actually needs unmap (shaded)\n", window->desc);
2256 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2257 "Incrementing unmaps_pending on %s for shade\n",
2258 window->desc);
2259 window->mapped = FALSE(0);
2260 window->unmaps_pending += 1;
2261 meta_error_trap_push (window->display);
2262 XUnmapWindow (window->display->xdisplay, window->xwindow);
2263 meta_error_trap_pop (window->display, FALSE(0));
2264 }
2265
2266 if (!window->iconic)
2267 {
2268 window->iconic = TRUE(!(0));
2269 set_wm_state (window, IconicState3);
2270 }
2271 }
2272 else
2273 {
2274 if (!window->mapped)
2275 {
2276 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2277 "%s actually needs map\n", window->desc);
2278 window->mapped = TRUE(!(0));
2279 meta_error_trap_push (window->display);
2280 XMapWindow (window->display->xdisplay, window->xwindow);
2281 meta_error_trap_pop (window->display, FALSE(0));
2282 did_show = TRUE(!(0));
2283
2284 if (window->was_minimized)
2285 {
2286 MetaRectangle window_rect;
2287 MetaRectangle icon_rect;
2288
2289 window->was_minimized = FALSE(0);
2290
2291 if (meta_window_get_icon_geometry (window, &icon_rect))
2292 {
2293 meta_window_get_outer_rect (window, &window_rect);
2294
2295 meta_effect_run_unminimize (window,
2296 &window_rect,
2297 &icon_rect,
2298 NULL((void*)0), NULL((void*)0));
2299 }
2300 }
2301 }
2302
2303 if (window->iconic)
2304 {
2305 window->iconic = FALSE(0);
2306 set_wm_state (window, NormalState1);
2307 }
2308 }
2309
2310 /* We don't want to worry about all cases from inside
2311 * implement_showing(); we only want to worry about focus if this
2312 * window has not been shown before.
2313 */
2314 if (window->showing_for_first_time)
2315 {
2316 window->showing_for_first_time = FALSE(0);
2317 if (takes_focus_on_map)
2318 {
2319 meta_window_focus (window, timestamp);
2320
2321 if (window->move_after_placement)
2322 {
2323 meta_window_begin_grab_op(window, META_GRAB_OP_KEYBOARD_MOVING,
2324 FALSE(0), timestamp);
2325 window->move_after_placement = FALSE(0);
2326 }
2327 }
2328 else
2329 {
2330 /* Prevent EnterNotify events in sloppy/mouse focus from
2331 * erroneously focusing the window that had been denied
2332 * focus. FIXME: This introduces a race; I have a couple
2333 * ideas for a better way to accomplish the same thing, but
2334 * they're more involved so do it this way for now.
2335 */
2336 meta_display_increment_focus_sentinel (window->display);
2337 }
2338 }
2339
2340 set_net_wm_state (window);
2341
2342 if (did_show && window->struts)
2343 {
2344 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2345 "Mapped window %s with struts, so invalidating work areas\n",
2346 window->desc);
2347 invalidate_work_areas (window);
2348 }
2349
2350 /*
2351 * Now that we have shown the window, we no longer want to consider the
2352 * initial timestamp in any subsequent deliberations whether to focus this
2353 * window or not, so clear the flag.
2354 *
2355 * See http://bugzilla.gnome.org/show_bug.cgi?id=573922
2356 */
2357 window->initial_timestamp_set = FALSE(0);
2358}
2359
2360/* XXX META_EFFECT_*_UNMAP */
2361static void
2362meta_window_hide (MetaWindow *window)
2363{
2364 gboolean did_hide;
2365
2366 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2367 "Hiding window %s\n", window->desc);
2368
2369 did_hide = FALSE(0);
2370
2371 if (window->frame && window->frame->mapped)
2372 {
2373 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE, "Frame actually needs unmap\n");
2374 window->frame->mapped = FALSE(0);
2375 meta_ui_unmap_frame (window->screen->ui, window->frame->xwindow);
2376 did_hide = TRUE(!(0));
2377 }
2378
2379 if (window->mapped)
2380 {
2381 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2382 "%s actually needs unmap\n", window->desc);
2383 meta_topicmeta_topic_real (META_DEBUG_WINDOW_STATE,
2384 "Incrementing unmaps_pending on %s for hide\n",
2385 window->desc);
2386 window->mapped = FALSE(0);
2387 window->unmaps_pending += 1;
2388 meta_error_trap_push (window->display);
2389 XUnmapWindow (window->display->xdisplay, window->xwindow);
2390 meta_error_trap_pop (window->display, FALSE(0));
2391 did_hide = TRUE(!(0));
2392 }
2393
2394 if (!window->iconic)
2395 {
2396 window->iconic = TRUE(!(0));
2397 set_wm_state (window, IconicState3);
2398 }
2399
2400 set_net_wm_state (window);
2401
2402 if (did_hide && window->struts)
2403 {
2404 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2405 "Unmapped window %s with struts, so invalidating work areas\n",
2406 window->desc);
2407 invalidate_work_areas (window);
2408 }
2409}
2410
2411static gboolean
2412queue_calc_showing_func (MetaWindow *window,
2413 void *data)
2414{
2415 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
2416 return TRUE(!(0));
2417}
2418
2419void
2420meta_window_minimize (MetaWindow *window)
2421{
2422 if (!window->minimized)
2423 {
2424 window->minimized = TRUE(!(0));
2425 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
2426
2427 meta_window_foreach_transient (window,
2428 queue_calc_showing_func,
2429 NULL((void*)0));
2430
2431 set_allowed_actions_hint (window);
2432
2433 if (window->has_focus)
2434 {
2435 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
2436 "Focusing default window due to minimization of focus window %s\n",
2437 window->desc);
2438 }
2439 else
2440 {
2441 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
2442 "Minimizing window %s which doesn't have the focus\n",
2443 window->desc);
2444 }
2445 }
2446}
2447
2448void
2449meta_window_unminimize (MetaWindow *window)
2450{
2451 if (window->minimized)
2452 {
2453 window->minimized = FALSE(0);
2454 window->was_minimized = TRUE(!(0));
2455 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
2456
2457 meta_window_foreach_transient (window,
2458 queue_calc_showing_func,
2459 NULL((void*)0));
2460
2461 set_allowed_actions_hint (window);
2462 }
2463}
2464
2465static void
2466ensure_size_hints_satisfied (MetaRectangle *rect,
2467 const XSizeHints *size_hints)
2468{
2469 int minw, minh, maxw, maxh; /* min/max width/height */
2470 int basew, baseh, winc, hinc; /* base width/height, width/height increment */
2471 int extra_width, extra_height;
2472
2473 minw = size_hints->min_width; minh = size_hints->min_height;
2474 maxw = size_hints->max_width; maxh = size_hints->max_height;
2475 basew = size_hints->base_width; baseh = size_hints->base_height;
2476 winc = size_hints->width_inc; hinc = size_hints->height_inc;
2477
2478 /* First, enforce min/max size constraints */
2479 rect->width = CLAMP (rect->width, minw, maxw)(((rect->width) > (maxw)) ? (maxw) : (((rect->width)
< (minw)) ? (minw) : (rect->width)))
;
2480 rect->height = CLAMP (rect->height, minh, maxh)(((rect->height) > (maxh)) ? (maxh) : (((rect->height
) < (minh)) ? (minh) : (rect->height)))
;
2481
2482 /* Now, verify size increment constraints are satisfied, or make them be */
2483 extra_width = (rect->width - basew) % winc;
2484 extra_height = (rect->height - baseh) % hinc;
2485
2486 rect->width -= extra_width;
2487 rect->height -= extra_height;
2488
2489 /* Adjusting width/height down, as done above, may violate minimum size
2490 * constraints, so one last fix.
2491 */
2492 if (rect->width < minw)
2493 rect->width += ((minw - rect->width)/winc + 1)*winc;
2494 if (rect->height < minh)
2495 rect->height += ((minh - rect->height)/hinc + 1)*hinc;
2496}
2497
2498static void
2499meta_window_save_rect (MetaWindow *window)
2500{
2501 if (!(META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
||
2502 META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
||
2503 META_WINDOW_CORNER_TILED(window)((window)->tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT))
||
2504 window->fullscreen))
2505 {
2506 /* save size/pos as appropriate args for move_resize */
2507 if (!window->maximized_horizontally)
2508 {
2509 window->saved_rect.x = window->rect.x;
2510 window->saved_rect.width = window->rect.width;
2511 if (window->frame)
2512 window->saved_rect.x += window->frame->rect.x;
2513 }
2514 if (!window->maximized_vertically)
2515 {
2516 window->saved_rect.y = window->rect.y;
2517 window->saved_rect.height = window->rect.height;
2518 if (window->frame)
2519 window->saved_rect.y += window->frame->rect.y;
2520 }
2521 }
2522}
2523
2524/**
2525 * Save the user_rect regardless of whether the window is maximized or
2526 * fullscreen. See save_user_window_placement() for most uses.
2527 *
2528 * \param window Store current position of this window for future reference
2529 */
2530static void
2531force_save_user_window_placement (MetaWindow *window)
2532{
2533 meta_window_get_client_root_coords (window, &window->user_rect);
2534}
2535
2536/**
2537 * Save the user_rect, but only if the window is neither maximized nor
2538 * fullscreen, otherwise the window may snap back to those dimensions
2539 * (bug #461927).
2540 *
2541 * \param window Store current position of this window for future reference
2542 */
2543static void
2544save_user_window_placement (MetaWindow *window)
2545{
2546 if (!(META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
|| META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
|| window->fullscreen))
2547 {
2548 MetaRectangle user_rect;
2549
2550 meta_window_get_client_root_coords (window, &user_rect);
2551
2552 if (!window->maximized_horizontally)
2553 {
2554 window->user_rect.x = user_rect.x;
2555 window->user_rect.width = user_rect.width;
2556 }
2557 if (!window->maximized_vertically)
2558 {
2559 window->user_rect.y = user_rect.y;
2560 window->user_rect.height = user_rect.height;
2561 }
2562 }
2563}
2564
2565void
2566meta_window_maximize_internal (MetaWindow *window,
2567 MetaMaximizeFlags directions,
2568 MetaRectangle *saved_rect)
2569{
2570 /* At least one of the two directions ought to be set */
2571 gboolean maximize_horizontally, maximize_vertically;
2572 maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
2573 maximize_vertically = directions & META_MAXIMIZE_VERTICAL;
2574 g_assert (maximize_horizontally || maximize_vertically)do { if (maximize_horizontally || maximize_vertically) ; else
g_assertion_message_expr ("marco", "core/window.c", 2574, ((
const char*) (__func__)), "maximize_horizontally || maximize_vertically"
); } while (0)
;
2575
2576 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
2577 "Maximizing %s%s\n",
2578 window->desc,
2579 maximize_horizontally && maximize_vertically ? "" :
2580 maximize_horizontally ? " horizontally" :
2581 maximize_vertically ? " vertically" : "BUGGGGG");
2582
2583 if (saved_rect != NULL((void*)0))
2584 window->saved_rect = *saved_rect;
2585 else
2586 meta_window_save_rect (window);
2587
2588 if (maximize_horizontally && maximize_vertically)
2589 window->saved_maximize = TRUE(!(0));
2590
2591 window->maximized_horizontally =
2592 window->maximized_horizontally || maximize_horizontally;
2593 window->maximized_vertically =
2594 window->maximized_vertically || maximize_vertically;
2595
2596 /* Fix for #336850: If the frame shape isn't reapplied, it is
2597 * possible that the frame will retains its rounded corners. That
2598 * happens if the client's size when maximized equals the unmaximized
2599 * size.
2600 */
2601 if (window->frame)
2602 window->frame->need_reapply_frame_shape = TRUE(!(0));
2603
2604 recalc_window_features (window);
2605 set_allowed_actions_hint (window);
2606 set_net_wm_state (window);
2607}
2608
2609void
2610meta_window_maximize (MetaWindow *window,
2611 MetaMaximizeFlags directions)
2612{
2613 MetaRectangle *saved_rect = NULL((void*)0);
2614 /* At least one of the two directions ought to be set */
2615 gboolean maximize_horizontally, maximize_vertically;
2616 maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
2617 maximize_vertically = directions & META_MAXIMIZE_VERTICAL;
2618 g_assert (maximize_horizontally || maximize_vertically)do { if (maximize_horizontally || maximize_vertically) ; else
g_assertion_message_expr ("marco", "core/window.c", 2618, ((
const char*) (__func__)), "maximize_horizontally || maximize_vertically"
); } while (0)
;
2619
2620 /* Only do something if the window isn't already maximized in the
2621 * given direction(s).
2622 */
2623 if ((maximize_horizontally && !window->maximized_horizontally) ||
2624 (maximize_vertically && !window->maximized_vertically))
2625 {
2626 if (window->shaded && maximize_vertically)
2627 {
2628 /* Shading sucks anyway; I'm not adding a timestamp argument
2629 * to this function just for this niche usage & corner case.
2630 */
2631 guint32 timestamp =
2632 meta_display_get_current_time_roundtrip (window->display);
2633 meta_window_unshade (window, timestamp);
2634 }
2635
2636 /* if the window hasn't been placed yet, we'll maximize it then
2637 */
2638 if (!window->placed)
2639 {
2640 window->maximize_horizontally_after_placement = window->maximize_horizontally_after_placement || maximize_horizontally;
2641 window->maximize_vertically_after_placement = window->maximize_vertically_after_placement || maximize_vertically;
2642 return;
2643 }
2644
2645 if (window->tile_mode != META_TILE_NONE)
2646 {
2647 saved_rect = &window->saved_rect;
2648
2649 window->maximized_vertically = FALSE(0);
2650 window->tile_mode = META_TILE_NONE;
2651 }
2652
2653 meta_window_maximize_internal (window,
2654 directions,
2655 saved_rect);
2656
2657 /* move_resize with new maximization constraints
2658 */
2659 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
2660
2661 meta_compositor_maximize_window (window->display->compositor, window);
2662 }
2663}
2664
2665static void
2666unmaximize_window_before_freeing (MetaWindow *window)
2667{
2668 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
2669 "Unmaximizing %s just before freeing\n",
2670 window->desc);
2671
2672 window->maximized_horizontally = FALSE(0);
2673 window->maximized_vertically = FALSE(0);
2674
2675 if (window->withdrawn) /* See bug #137185 */
2676 {
2677 window->rect = window->saved_rect;
2678 set_net_wm_state (window);
2679 }
2680 else if (window->screen->closing) /* See bug #358042 */
2681 {
2682 /* Do NOT update net_wm_state: this screen is closing,
2683 * it likely will be managed by another window manager
2684 * that will need the current _NET_WM_STATE atoms.
2685 * Moreover, it will need to know the unmaximized geometry,
2686 * therefore move_resize the window to saved_rect here
2687 * before closing it. */
2688 meta_window_move_resize (window,
2689 FALSE(0),
2690 window->saved_rect.x,
2691 window->saved_rect.y,
2692 window->saved_rect.width,
2693 window->saved_rect.height);
2694 }
2695}
2696
2697void
2698meta_window_tile (MetaWindow *window)
2699{
2700 /* Don't do anything if no tiling is requested */
2701 if (window->tile_mode == META_TILE_NONE)
2702 return;
2703
2704 if (window->tile_mode == META_TILE_LEFT ||
2705 window->tile_mode == META_TILE_RIGHT)
2706 {
2707 MetaRectangle *saved_rect = NULL((void*)0);
2708 saved_rect = &window->saved_rect;
2709 meta_window_maximize_internal (window, META_MAXIMIZE_VERTICAL, saved_rect);
2710 }
2711 else if (window->tile_mode == META_TILE_BOTTOM_RIGHT ||
2712 window->tile_mode == META_TILE_BOTTOM_LEFT ||
2713 window->tile_mode == META_TILE_TOP_RIGHT ||
2714 window->tile_mode == META_TILE_TOP_LEFT)
2715 {
2716 MetaRectangle *saved_rect = NULL((void*)0);
2717 saved_rect = &window->saved_rect;
2718 meta_window_maximize_internal (window, META_MAXIMIZE_HORIZONTAL, saved_rect);
2719 }
2720 else
2721 meta_window_save_rect (window);
2722
2723 window->tiled = TRUE(!(0));
2724 /* move_resize with new tiling constraints
2725 */
2726 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2727
2728 set_allowed_actions_hint (window);
2729}
2730
2731void
2732meta_window_untile (MetaWindow *window)
2733{
2734 window->tiled = FALSE(0);
2735
2736 meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL);
2737}
2738
2739static gboolean
2740meta_window_can_tile_maximized (MetaWindow *window)
2741{
2742 return window->has_maximize_func;
2743}
2744
2745gboolean
2746meta_window_can_tile (MetaWindow *window)
2747{
2748 const MetaXineramaScreenInfo *monitor;
2749 MetaRectangle tile_area;
2750
2751 /*if (!META_WINDOW_ALLOWS_RESIZE (window))*/
2752 if (!meta_window_can_tile_maximized (window) || window->shaded)
2753 return FALSE(0);
2754
2755 monitor = meta_screen_get_current_xinerama (window->screen);
2756 meta_window_get_work_area_for_xinerama (window, monitor->number, &tile_area);
2757
2758 tile_area.width /= 2;
2759
2760 if (window->frame)
2761 {
2762 MetaFrameBorders borders;
2763
2764 meta_frame_calc_borders (window->frame, &borders);
2765
2766 tile_area.width -= (borders.visible.left + borders.visible.right);
2767 tile_area.height -= (borders.visible.top + borders.visible.bottom);
2768 }
2769
2770 return tile_area.width >= window->size_hints.min_width &&
2771 tile_area.height >= window->size_hints.min_height;
2772}
2773
2774void
2775meta_window_unmaximize (MetaWindow *window,
2776 MetaMaximizeFlags directions)
2777{
2778 /* At least one of the two directions ought to be set */
2779 gboolean unmaximize_horizontally, unmaximize_vertically;
2780
2781 unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
2782 unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL;
2783 g_assert (unmaximize_horizontally || unmaximize_vertically)do { if (unmaximize_horizontally || unmaximize_vertically) ; else
g_assertion_message_expr ("marco", "core/window.c", 2783, ((
const char*) (__func__)), "unmaximize_horizontally || unmaximize_vertically"
); } while (0)
;
2784
2785 if (unmaximize_horizontally && unmaximize_vertically)
2786 window->saved_maximize = FALSE(0);
2787
2788 window->tile_mode = META_TILE_NONE;
2789 window->tiled = FALSE(0);
2790
2791 /* Only do something if the window is already maximized in the
2792 * given direction(s).
2793 */
2794 if ((unmaximize_horizontally && window->maximized_horizontally) ||
2795 (unmaximize_vertically && window->maximized_vertically))
2796 {
2797 MetaRectangle target_rect;
2798
2799 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
2800 "Unmaximizing %s%s\n",
2801 window->desc,
2802 unmaximize_horizontally && unmaximize_vertically ? "" :
2803 unmaximize_horizontally ? " horizontally" :
2804 unmaximize_vertically ? " vertically" : "BUGGGGG");
2805
2806 window->maximized_horizontally =
2807 window->maximized_horizontally && !unmaximize_horizontally;
2808 window->maximized_vertically =
2809 window->maximized_vertically && !unmaximize_vertically;
2810
2811 /* Unmaximize to the saved_rect position in the direction(s)
2812 * being unmaximized.
2813 */
2814 meta_window_get_client_root_coords (window, &target_rect);
2815 if (unmaximize_horizontally)
2816 {
2817 target_rect.x = window->saved_rect.x;
2818 target_rect.width = window->saved_rect.width;
2819 }
2820 if (unmaximize_vertically)
2821 {
2822 target_rect.y = window->saved_rect.y;
2823 target_rect.height = window->saved_rect.height;
2824 }
2825
2826 /* Window's size hints may have changed while maximized, making
2827 * saved_rect invalid. #329152
2828 */
2829 ensure_size_hints_satisfied (&target_rect, &window->size_hints);
2830
2831 meta_window_move_resize (window,
2832 FALSE(0),
2833 target_rect.x,
2834 target_rect.y,
2835 target_rect.width,
2836 target_rect.height);
2837
2838 /* Make sure user_rect is current.
2839 */
2840 force_save_user_window_placement (window);
2841
2842 /* When we unmaximize, if we're doing a mouse move also we could
2843 * get the window suddenly jumping to the upper left corner of
2844 * the workspace, since that's where it was when the grab op
2845 * started. So we need to update the grab state. We have to do
2846 * it after the actual operation, as the window may have been moved
2847 * by constraints.
2848 */
2849 if (meta_grab_op_is_moving (window->display->grab_op) &&
2850 window->display->grab_window == window)
2851 {
2852 window->display->grab_anchor_window_pos = window->user_rect;
2853 }
2854
2855 if (window->display->grab_wireframe_active)
2856 {
2857 window->display->grab_wireframe_rect = target_rect;
2858 }
2859
2860 recalc_window_features (window);
2861 set_allowed_actions_hint (window);
2862 set_net_wm_state (window);
2863
2864 meta_compositor_unmaximize_window (window->display->compositor, window);
2865 }
2866}
2867
2868void
2869meta_window_move_to_monitor(MetaWindow *window,
2870 const MetaXineramaScreenInfo *from_monitor,
2871 const MetaXineramaScreenInfo *to_monitor)
2872{
2873 MetaRectangle target_rect;
2874
2875 if(META_WINDOW_TILED (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) || ((window)->
tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT)))
)
2876 {
2877 window->tile_monitor_number = to_monitor->number;
2878
2879 /* Transform user_rect and saved_rect to the other monitor */
2880 meta_window_transform_to_monitor(&window->saved_rect,
2881 &from_monitor->rect,
2882 &to_monitor->rect);
2883 meta_window_transform_to_monitor(&window->user_rect,
2884 &from_monitor->rect,
2885 &to_monitor->rect);
2886
2887 meta_window_tile(window);
2888 return;
2889 }
2890
2891 /* Normally, just transform the window itself */
2892 meta_window_get_client_root_coords(window, &target_rect);
2893
2894 meta_window_transform_to_monitor(&target_rect,
2895 &from_monitor->rect,
2896 &to_monitor->rect);
2897
2898 meta_window_move_resize(window, TRUE(!(0)),
2899 target_rect.x,
2900 target_rect.y,
2901 target_rect.width,
2902 target_rect.height);
2903}
2904
2905static void meta_window_transform_to_monitor(MetaRectangle *target_rect,
2906 const MetaRectangle *from_monitor,
2907 const MetaRectangle *to_monitor)
2908{
2909 double horizontal_ratio;
2910 double vertical_ratio;
2911
2912 horizontal_ratio = (double)to_monitor->width / from_monitor->width;
2913 vertical_ratio = (double)to_monitor->height / from_monitor->height;
2914
2915 target_rect->x -= from_monitor->x;
2916 target_rect->y -= from_monitor->y;
2917
2918 target_rect->width = (int) (horizontal_ratio * (double) target_rect->width);
2919 target_rect->height = (int) (vertical_ratio * (double) target_rect->height);
2920 target_rect->x = (int) (horizontal_ratio * (double) target_rect->x);
2921 target_rect->y = (int) (vertical_ratio * (double) target_rect->y);
2922
2923 target_rect->x += to_monitor->x;
2924 target_rect->y += to_monitor->y;
2925
2926}
2927
2928void
2929meta_window_make_above (MetaWindow *window)
2930{
2931 window->wm_state_above = TRUE(!(0));
2932 meta_window_update_layer (window);
2933 meta_window_raise (window);
2934 set_net_wm_state (window);
2935}
2936
2937void
2938meta_window_unmake_above (MetaWindow *window)
2939{
2940 window->wm_state_above = FALSE(0);
2941 meta_window_raise (window);
2942 meta_window_update_layer (window);
2943 set_net_wm_state (window);
2944}
2945
2946void
2947meta_window_make_fullscreen_internal (MetaWindow *window)
2948{
2949 if (!window->fullscreen)
2950 {
2951 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
2952 "Fullscreening %s\n", window->desc);
2953
2954 if (window->shaded)
2955 {
2956 /* Shading sucks anyway; I'm not adding a timestamp argument
2957 * to this function just for this niche usage & corner case.
2958 */
2959 guint32 timestamp =
2960 meta_display_get_current_time_roundtrip (window->display);
2961 meta_window_unshade (window, timestamp);
2962 }
2963
2964 meta_window_save_rect (window);
2965
2966 window->fullscreen = TRUE(!(0));
2967 window->tile_resized = FALSE(0);
2968 window->force_save_user_rect = FALSE(0);
2969
2970 meta_stack_freeze (window->screen->stack);
2971 meta_window_update_layer (window);
2972
2973 meta_window_raise (window);
2974 meta_stack_thaw (window->screen->stack);
2975
2976 recalc_window_features (window);
2977 set_allowed_actions_hint (window);
2978 set_net_wm_state (window);
2979 }
2980}
2981
2982void
2983meta_window_make_fullscreen (MetaWindow *window)
2984{
2985 if (!window->fullscreen)
2986 {
2987 meta_window_make_fullscreen_internal (window);
2988 /* move_resize with new constraints
2989 */
2990 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
2991 }
2992}
2993
2994void
2995meta_window_unmake_fullscreen (MetaWindow *window)
2996{
2997 if (window->fullscreen)
2998 {
2999 MetaRectangle target_rect;
3000
3001 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
3002 "Unfullscreening %s\n", window->desc);
3003
3004 window->fullscreen = FALSE(0);
3005
3006 if(!META_WINDOW_TILED (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) || ((window)->
tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT)))
)
3007 target_rect = window->saved_rect;
3008 else
3009 meta_window_get_current_tile_area(window, &target_rect);
3010
3011 /* Window's size hints may have changed while maximized, making
3012 * saved_rect invalid. #329152
3013 */
3014 ensure_size_hints_satisfied (&target_rect, &window->size_hints);
3015
3016 /* Need to update window->has_resize_func before we move_resize()
3017 */
3018 recalc_window_features (window);
3019 set_net_wm_state (window);
3020
3021 meta_window_move_resize (window,
3022 FALSE(0),
3023 target_rect.x,
3024 target_rect.y,
3025 target_rect.width,
3026 target_rect.height);
3027
3028 /* Make sure user_rect is current.
3029 */
3030 force_save_user_window_placement (window);
3031
3032 meta_window_update_layer (window);
3033 }
3034}
3035
3036void
3037meta_window_update_fullscreen_monitors (MetaWindow *window,
3038 unsigned long top,
3039 unsigned long bottom,
3040 unsigned long left,
3041 unsigned long right)
3042{
3043 if ((int)top < window->screen->n_xinerama_infos &&
3044 (int)bottom < window->screen->n_xinerama_infos &&
3045 (int)left < window->screen->n_xinerama_infos &&
3046 (int)right < window->screen->n_xinerama_infos)
3047 {
3048 window->fullscreen_monitors[0] = top;
3049 window->fullscreen_monitors[1] = bottom;
3050 window->fullscreen_monitors[2] = left;
3051 window->fullscreen_monitors[3] = right;
3052 }
3053 else
3054 {
3055 window->fullscreen_monitors[0] = -1;
3056 }
3057
3058 if (window->fullscreen)
3059 {
3060 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
3061 }
3062}
3063
3064void
3065meta_window_shade (MetaWindow *window,
3066 guint32 timestamp)
3067{
3068 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
3069 "Shading %s\n", window->desc);
3070 if (!window->shaded)
3071 {
3072 window->shaded = TRUE(!(0));
3073
3074 meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
3075
3076 set_allowed_actions_hint (window);
3077
3078 /* After queuing the calc showing, since _focus flushes it,
3079 * and we need to focus the frame
3080 */
3081 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
3082 "Re-focusing window %s after shading it\n",
3083 window->desc);
3084 meta_window_focus (window, timestamp);
3085
3086 set_net_wm_state (window);
3087 }
3088}
3089
3090void
3091meta_window_unshade (MetaWindow *window,
3092 guint32 timestamp)
3093{
3094 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
3095 "Unshading %s\n", window->desc);
3096 if (window->shaded)
3097 {
3098 window->shaded = FALSE(0);
3099 meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
3100
3101 set_allowed_actions_hint (window);
3102
3103 /* focus the window */
3104 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
3105 "Focusing window %s after unshading it\n",
3106 window->desc);
3107 meta_window_focus (window, timestamp);
3108
3109 set_net_wm_state (window);
3110 }
3111}
3112
3113static gboolean
3114unminimize_func (MetaWindow *window,
3115 void *data)
3116{
3117 meta_window_unminimize (window);
3118 return TRUE(!(0));
3119}
3120
3121static void
3122unminimize_window_and_all_transient_parents (MetaWindow *window)
3123{
3124 meta_window_unminimize (window);
3125 meta_window_foreach_ancestor (window, unminimize_func, NULL((void*)0));
3126}
3127
3128static void
3129window_activate (MetaWindow *window,
3130 guint32 timestamp,
3131 MetaClientType source_indication,
3132 MetaWorkspace *workspace)
3133{
3134 gboolean can_ignore_outdated_timestamps;
3135 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
3136 "_NET_ACTIVE_WINDOW message sent for %s at time %u "
3137 "by client type %u.\n",
3138 window->desc, timestamp, source_indication);
3139
3140 /* Older EWMH spec didn't specify a timestamp; we decide to honor these only
3141 * if the app specifies that it is a pager.
3142 *
3143 * Update: Unconditionally honor 0 timestamps for now; we'll fight
3144 * that battle later. Just remove the "FALSE &&" in order to only
3145 * honor 0 timestamps for pagers.
3146 */
3147 can_ignore_outdated_timestamps =
3148 (timestamp != 0 || (FALSE(0) && source_indication != META_CLIENT_TYPE_PAGER));
3149 if (XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time)( (timestamp) == 0 || (( (( (timestamp) < (window->display
->last_user_time) ) && ( (window->display->last_user_time
) - (timestamp) < ((guint32)-1)/2 )) || (( (timestamp) >
(window->display->last_user_time) ) && ( (timestamp
) - (window->display->last_user_time) > ((guint32)-1
)/2 )) ) && (window->display->last_user_time) !=
0) )
&&
3150 can_ignore_outdated_timestamps)
3151 {
3152 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
3153 "last_user_time (%u) is more recent; ignoring "
3154 " _NET_ACTIVE_WINDOW message.\n",
3155 window->display->last_user_time);
3156 meta_window_set_demands_attention(window);
3157 return;
3158 }
3159
3160 /* For those stupid pagers, get a valid timestamp and show a warning */
3161 if (timestamp == 0)
3162 {
3163 meta_warning ("meta_window_activate called by a pager with a 0 timestamp; "
3164 "the pager needs to be fixed.\n");
3165 timestamp = meta_display_get_current_time_roundtrip (window->display);
3166 }
3167
3168 meta_window_set_user_time (window, timestamp);
3169
3170 /* disable show desktop mode unless we're a desktop component */
3171 maybe_leave_show_desktop_mode (window);
3172
3173 /* Get window on current or given workspace */
3174 if (workspace == NULL((void*)0))
3175 workspace = window->screen->active_workspace;
3176
3177 /* For non-transient windows, we just set up a pulsing indicator,
3178 rather than move windows or workspaces.
3179 See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
3180 if (window->xtransient_for == None0L &&
3181 !meta_window_located_on_workspace (window, workspace))
3182 {
3183 meta_window_set_demands_attention (window);
3184 /* We've marked it as demanding, don't need to do anything else. */
3185 return;
3186 }
3187 else if (window->xtransient_for != None0L)
3188 {
3189 /* Move transients to current workspace - preference dialogs should appear over
3190 the source window. */
3191 meta_window_change_workspace (window, workspace);
3192 }
3193
3194 if (window->shaded)
3195 meta_window_unshade (window, timestamp);
3196
3197 unminimize_window_and_all_transient_parents (window);
3198
3199 if (meta_prefs_get_raise_on_click () ||
3200 source_indication == META_CLIENT_TYPE_PAGER)
3201 meta_window_raise (window);
3202
3203 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
3204 "Focusing window %s due to activation\n",
3205 window->desc);
3206 meta_window_focus (window, timestamp);
3207}
3208
3209/* This function exists since most of the functionality in window_activate
3210 * is useful for Marco, but Marco shouldn't need to specify a client
3211 * type for itself. ;-)
3212 */
3213void
3214meta_window_activate (MetaWindow *window,
3215 guint32 timestamp)
3216{
3217 /* We're not really a pager, but the behavior we want is the same as if
3218 * we were such. If we change the pager behavior later, we could revisit
3219 * this and just add extra flags to window_activate.
3220 */
3221 window_activate (window, timestamp, META_CLIENT_TYPE_PAGER, NULL((void*)0));
3222}
3223
3224void
3225meta_window_activate_with_workspace (MetaWindow *window,
3226 guint32 timestamp,
3227 MetaWorkspace *workspace)
3228{
3229 /* We're not really a pager, but the behavior we want is the same as if
3230 * we were such. If we change the pager behavior later, we could revisit
3231 * this and just add extra flags to window_activate.
3232 */
3233 window_activate (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace);
3234}
3235
3236/* Manually fix all the weirdness explained in the big comment at the
3237 * beginning of meta_window_move_resize_internal() giving positions
3238 * expected by meta_window_constrain (i.e. positions & sizes of the
3239 * internal or client window).
3240 */
3241static void
3242adjust_for_gravity (MetaWindow *window,
3243 MetaFrameBorders *borders,
3244 gboolean coords_assume_border,
3245 int gravity,
3246 MetaRectangle *rect)
3247{
3248 int ref_x, ref_y;
3249 int bw;
3250 int child_x, child_y;
3251 int frame_width, frame_height;
3252
3253 if (coords_assume_border)
3254 bw = window->border_width;
3255 else
3256 bw = 0;
3257
3258 if (borders)
3259 {
3260 child_x = borders->visible.left;
3261 child_y = borders->visible.top;
3262 frame_width = child_x + rect->width + borders->visible.right;
3263 frame_height = child_y + rect->height + borders->visible.bottom;
3264 }
3265 else
3266 {
3267 child_x = 0;
3268 child_y = 0;
3269 frame_width = rect->width;
3270 frame_height = rect->height;
3271 }
3272
3273 /* We're computing position to pass to window_move, which is
3274 * the position of the client window (StaticGravity basically)
3275 *
3276 * (see WM spec description of gravity computation, but note that
3277 * their formulas assume we're honoring the border width, rather
3278 * than compensating for having turned it off)
3279 */
3280 switch (gravity)
3281 {
3282 case NorthWestGravity1:
3283 ref_x = rect->x;
3284 ref_y = rect->y;
3285 break;
3286 case NorthGravity2:
3287 ref_x = rect->x + rect->width / 2 + bw;
3288 ref_y = rect->y;
3289 break;
3290 case NorthEastGravity3:
3291 ref_x = rect->x + rect->width + bw * 2;
3292 ref_y = rect->y;
3293 break;
3294 case WestGravity4:
3295 ref_x = rect->x;
3296 ref_y = rect->y + rect->height / 2 + bw;
3297 break;
3298 case CenterGravity5:
3299 ref_x = rect->x + rect->width / 2 + bw;
3300 ref_y = rect->y + rect->height / 2 + bw;
3301 break;
3302 case EastGravity6:
3303 ref_x = rect->x + rect->width + bw * 2;
3304 ref_y = rect->y + rect->height / 2 + bw;
3305 break;
3306 case SouthWestGravity7:
3307 ref_x = rect->x;
3308 ref_y = rect->y + rect->height + bw * 2;
3309 break;
3310 case SouthGravity8:
3311 ref_x = rect->x + rect->width / 2 + bw;
3312 ref_y = rect->y + rect->height + bw * 2;
3313 break;
3314 case SouthEastGravity9:
3315 ref_x = rect->x + rect->width + bw * 2;
3316 ref_y = rect->y + rect->height + bw * 2;
3317 break;
3318 case StaticGravity10:
3319 default:
3320 ref_x = rect->x;
3321 ref_y = rect->y;
3322 break;
3323 }
3324
3325 switch (gravity)
3326 {
3327 case NorthWestGravity1:
3328 rect->x = ref_x + child_x;
3329 rect->y = ref_y + child_y;
3330 break;
3331 case NorthGravity2:
3332 rect->x = ref_x - frame_width / 2 + child_x;
3333 rect->y = ref_y + child_y;
3334 break;
3335 case NorthEastGravity3:
3336 rect->x = ref_x - frame_width + child_x;
3337 rect->y = ref_y + child_y;
3338 break;
3339 case WestGravity4:
3340 rect->x = ref_x + child_x;
3341 rect->y = ref_y - frame_height / 2 + child_y;
3342 break;
3343 case CenterGravity5:
3344 rect->x = ref_x - frame_width / 2 + child_x;
3345 rect->y = ref_y - frame_height / 2 + child_y;
3346 break;
3347 case EastGravity6:
3348 rect->x = ref_x - frame_width + child_x;
3349 rect->y = ref_y - frame_height / 2 + child_y;
3350 break;
3351 case SouthWestGravity7:
3352 rect->x = ref_x + child_x;
3353 rect->y = ref_y - frame_height + child_y;
3354 break;
3355 case SouthGravity8:
3356 rect->x = ref_x - frame_width / 2 + child_x;
3357 rect->y = ref_y - frame_height + child_y;
3358 break;
3359 case SouthEastGravity9:
3360 rect->x = ref_x - frame_width + child_x;
3361 rect->y = ref_y - frame_height + child_y;
3362 break;
3363 case StaticGravity10:
3364 default:
3365 rect->x = ref_x;
3366 rect->y = ref_y;
3367 break;
3368 }
3369}
3370
3371static gboolean
3372static_gravity_works (MetaDisplay *display)
3373{
3374 return display->static_gravity_works;
3375}
3376
3377#ifdef HAVE_XSYNC
3378static void
3379send_sync_request (MetaWindow *window)
3380{
3381 XSyncValue value;
3382 XClientMessageEvent ev;
3383
3384 window->sync_request_serial++;
3385
3386 XSyncIntToValue (&value, window->sync_request_serial);
3387
3388 ev.type = ClientMessage33;
3389 ev.window = window->xwindow;
3390 ev.message_type = window->display->atom_WM_PROTOCOLS;
3391 ev.format = 32;
3392 ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST;
3393 /* FIXME: meta_display_get_current_time() is bad, but since calls
3394 * come from meta_window_move_resize_internal (which in turn come
3395 * from all over), I'm not sure what we can do to fix it. Do we
3396 * want to use _roundtrip, though?
3397 */
3398 ev.data.l[1] = meta_display_get_current_time (window->display);
3399 ev.data.l[2] = XSyncValueLow32 (value);
3400 ev.data.l[3] = XSyncValueHigh32 (value);
3401 ev.data.l[4] = 0;
3402
3403 /* We don't need to trap errors here as we are already
3404 * inside an error_trap_push()/pop() pair.
3405 */
3406 XSendEvent (window->display->xdisplay,
3407 window->xwindow, False0, 0, (XEvent*) &ev);
3408
3409 window->sync_request_time = g_get_real_time ();
3410}
3411#endif
3412
3413static gboolean
3414move_attached_dialog (MetaWindow *window,
3415 void *data)
3416{
3417 MetaWindow *parent = meta_window_get_transient_for (window);
3418
3419 if (window->type == META_WINDOW_MODAL_DIALOG && parent && parent != window)
3420 /* It ignores x,y for such a dialog */
3421 meta_window_move (window, FALSE(0), 0, 0);
3422
3423 return FALSE(0);
3424}
3425
3426static void
3427meta_window_move_resize_internal (MetaWindow *window,
3428 MetaMoveResizeFlags flags,
3429 int gravity,
3430 int root_x_nw,
3431 int root_y_nw,
3432 int w,
3433 int h)
3434{
3435 /* meta_window_move_resize_internal gets called with very different
3436 * meanings for root_x_nw and root_y_nw. w & h are always the area
3437 * of the inner or client window (i.e. excluding the frame) and
3438 * gravity is the relevant gravity associated with the request (note
3439 * that gravity is ignored for move-only operations unless its
3440 * e.g. a configure request). The location is different for
3441 * different cases because of how this function gets called; note
3442 * that in all cases what we want to find out is the upper left
3443 * corner of the position of the inner window:
3444 *
3445 * Case | Called from (flags; gravity)
3446 * -----+-----------------------------------------------
3447 * 1 | A resize only ConfigureRequest
3448 * 1 | meta_window_resize
3449 * 1 | meta_window_resize_with_gravity
3450 * 2 | New window
3451 * 2 | Session restore
3452 * 2 | A not-resize-only ConfigureRequest/net_moveresize_window request
3453 * 3 | meta_window_move
3454 * 3 | meta_window_move_resize
3455 *
3456 * For each of the cases, root_x_nw and root_y_nw must be treated as follows:
3457 *
3458 * (1) They should be entirely ignored; instead the previous position
3459 * and size of the window should be resized according to the given
3460 * gravity in order to determine the new position of the window.
3461 * (2) Needs to be fixed up by adjust_for_gravity() as these
3462 * coordinates are relative to some corner or side of the outer
3463 * window (except for the case of StaticGravity) and we want to
3464 * know the location of the upper left corner of the inner window.
3465 * (3) These values are already the desired positon of the NW corner
3466 * of the inner window
3467 */
3468 XWindowChanges values;
3469 unsigned int mask;
3470 gboolean need_configure_notify;
3471 MetaFrameBorders borders;
3472 gboolean need_move_client = FALSE(0);
3473 gboolean need_move_frame = FALSE(0);
3474 gboolean need_resize_client = FALSE(0);
3475 gboolean need_resize_frame = FALSE(0);
3476 int size_dx;
3477 int size_dy;
3478 gboolean frame_shape_changed = FALSE(0);
3479 gboolean is_configure_request;
3480 gboolean do_gravity_adjust;
3481 gboolean is_user_action;
3482 gboolean configure_frame_first;
3483 gboolean use_static_gravity;
3484 gboolean have_window_frame;
3485 /* used for the configure request, but may not be final
3486 * destination due to StaticGravity etc.
3487 */
3488 int client_move_x;
3489 int client_move_y;
3490 MetaRectangle new_rect;
3491 MetaRectangle old_rect;
3492
3493 if (window->frame)
3494 have_window_frame = TRUE(!(0));
3495 else
3496 have_window_frame = FALSE(0);
3497
3498 is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
3499 do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
3500 is_user_action = (flags & META_IS_USER_ACTION) != 0;
3501
3502 /* The action has to be a move or a resize or both... */
3503 g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))do { if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION
)) ; else g_assertion_message_expr ("marco", "core/window.c",
3503, ((const char*) (__func__)), "flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)"
); } while (0)
;
3504
3505 /* We don't need it in the idle queue anymore. */
3506 meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
3507
3508 meta_window_get_client_root_coords (window, &old_rect);
3509
3510 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
3511 "Move/resize %s to %d,%d %dx%d%s%s from %d,%d %dx%d\n",
3512 window->desc, root_x_nw, root_y_nw, w, h,
3513 is_configure_request ? " (configure request)" : "",
3514 is_user_action ? " (user move/resize)" : "",
3515 old_rect.x, old_rect.y, old_rect.width, old_rect.height);
3516
3517 if (have_window_frame)
3518 meta_frame_calc_borders (window->frame, &borders);
3519
3520 new_rect.x = root_x_nw;
3521 new_rect.y = root_y_nw;
3522 new_rect.width = w;
3523 new_rect.height = h;
3524
3525 /* If this is a resize only, the position should be ignored and
3526 * instead obtained by resizing the old rectangle according to the
3527 * relevant gravity.
3528 */
3529 if ((flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) ==
3530 META_IS_RESIZE_ACTION)
3531 {
3532 meta_rectangle_resize_with_gravity (&old_rect,
3533 &new_rect,
3534 gravity,
3535 new_rect.width,
3536 new_rect.height);
3537
3538 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
3539 "Compensated for gravity in resize action; new pos %d,%d\n",
3540 new_rect.x, new_rect.y);
3541 }
3542 else if (is_configure_request || do_gravity_adjust)
3543 {
3544 adjust_for_gravity (window,
3545 have_window_frame ? &borders : NULL((void*)0),
3546 /* configure request coords assume
3547 * the border width existed
3548 */
3549 is_configure_request,
3550 gravity,
3551 &new_rect);
3552
3553 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
3554 "Compensated for configure_request/do_gravity_adjust needing "
3555 "weird positioning; new pos %d,%d\n",
3556 new_rect.x, new_rect.y);
3557 }
3558
3559 meta_window_constrain (window,
3560 have_window_frame ? &borders : NULL((void*)0),
3561 flags,
3562 gravity,
3563 &old_rect,
3564 &new_rect);
3565
3566 w = new_rect.width;
3567 h = new_rect.height;
3568 root_x_nw = new_rect.x;
3569 root_y_nw = new_rect.y;
3570
3571 if (w != window->rect.width ||
3572 h != window->rect.height)
3573 need_resize_client = TRUE(!(0));
3574
3575 window->rect.width = w;
3576 window->rect.height = h;
3577
3578 if (have_window_frame)
3579 {
3580 int frame_size_dx, frame_size_dy, new_w, new_h;
3581
3582 new_w = window->rect.width + borders.total.left + borders.total.right;
3583
3584 if (window->shaded)
3585 new_h = borders.total.top;
3586 else
3587 new_h = window->rect.height + borders.total.top + borders.total.bottom;
3588
3589 frame_size_dx = new_w - window->frame->rect.width;
3590 frame_size_dy = new_h - window->frame->rect.height;
3591
3592 need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
3593
3594 window->frame->rect.width = new_w;
3595 window->frame->rect.height = new_h;
3596
3597 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
3598 "Calculated frame size %dx%d\n",
3599 window->frame->rect.width,
3600 window->frame->rect.height);
3601 }
3602
3603 /* For nice effect, when growing the window we want to move/resize
3604 * the frame first, when shrinking the window we want to move/resize
3605 * the client first. If we grow one way and shrink the other,
3606 * see which way we're moving "more"
3607 *
3608 * Mail from Owen subject "Suggestion: Gravity and resizing from the left"
3609 * http://mail.gnome.org/archives/wm-spec-list/1999-November/msg00088.html
3610 *
3611 * An annoying fact you need to know in this code is that StaticGravity
3612 * does nothing if you _only_ resize or _only_ move the frame;
3613 * it must move _and_ resize, otherwise you get NorthWestGravity
3614 * behavior. The move and resize must actually occur, it is not
3615 * enough to set CWX | CWWidth but pass in the current size/pos.
3616 */
3617
3618 if (have_window_frame)
3619 {
3620 int new_x, new_y;
3621 int frame_pos_dx, frame_pos_dy;
3622
3623 /* Compute new frame coords */
3624 new_x = root_x_nw - borders.total.left;
3625 new_y = root_y_nw - borders.total.top;
3626
3627 frame_pos_dx = new_x - window->frame->rect.x;
3628 frame_pos_dy = new_y - window->frame->rect.y;
3629
3630 need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
3631
3632 window->frame->rect.x = new_x;
3633 window->frame->rect.y = new_y;
3634
3635 /* If frame will both move and resize, then StaticGravity
3636 * on the child window will kick in and implicitly move
3637 * the child with respect to the frame. The implicit
3638 * move will keep the child in the same place with
3639 * respect to the root window. If frame only moves
3640 * or only resizes, then the child will just move along
3641 * with the frame.
3642 */
3643
3644 /* window->rect.x, window->rect.y are relative to frame,
3645 * remember they are the server coords
3646 */
3647
3648 new_x = borders.total.left;
3649 new_y = borders.total.top;
3650
3651 if (need_resize_frame && need_move_frame &&
3652 static_gravity_works (window->display))
3653 {
3654 /* static gravity kicks in because frame
3655 * is both moved and resized
3656 */
3657 /* when we move the frame by frame_pos_dx, frame_pos_dy the
3658 * client will implicitly move relative to frame by the
3659 * inverse delta.
3660 *
3661 * When moving client then frame, we move the client by the
3662 * frame delta, to be canceled out by the implicit move by
3663 * the inverse frame delta, resulting in a client at new_x,
3664 * new_y.
3665 *
3666 * When moving frame then client, we move the client
3667 * by the same delta as the frame, because the client
3668 * was "left behind" by the frame - resulting in a client
3669 * at new_x, new_y.
3670 *
3671 * In both cases we need to move the client window
3672 * in all cases where we had to move the frame window.
3673 */
3674
3675 client_move_x = new_x + frame_pos_dx;
3676 client_move_y = new_y + frame_pos_dy;
3677
3678 if (need_move_frame)
3679 need_move_client = TRUE(!(0));
3680
3681 use_static_gravity = TRUE(!(0));
3682 }
3683 else
3684 {
3685 client_move_x = new_x;
3686 client_move_y = new_y;
3687
3688 if (client_move_x != window->rect.x ||
3689 client_move_y != window->rect.y)
3690 need_move_client = TRUE(!(0));
3691
3692 use_static_gravity = FALSE(0);
3693 }
3694
3695 /* This is the final target position, but not necessarily what
3696 * we pass to XConfigureWindow, due to StaticGravity implicit
3697 * movement.
3698 */
3699 window->rect.x = new_x;
3700 window->rect.y = new_y;
3701 }
3702 else
3703 {
3704 if (root_x_nw != window->rect.x ||
3705 root_y_nw != window->rect.y)
3706 need_move_client = TRUE(!(0));
3707
3708 window->rect.x = root_x_nw;
3709 window->rect.y = root_y_nw;
3710
3711 client_move_x = window->rect.x;
3712 client_move_y = window->rect.y;
3713
3714 use_static_gravity = FALSE(0);
3715 }
3716
3717 /* If frame extents have changed, fill in other frame fields and
3718 change frame's extents property. */
3719 if (have_window_frame &&
3720 (window->frame->child_x != borders.total.left ||
3721 window->frame->child_y != borders.total.top ||
3722 window->frame->right_width != borders.total.right ||
3723 window->frame->bottom_height != borders.total.bottom))
3724 {
3725 window->frame->child_x = borders.total.left;
3726 window->frame->child_y = borders.total.top;
3727 window->frame->right_width = borders.total.right;
3728 window->frame->bottom_height = borders.total.bottom;
3729
3730 update_net_frame_extents (window);
3731 }
3732
3733 /* See ICCCM 4.1.5 for when to send ConfigureNotify */
3734
3735 need_configure_notify = FALSE(0);
3736
3737 /* If this is a configure request and we change nothing, then we
3738 * must send configure notify.
3739 */
3740 if (is_configure_request &&
3741 !(need_move_client || need_move_frame ||
3742 need_resize_client || need_resize_frame ||
3743 window->border_width != 0))
3744 need_configure_notify = TRUE(!(0));
3745
3746 /* We must send configure notify if we move but don't resize, since
3747 * the client window may not get a real event
3748 */
3749 if ((need_move_client || need_move_frame) &&
3750 !(need_resize_client || need_resize_frame))
3751 need_configure_notify = TRUE(!(0));
3752
3753 /* MapRequest events with a PPosition or UPosition hint with a frame
3754 * are moved by marco without resizing; send a configure notify
3755 * in such cases. See #322840. (Note that window->constructing is
3756 * only true iff this call is due to a MapRequest, and when
3757 * PPosition/UPosition hints aren't set, marco seems to send a
3758 * ConfigureNotify anyway due to the above code.)
3759 */
3760 if (window->constructing && have_window_frame &&
3761 ((window->size_hints.flags & PPosition(1L << 2)) ||
3762 (window->size_hints.flags & USPosition(1L << 0))))
3763 need_configure_notify = TRUE(!(0));
3764
3765 /* The rest of this function syncs our new size/pos with X as
3766 * efficiently as possible
3767 */
3768
3769 /* configure frame first if we grow more than we shrink
3770 */
3771 size_dx = w - window->rect.width;
3772 size_dy = h - window->rect.height;
3773
3774 configure_frame_first = (size_dx + size_dy >= 0);
3775
3776 if (use_static_gravity)
3777 meta_window_set_gravity (window, StaticGravity10);
3778
3779 if (configure_frame_first && have_window_frame)
3780 frame_shape_changed = meta_frame_sync_to_window (window->frame,
3781 gravity,
3782 need_move_frame,
3783 need_resize_frame);
3784
3785 values.border_width = 0;
3786 values.x = client_move_x;
3787 values.y = client_move_y;
3788 values.width = window->rect.width;
3789 values.height = window->rect.height;
3790
3791 mask = 0;
3792 if (is_configure_request && window->border_width != 0)
3793 mask |= CWBorderWidth(1<<4); /* must force to 0 */
3794 if (need_move_client)
3795 mask |= (CWX(1<<0) | CWY(1<<1));
3796 if (need_resize_client)
3797 mask |= (CWWidth(1<<2) | CWHeight(1<<3));
3798
3799 if (mask != 0)
3800 {
3801 {
3802 int newx, newy;
3803 meta_window_get_position (window, &newx, &newy);
3804 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
3805 "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
3806 newx, newy,
3807 window->rect.width, window->rect.height,
3808 mask & CWBorderWidth(1<<4) ? "true" : "false",
3809 need_move_client ? "true" : "false",
3810 need_resize_client ? "true" : "false");
3811 }
3812
3813 meta_error_trap_push (window->display);
3814
3815#ifdef HAVE_XSYNC
3816 if (window->sync_request_counter != None0L &&
3817 window->display->grab_sync_request_alarm != None0L &&
3818 window->sync_request_time == 0)
3819 {
3820 /* turn off updating */
3821 if (window->display->compositor)
3822 meta_compositor_set_updates (window->display->compositor, window, FALSE(0));
3823
3824 send_sync_request (window);
3825 }
3826#endif
3827
3828 XConfigureWindow (window->display->xdisplay,
3829 window->xwindow,
3830 mask,
3831 &values);
3832
3833 meta_error_trap_pop (window->display, FALSE(0));
3834 }
3835
3836 if (!configure_frame_first && have_window_frame)
3837 frame_shape_changed = meta_frame_sync_to_window (window->frame,
3838 gravity,
3839 need_move_frame,
3840 need_resize_frame);
3841
3842 /* Put gravity back to be nice to lesser window managers */
3843 if (use_static_gravity)
3844 meta_window_set_gravity (window, NorthWestGravity1);
3845
3846 if (need_configure_notify)
3847 send_configure_notify (window);
3848
3849 if (!window->placed && window->force_save_user_rect && !window->fullscreen)
3850 force_save_user_window_placement (window);
3851 else if (is_user_action)
3852 save_user_window_placement (window);
3853
3854 if (need_move_frame || need_resize_frame ||
3855 need_move_client || need_resize_client)
3856 {
3857 int newx, newy;
3858 meta_window_get_position (window, &newx, &newy);
3859 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
3860 "New size/position %d,%d %dx%d (user %d,%d %dx%d)\n",
3861 newx, newy, window->rect.width, window->rect.height,
3862 window->user_rect.x, window->user_rect.y,
3863 window->user_rect.width, window->user_rect.height);
3864 }
3865 else
3866 {
3867 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY, "Size/position not modified\n");
3868 }
3869
3870 if (window->display->grab_wireframe_active)
3871 meta_window_update_wireframe (window, root_x_nw, root_y_nw, w, h);
3872 else
3873 meta_window_refresh_resize_popup (window);
3874
3875 /* Invariants leaving this function are:
3876 * a) window->rect and frame->rect reflect the actual
3877 * server-side size/pos of window->xwindow and frame->xwindow
3878 * b) all constraints are obeyed by window->rect and frame->rect
3879 */
3880 if (frame_shape_changed && window->frame_bounds)
3881 {
3882 cairo_region_destroy (window->frame_bounds);
3883 window->frame_bounds = NULL((void*)0);
3884 }
3885
3886 if (meta_prefs_get_attach_modal_dialogs ())
3887 meta_window_foreach_transient (window, move_attached_dialog, NULL((void*)0));
3888}
3889
3890void
3891meta_window_resize (MetaWindow *window,
3892 gboolean user_op,
3893 int w,
3894 int h)
3895{
3896 int x, y;
3897 MetaMoveResizeFlags flags;
3898
3899 meta_window_get_position (window, &x, &y);
3900
3901 flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
3902 meta_window_move_resize_internal (window,
3903 flags,
3904 NorthWestGravity1,
3905 x, y, w, h);
3906}
3907
3908void
3909meta_window_move (MetaWindow *window,
3910 gboolean user_op,
3911 int root_x_nw,
3912 int root_y_nw)
3913{
3914 MetaMoveResizeFlags flags =
3915 (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION;
3916 meta_window_move_resize_internal (window,
3917 flags,
3918 NorthWestGravity1,
3919 root_x_nw, root_y_nw,
3920 window->rect.width,
3921 window->rect.height);
3922}
3923
3924void
3925meta_window_move_resize (MetaWindow *window,
3926 gboolean user_op,
3927 int root_x_nw,
3928 int root_y_nw,
3929 int w,
3930 int h)
3931{
3932 MetaMoveResizeFlags flags =
3933 (user_op ? META_IS_USER_ACTION : 0) |
3934 META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
3935 meta_window_move_resize_internal (window,
3936 flags,
3937 NorthWestGravity1,
3938 root_x_nw, root_y_nw,
3939 w, h);
3940}
3941
3942void
3943meta_window_resize_with_gravity (MetaWindow *window,
3944 gboolean user_op,
3945 int w,
3946 int h,
3947 int gravity)
3948{
3949 int x, y;
3950 MetaMoveResizeFlags flags;
3951
3952 meta_window_get_position (window, &x, &y);
3953
3954 flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
3955 meta_window_move_resize_internal (window,
3956 flags,
3957 gravity,
3958 x, y, w, h);
3959}
3960
3961static void
3962meta_window_move_resize_now (MetaWindow *window)
3963{
3964 /* If constraints have changed then we want to snap back to wherever
3965 * the user had the window. We use user_rect for this reason. See
3966 * also bug 426519 comment 3.
3967 */
3968 meta_window_move_resize (window, FALSE(0),
3969 window->user_rect.x,
3970 window->user_rect.y,
3971 window->user_rect.width,
3972 window->user_rect.height);
3973}
3974
3975static gboolean
3976idle_move_resize (gpointer data)
3977{
3978 GSList *tmp;
3979 GSList *copy;
3980 guint queue_index = GPOINTER_TO_INT (data)((gint) (glong) (data));
3981
3982 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY, "Clearing the move_resize queue\n");
3983
3984 /* Work with a copy, for reentrancy. The allowed reentrancy isn't
3985 * complete; destroying a window while we're in here would result in
3986 * badness. But it's OK to queue/unqueue move_resizes.
3987 */
3988 copy = g_slist_copy (queue_pending[queue_index]);
3989 g_slist_free (queue_pending[queue_index]);
3990 queue_pending[queue_index] = NULL((void*)0);
3991 queue_idle[queue_index] = 0;
3992
3993 destroying_windows_disallowed += 1;
3994
3995 tmp = copy;
3996 while (tmp != NULL((void*)0))
3997 {
3998 MetaWindow *window;
3999
4000 window = tmp->data;
4001
4002 /* As a side effect, sets window->move_resize_queued = FALSE */
4003 meta_window_move_resize_now (window);
4004
4005 tmp = tmp->next;
4006 }
4007
4008 g_slist_free (copy);
4009
4010 destroying_windows_disallowed -= 1;
4011
4012 return FALSE(0);
4013}
4014
4015void
4016meta_window_get_position (MetaWindow *window,
4017 int *x,
4018 int *y)
4019{
4020 if (window->frame)
4021 {
4022 if (x)
4023 *x = window->frame->rect.x + window->frame->child_x;
4024 if (y)
4025 *y = window->frame->rect.y + window->frame->child_y;
4026 }
4027 else
4028 {
4029 if (x)
4030 *x = window->rect.x;
4031 if (y)
4032 *y = window->rect.y;
4033 }
4034}
4035
4036void
4037meta_window_get_client_root_coords (MetaWindow *window,
4038 MetaRectangle *rect)
4039{
4040 meta_window_get_position (window, &rect->x, &rect->y);
4041 rect->width = window->rect.width;
4042 rect->height = window->rect.height;
4043}
4044
4045void
4046meta_window_get_gravity_position (MetaWindow *window,
4047 int gravity,
4048 int *root_x,
4049 int *root_y)
4050{
4051 MetaRectangle frame_extents;
4052 int w, h;
4053 int x, y;
4054
4055 w = window->rect.width;
4056 h = window->rect.height;
4057
4058 if (gravity == StaticGravity10)
4059 {
4060 frame_extents = window->rect;
4061 if (window->frame)
4062 {
4063 frame_extents.x = window->frame->rect.x + window->frame->child_x;
4064 frame_extents.y = window->frame->rect.y + window->frame->child_y;
4065 }
4066 }
4067 else
4068 {
4069 if (window->frame == NULL((void*)0))
4070 frame_extents = window->rect;
4071 else
4072 frame_extents = window->frame->rect;
4073 }
4074
4075 x = frame_extents.x;
4076 y = frame_extents.y;
4077
4078 switch (gravity)
4079 {
4080 case NorthGravity2:
4081 case CenterGravity5:
4082 case SouthGravity8:
4083 /* Find center of frame. */
4084 x += frame_extents.width / 2;
4085 /* Center client window on that point. */
4086 x -= w / 2;
4087 break;
4088
4089 case SouthEastGravity9:
4090 case EastGravity6:
4091 case NorthEastGravity3:
4092 /* Find right edge of frame */
4093 x += frame_extents.width;
4094 /* Align left edge of client at that point. */
4095 x -= w;
4096 break;
4097 default:
4098 break;
4099 }
4100
4101 switch (gravity)
4102 {
4103 case WestGravity4:
4104 case CenterGravity5:
4105 case EastGravity6:
4106 /* Find center of frame. */
4107 y += frame_extents.height / 2;
4108 /* Center client window there. */
4109 y -= h / 2;
4110 break;
4111 case SouthWestGravity7:
4112 case SouthGravity8:
4113 case SouthEastGravity9:
4114 /* Find south edge of frame */
4115 y += frame_extents.height;
4116 /* Place bottom edge of client there */
4117 y -= h;
4118 break;
4119 default:
4120 break;
4121 }
4122
4123 if (root_x)
4124 *root_x = x;
4125 if (root_y)
4126 *root_y = y;
4127}
4128
4129void
4130meta_window_get_geometry (MetaWindow *window,
4131 int *x,
4132 int *y,
4133 int *width,
4134 int *height)
4135{
4136 meta_window_get_gravity_position (window,
4137 window->size_hints.win_gravity,
4138 x, y);
4139
4140 *width = (window->rect.width - window->size_hints.base_width) /
4141 window->size_hints.width_inc;
4142 *height = (window->rect.height - window->size_hints.base_height) /
4143 window->size_hints.height_inc;
4144}
4145
4146/**
4147 * meta_window_get_input_rect:
4148 * @window: a #MetaWindow
4149 * @rect: (out): pointer to an allocated #MetaRectangle
4150 *
4151 * Gets the rectangle that bounds @window that is responsive to mouse events.
4152 * This includes decorations - the visible portion of its border - and (if
4153 * present) any invisible area that we make make responsive to mouse clicks in
4154 * order to allow convenient border dragging.
4155 */
4156void
4157meta_window_get_input_rect (const MetaWindow *window,
4158 MetaRectangle *rect)
4159{
4160 if (window->frame)
4161 *rect = window->frame->rect;
4162 else
4163 *rect = window->rect;
4164}
4165
4166/**
4167 * meta_window_get_outer_rect:
4168 * @window: a #MetaWindow
4169 * @rect: (out): pointer to an allocated #MetaRectangle
4170 *
4171 * Gets the rectangle that bounds @window that is responsive to mouse events.
4172 * This includes only what is visible; it doesn't include any extra reactive
4173 * area we add to the edges of windows.
4174 */
4175void
4176meta_window_get_outer_rect (const MetaWindow *window,
4177 MetaRectangle *rect)
4178{
4179 if (window->frame)
4180 {
4181 MetaFrameBorders borders;
4182 *rect = window->frame->rect;
4183 meta_frame_calc_borders (window->frame, &borders);
4184
4185 rect->x += borders.invisible.left;
4186 rect->y += borders.invisible.top;
4187 rect->width -= borders.invisible.left + borders.invisible.right;
4188 rect->height -= borders.invisible.top + borders.invisible.bottom;
4189 }
4190 else
4191 {
4192 *rect = window->rect;
4193
4194 if (window->has_custom_frame_extents)
4195 {
4196 const GtkBorder *extents = &window->custom_frame_extents;
4197 rect->x += extents->left;
4198 rect->y += extents->top;
4199 rect->width -= extents->left + extents->right;
4200 rect->height -= extents->top + extents->bottom;
4201 }
4202 }
4203}
4204
4205void
4206meta_window_get_xor_rect (MetaWindow *window,
4207 const MetaRectangle *grab_wireframe_rect,
4208 MetaRectangle *xor_rect)
4209{
4210 if (window->frame)
4211 {
4212 xor_rect->x = grab_wireframe_rect->x - window->frame->child_x;
4213 xor_rect->y = grab_wireframe_rect->y - window->frame->child_y;
4214 xor_rect->width = grab_wireframe_rect->width + window->frame->child_x + window->frame->right_width;
4215
4216 if (window->shaded)
4217 xor_rect->height = window->frame->child_y;
4218 else
4219 xor_rect->height = grab_wireframe_rect->height + window->frame->child_y + window->frame->bottom_height;
4220 }
4221 else
4222 *xor_rect = *grab_wireframe_rect;
4223}
4224
4225/* Figure out the numbers that show up in the
4226 * resize popup when in reduced resources mode.
4227 */
4228static void
4229meta_window_get_wireframe_geometry (MetaWindow *window,
4230 int *width,
4231 int *height)
4232{
4233 if (!window->display->grab_wireframe_active)
4234 return;
4235
4236 if ((width == NULL((void*)0)) || (height == NULL((void*)0)))
4237 return;
4238
4239 if ((window->display->grab_window->size_hints.width_inc <= 1) ||
4240 (window->display->grab_window->size_hints.height_inc <= 1))
4241 {
4242 *width = -1;
4243 *height = -1;
4244 return;
4245 }
4246
4247 *width = window->display->grab_wireframe_rect.width -
4248 window->display->grab_window->size_hints.base_width;
4249 *width /= window->display->grab_window->size_hints.width_inc;
4250
4251 *height = window->display->grab_wireframe_rect.height -
4252 window->display->grab_window->size_hints.base_height;
4253 *height /= window->display->grab_window->size_hints.height_inc;
4254}
4255
4256/* XXX META_EFFECT_ALT_TAB, well, this and others */
4257void
4258meta_window_begin_wireframe (MetaWindow *window)
4259{
4260
4261 MetaRectangle new_xor;
4262 int display_width, display_height;
4263
4264 display_width = 0;
4265 display_height = 0;
4266
4267 meta_window_get_client_root_coords (window,
4268 &window->display->grab_wireframe_rect);
4269
4270 meta_window_get_xor_rect (window, &window->display->grab_wireframe_rect,
4271 &new_xor);
4272 meta_window_get_wireframe_geometry (window, &display_width, &display_height);
4273
4274 meta_effects_begin_wireframe (window->screen,
4275 &new_xor, display_width, display_height);
4276
4277 window->display->grab_wireframe_last_xor_rect = new_xor;
4278 window->display->grab_wireframe_last_display_width = display_width;
4279 window->display->grab_wireframe_last_display_height = display_height;
4280}
4281
4282void
4283meta_window_update_wireframe (MetaWindow *window,
4284 int x,
4285 int y,
4286 int width,
4287 int height)
4288{
4289
4290 MetaRectangle new_xor;
4291 int display_width, display_height;
4292
4293 display_width = 0;
4294 display_height = 0;
4295
4296 window->display->grab_wireframe_rect.x = x;
4297 window->display->grab_wireframe_rect.y = y;
4298 window->display->grab_wireframe_rect.width = width;
4299 window->display->grab_wireframe_rect.height = height;
4300
4301 meta_window_get_xor_rect (window, &window->display->grab_wireframe_rect,
4302 &new_xor);
4303 meta_window_get_wireframe_geometry (window, &display_width, &display_height);
4304
4305 meta_effects_update_wireframe (window->screen,
4306 &window->display->grab_wireframe_last_xor_rect,
4307 window->display->grab_wireframe_last_display_width,
4308 window->display->grab_wireframe_last_display_height,
4309 &new_xor, display_width, display_height);
4310
4311 window->display->grab_wireframe_last_xor_rect = new_xor;
4312 window->display->grab_wireframe_last_display_width = display_width;
4313 window->display->grab_wireframe_last_display_height = display_height;
4314}
4315
4316void
4317meta_window_end_wireframe (MetaWindow *window)
4318{
4319 meta_effects_end_wireframe (window->display->grab_window->screen,
4320 &window->display->grab_wireframe_last_xor_rect,
4321 window->display->grab_wireframe_last_display_width,
4322 window->display->grab_wireframe_last_display_height);
4323}
4324
4325const char*
4326meta_window_get_startup_id (MetaWindow *window)
4327{
4328 if (window->startup_id == NULL((void*)0))
4329 {
4330 MetaGroup *group;
4331
4332 group = meta_window_get_group (window);
4333
4334 if (group != NULL((void*)0))
4335 return meta_group_get_startup_id (group);
4336 }
4337
4338 return window->startup_id;
4339}
4340
4341static MetaWindow*
4342get_modal_transient (MetaWindow *window)
4343{
4344 GSList *windows;
4345 GSList *tmp;
4346 MetaWindow *modal_transient;
4347
4348 /* A window can't be the transient of itself, but this is just for
4349 * convenience in the loop below; we manually fix things up at the
4350 * end if no real modal transient was found.
4351 */
4352 modal_transient = window;
4353
4354 windows = meta_display_list_windows (window->display);
4355 tmp = windows;
4356 while (tmp != NULL((void*)0))
4357 {
4358 MetaWindow *transient = tmp->data;
4359
4360 if (transient->xtransient_for == modal_transient->xwindow &&
4361 transient->wm_state_modal)
4362 {
4363 modal_transient = transient;
4364 tmp = windows;
4365 continue;
4366 }
4367
4368 tmp = tmp->next;
4369 }
4370
4371 g_slist_free (windows);
4372
4373 if (window == modal_transient)
4374 modal_transient = NULL((void*)0);
4375
4376 return modal_transient;
4377}
4378
4379/* XXX META_EFFECT_FOCUS */
4380void
4381meta_window_focus (MetaWindow *window,
4382 guint32 timestamp)
4383{
4384 MetaWindow *modal_transient;
4385
4386 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4387 "Setting input focus to window %s, input: %d take_focus: %d\n",
4388 window->desc, window->input, window->take_focus);
4389
4390 if (window->display->grab_window &&
4391 window->display->grab_window->all_keys_grabbed)
4392 {
4393 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4394 "Current focus window %s has global keygrab, not focusing window %s after all\n",
4395 window->display->grab_window->desc, window->desc);
4396 return;
4397 }
4398
4399 modal_transient = get_modal_transient (window);
4400 if (modal_transient != NULL((void*)0) &&
4401 !modal_transient->unmanaging)
4402 {
4403 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4404 "%s has %s as a modal transient, so focusing it instead.\n",
4405 window->desc, modal_transient->desc);
4406 if (!modal_transient->on_all_workspaces &&
4407 modal_transient->workspace != window->screen->active_workspace)
4408 meta_window_change_workspace (modal_transient,
4409 window->screen->active_workspace);
4410 window = modal_transient;
4411 }
4412
4413 meta_window_flush_calc_showing (window);
4414
4415 if (!window->mapped && !window->shaded)
4416 {
4417 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4418 "Window %s is not showing, not focusing after all\n",
4419 window->desc);
4420 return;
4421 }
4422
4423 /* For output-only or shaded windows, focus the frame.
4424 * This seems to result in the client window getting key events
4425 * though, so I don't know if it's icccm-compliant.
4426 *
4427 * Still, we have to do this or keynav breaks for these windows.
4428 */
4429 if (window->frame &&
4430 (window->shaded ||
4431 !(window->input || window->take_focus)))
4432 {
4433 if (window->frame)
4434 {
4435 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4436 "Focusing frame of %s\n", window->desc);
4437 meta_display_set_input_focus_window (window->display,
4438 window,
4439 TRUE(!(0)),
4440 timestamp);
4441 }
4442 }
4443 else
4444 {
4445 if (window->input)
4446 {
4447 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4448 "Setting input focus on %s since input = true\n",
4449 window->desc);
4450 meta_display_set_input_focus_window (window->display,
4451 window,
4452 FALSE(0),
4453 timestamp);
4454 }
4455
4456 if (window->take_focus)
4457 {
4458 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
4459 "Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
4460 window->desc);
4461 meta_window_send_icccm_message (window,
4462 window->display->atom_WM_TAKE_FOCUS,
4463 timestamp);
4464 window->display->expected_focus_window = window;
4465 }
4466 }
4467
4468 if (window->wm_state_demands_attention)
4469 meta_window_unset_demands_attention(window);
4470
4471 meta_effect_run_focus(window, NULL((void*)0), NULL((void*)0));
4472}
4473
4474static void
4475meta_window_change_workspace_without_transients (MetaWindow *window,
4476 MetaWorkspace *workspace)
4477{
4478 meta_verbosemeta_verbose_real ("Changing window %s to workspace %d\n",
4479 window->desc, meta_workspace_index (workspace));
4480
4481 /* unstick if stuck. meta_window_unstick would call
4482 * meta_window_change_workspace recursively if the window
4483 * is not in the active workspace.
4484 */
4485 if (window->on_all_workspaces)
4486 meta_window_unstick (window);
4487
4488 /* See if we're already on this space. If not, make sure we are */
4489 if (window->workspace != workspace)
4490 {
4491 meta_workspace_remove_window (window->workspace, window);
4492 meta_workspace_add_window (workspace, window);
4493 }
4494}
4495
4496static gboolean
4497change_workspace_foreach (MetaWindow *window,
4498 void *data)
4499{
4500 meta_window_change_workspace_without_transients (window, data);
4501 return TRUE(!(0));
4502}
4503
4504void
4505meta_window_change_workspace (MetaWindow *window,
4506 MetaWorkspace *workspace)
4507{
4508 meta_window_change_workspace_without_transients (window, workspace);
4509
4510 meta_window_foreach_transient (window, change_workspace_foreach,
4511 workspace);
4512 meta_window_foreach_ancestor (window, change_workspace_foreach,
4513 workspace);
4514}
4515
4516static void
4517window_stick_impl (MetaWindow *window)
4518{
4519 GList *tmp;
4520 MetaWorkspace *workspace;
4521
4522 meta_verbosemeta_verbose_real ("Sticking window %s current on_all_workspaces = %d\n",
4523 window->desc, window->on_all_workspaces);
4524
4525 if (window->on_all_workspaces)
4526 return;
4527
4528 /* We don't change window->workspaces, because we revert
4529 * to that original workspace list if on_all_workspaces is
4530 * toggled back off.
4531 */
4532 window->on_all_workspaces = TRUE(!(0));
4533
4534 /* We do, however, change the MRU lists of all the workspaces
4535 */
4536 tmp = window->screen->workspaces;
4537 while (tmp)
4538 {
4539 workspace = (MetaWorkspace *) tmp->data;
4540 if (!g_list_find (workspace->mru_list, window))
4541 workspace->mru_list = g_list_prepend (workspace->mru_list, window);
4542
4543 tmp = tmp->next;
4544 }
4545
4546 meta_window_set_current_workspace_hint (window);
4547
4548 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
4549}
4550
4551static void
4552window_unstick_impl (MetaWindow *window)
4553{
4554 GList *tmp;
4555 MetaWorkspace *workspace;
4556
4557 if (!window->on_all_workspaces)
4558 return;
4559
4560 /* Revert to window->workspaces */
4561
4562 window->on_all_workspaces = FALSE(0);
4563
4564 /* Remove window from MRU lists that it doesn't belong in */
4565 tmp = window->screen->workspaces;
4566 while (tmp)
4567 {
4568 workspace = (MetaWorkspace *) tmp->data;
4569 if (window->workspace != workspace)
4570 workspace->mru_list = g_list_remove (workspace->mru_list, window);
4571 tmp = tmp->next;
4572 }
4573
4574 /* We change ourselves to the active workspace, since otherwise you'd get
4575 * a weird window-vaporization effect. Once we have UI for being
4576 * on more than one workspace this should probably be add_workspace
4577 * not change_workspace.
4578 */
4579 if (window->screen->active_workspace != window->workspace)
4580 meta_window_change_workspace (window, window->screen->active_workspace);
4581
4582 meta_window_set_current_workspace_hint (window);
4583
4584 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
4585}
4586
4587static gboolean
4588stick_foreach_func (MetaWindow *window,
4589 void *data)
4590{
4591 gboolean stick;
4592
4593 stick = *(gboolean*)data;
4594 if (stick)
4595 window_stick_impl (window);
4596 else
4597 window_unstick_impl (window);
4598 return TRUE(!(0));
4599}
4600
4601void
4602meta_window_stick (MetaWindow *window)
4603{
4604 gboolean stick = TRUE(!(0));
4605 window_stick_impl (window);
4606 meta_window_foreach_transient (window,
4607 stick_foreach_func,
4608 &stick);
4609}
4610
4611void
4612meta_window_unstick (MetaWindow *window)
4613{
4614 gboolean stick = FALSE(0);
4615 window_unstick_impl (window);
4616 meta_window_foreach_transient (window,
4617 stick_foreach_func,
4618 &stick);
4619}
4620
4621unsigned long
4622meta_window_get_net_wm_desktop (MetaWindow *window)
4623{
4624 if (window->on_all_workspaces)
4625 return 0xFFFFFFFF;
4626 else
4627 return meta_workspace_index (window->workspace);
4628}
4629
4630static void
4631update_net_frame_extents (MetaWindow *window)
4632{
4633 unsigned long data[4] = { 0, 0, 0, 0 };
4634
4635 if (window->frame)
4636 {
4637 MetaFrameBorders borders;
4638
4639 meta_frame_calc_borders (window->frame, &borders);
4640 /* Left */
4641 data[0] = borders.visible.left;
4642 /* Right */
4643 data[1] = borders.visible.right;
4644 /* Top */
4645 data[2] = borders.visible.top;
4646 /* Bottom */
4647 data[3] = borders.visible.bottom;
4648 }
4649
4650 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
4651 "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
4652 "to left = %lu, right = %lu, top = %lu, bottom = %lu\n",
4653 window->xwindow, data[0], data[1], data[2], data[3]);
4654
4655 meta_error_trap_push (window->display);
4656 XChangeProperty (window->display->xdisplay, window->xwindow,
4657 window->display->atom__NET_FRAME_EXTENTS,
4658 XA_CARDINAL((Atom) 6),
4659 32, PropModeReplace0, (guchar*) data, 4);
4660 meta_error_trap_pop (window->display, FALSE(0));
4661}
4662
4663void
4664meta_window_set_current_workspace_hint (MetaWindow *window)
4665{
4666 /* FIXME if on more than one workspace, we claim to be "sticky",
4667 * the WM spec doesn't say what to do here.
4668 */
4669 unsigned long data[1];
4670
4671 if (window->workspace == NULL((void*)0))
4672 {
4673 /* this happens when unmanaging windows */
4674 return;
4675 }
4676
4677 data[0] = meta_window_get_net_wm_desktop (window);
4678
4679 meta_verbosemeta_verbose_real ("Setting _NET_WM_DESKTOP of %s to %lu\n",
4680 window->desc, data[0]);
4681
4682 meta_error_trap_push (window->display);
4683 XChangeProperty (window->display->xdisplay, window->xwindow,
4684 window->display->atom__NET_WM_DESKTOP,
4685 XA_CARDINAL((Atom) 6),
4686 32, PropModeReplace0, (guchar*) data, 1);
4687 meta_error_trap_pop (window->display, FALSE(0));
4688}
4689
4690static gboolean
4691find_root_ancestor (MetaWindow *window,
4692 void *data)
4693{
4694 MetaWindow **ancestor = data;
4695
4696 /* Overwrite the previously "most-root" ancestor with the new one found */
4697 *ancestor = window;
4698
4699 /* We want this to continue until meta_window_foreach_ancestor quits because
4700 * there are no more valid ancestors.
4701 */
4702 return TRUE(!(0));
4703}
4704
4705MetaWindow *
4706meta_window_find_root_ancestor (MetaWindow *window)
4707{
4708 MetaWindow *ancestor;
4709 ancestor = window;
4710 meta_window_foreach_ancestor (window, find_root_ancestor, &ancestor);
4711 return ancestor;
4712}
4713
4714void
4715meta_window_raise (MetaWindow *window)
4716{
4717 MetaWindow *ancestor;
4718 ancestor = meta_window_find_root_ancestor (window);
4719
4720 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
4721 "Raising window %s, ancestor of %s\n",
4722 ancestor->desc, window->desc);
4723
4724 /* Raise the ancestor of the window (if the window has no ancestor,
4725 * then ancestor will be set to the window itself); do this because
4726 * it's weird to see windows from other apps stacked between a child
4727 * and parent window of the currently active app. The stacking
4728 * constraints in stack.c then magically take care of raising all
4729 * the child windows appropriately.
4730 */
4731 if (window->screen->stack == ancestor->screen->stack)
4732 meta_stack_raise (window->screen->stack, ancestor);
4733 else
4734 {
4735 meta_warning (
4736 "Either stacks aren't per screen or some window has a weird "
4737 "transient_for hint; window->screen->stack != "
4738 "ancestor->screen->stack. window = %s, ancestor = %s.\n",
4739 window->desc, ancestor->desc);
4740 /* We could raise the window here, but don't want to do that twice and
4741 * so we let the case below handle that.
4742 */
4743 }
4744
4745 /* Okay, so stacking constraints misses one case: If a window has
4746 * two children and we want to raise one of those children, then
4747 * raising the ancestor isn't enough; we need to also raise the
4748 * correct child. See bug 307875.
4749 */
4750 if (window != ancestor)
4751 meta_stack_raise (window->screen->stack, window);
4752}
4753
4754void
4755meta_window_lower (MetaWindow *window)
4756{
4757 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
4758 "Lowering window %s\n", window->desc);
4759
4760 meta_stack_lower (window->screen->stack, window);
4761}
4762
4763void
4764meta_window_send_icccm_message (MetaWindow *window,
4765 Atom atom,
4766 guint32 timestamp)
4767{
4768 /* This comment and code are from twm, copyright
4769 * Open Group, Evans & Sutherland, etc.
4770 */
4771
4772 /*
4773 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
4774 * client messages will have the following form:
4775 *
4776 * event type ClientMessage
4777 * message type _XA_WM_PROTOCOLS
4778 * window tmp->w
4779 * format 32
4780 * data[0] message atom
4781 * data[1] time stamp
4782 */
4783
4784 XClientMessageEvent ev;
4785
4786 ev.type = ClientMessage33;
4787 ev.window = window->xwindow;
4788 ev.message_type = window->display->atom_WM_PROTOCOLS;
4789 ev.format = 32;
4790 ev.data.l[0] = atom;
4791 ev.data.l[1] = timestamp;
4792
4793 meta_error_trap_push (window->display);
4794 XSendEvent (window->display->xdisplay,
4795 window->xwindow, False0, 0, (XEvent*) &ev);
4796 meta_error_trap_pop (window->display, FALSE(0));
4797}
4798
4799void
4800meta_window_move_resize_request (MetaWindow *window,
4801 guint value_mask,
4802 int gravity,
4803 int new_x,
4804 int new_y,
4805 int new_width,
4806 int new_height)
4807{
4808 int x, y, width, height;
4809 gboolean allow_position_change;
4810 gboolean in_grab_op;
4811 MetaMoveResizeFlags flags;
4812
4813 /* We ignore configure requests while the user is moving/resizing
4814 * the window, since these represent the app sucking and fighting
4815 * the user, most likely due to a bug in the app (e.g. pfaedit
4816 * seemed to do this)
4817 *
4818 * Still have to do the ConfigureNotify and all, but pretend the
4819 * app asked for the current size/position instead of the new one.
4820 */
4821 in_grab_op = FALSE(0);
4822 if (window->display->grab_op != META_GRAB_OP_NONE &&
4823 window == window->display->grab_window)
4824 {
4825 switch (window->display->grab_op)
4826 {
4827 case META_GRAB_OP_MOVING:
4828 case META_GRAB_OP_RESIZING_SE:
4829 case META_GRAB_OP_RESIZING_S:
4830 case META_GRAB_OP_RESIZING_SW:
4831 case META_GRAB_OP_RESIZING_N:
4832 case META_GRAB_OP_RESIZING_NE:
4833 case META_GRAB_OP_RESIZING_NW:
4834 case META_GRAB_OP_RESIZING_W:
4835 case META_GRAB_OP_RESIZING_E:
4836 in_grab_op = TRUE(!(0));
4837 break;
4838 default:
4839 break;
4840 }
4841 }
4842
4843 /* it's essential to use only the explicitly-set fields,
4844 * and otherwise use our current up-to-date position.
4845 *
4846 * Otherwise you get spurious position changes when the app changes
4847 * size, for example, if window->rect is not in sync with the
4848 * server-side position in effect when the configure request was
4849 * generated.
4850 */
4851 meta_window_get_gravity_position (window,
4852 gravity,
4853 &x, &y);
4854
4855 allow_position_change = FALSE(0);
4856
4857 if (meta_prefs_get_disable_workarounds ())
4858 {
4859 if (window->type == META_WINDOW_DIALOG ||
4860 window->type == META_WINDOW_MODAL_DIALOG ||
4861 window->type == META_WINDOW_SPLASHSCREEN)
4862 ; /* No position change for these */
4863 else if ((window->size_hints.flags & PPosition(1L << 2)) ||
4864 /* USPosition is just stale if window is placed;
4865 * no --geometry involved here.
4866 */
4867 ((window->size_hints.flags & USPosition(1L << 0)) &&
4868 !window->placed))
4869 allow_position_change = TRUE(!(0));
4870 }
4871 else
4872 {
4873 allow_position_change = TRUE(!(0));
4874 }
4875
4876 if (in_grab_op)
4877 allow_position_change = FALSE(0);
4878
4879 if (allow_position_change)
4880 {
4881 if (value_mask & CWX(1<<0))
4882 x = new_x;
4883 if (value_mask & CWY(1<<1))
4884 y = new_y;
4885 if (value_mask & (CWX(1<<0) | CWY(1<<1)))
4886 {
4887 /* Once manually positioned, windows shouldn't be placed
4888 * by the window manager.
4889 */
4890 window->placed = TRUE(!(0));
4891 }
4892 }
4893 else
4894 {
4895 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
4896 "Not allowing position change for window %s PPosition 0x%lx USPosition 0x%lx type %u\n",
4897 window->desc, window->size_hints.flags & PPosition(1L << 2),
4898 window->size_hints.flags & USPosition(1L << 0),
4899 window->type);
4900 }
4901
4902 width = window->rect.width;
4903 height = window->rect.height;
4904 if (!in_grab_op)
4905 {
4906 if (value_mask & CWWidth(1<<2))
4907 width = new_width;
4908
4909 if (value_mask & CWHeight(1<<3))
4910 height = new_height;
4911 }
4912
4913 /* ICCCM 4.1.5 */
4914
4915 /* We're ignoring the value_mask here, since sizes
4916 * not in the mask will be the current window geometry.
4917 */
4918 window->size_hints.x = x;
4919 window->size_hints.y = y;
4920 window->size_hints.width = width;
4921 window->size_hints.height = height;
4922
4923 /* NOTE: We consider ConfigureRequests to be "user" actions in one
4924 * way, but not in another. Explanation of the two cases are in the
4925 * next two big comments.
4926 */
4927
4928 /* The constraints code allows user actions to move windows
4929 * offscreen, etc., and configure request actions would often send
4930 * windows offscreen when users don't want it if not constrained
4931 * (e.g. hitting a dropdown triangle in a fileselector to show more
4932 * options, which makes the window bigger). Thus we do not set
4933 * META_IS_USER_ACTION in flags to the
4934 * meta_window_move_resize_internal() call.
4935 */
4936 flags = META_IS_CONFIGURE_REQUEST;
4937 if (value_mask & (CWX(1<<0) | CWY(1<<1)))
4938 flags |= META_IS_MOVE_ACTION;
4939 if (value_mask & (CWWidth(1<<2) | CWHeight(1<<3)))
4940 flags |= META_IS_RESIZE_ACTION;
4941
4942 if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
4943 {
4944 const MetaXineramaScreenInfo *xinerama_info;
4945 MetaRectangle rect;
4946
4947 rect.x = x;
4948 rect.y = y;
4949 rect.width = width;
4950 rect.height = height;
4951
4952 xinerama_info = meta_screen_get_xinerama_for_rect (window->screen, &rect);
4953
4954 /* Workaround braindead legacy apps that don't know how to
4955 * fullscreen themselves properly - don't get fooled by
4956 * windows which are client decorated; that's not the same
4957 * as fullscreen, even if there are no struts making the
4958 * workarea smaller than the monitor.
4959 */
4960 if (meta_prefs_get_force_fullscreen() &&
4961 (window->decorated || !meta_window_is_client_decorated (window)) &&
4962 meta_rectangle_equal (&rect, &xinerama_info->rect) &&
4963 window->has_fullscreen_func &&
4964 !window->fullscreen)
4965 {
4966 g_warning ("Treating resize request of legacy application %s as a "
4967 "fullscreen request", window->desc);
4968 meta_window_make_fullscreen_internal (window);
4969 }
4970 meta_window_move_resize_internal (window,
4971 flags,
4972 gravity,
4973 x,
4974 y,
4975 width,
4976 height);
4977
4978 }
4979
4980 /* window->user_rect exists to allow "snapping-back" the window if a
4981 * new strut is set (causing the window to move) and then the strut
4982 * is later removed without the user moving the window in the
4983 * interim. We'd like to "snap-back" to the position specified by
4984 * ConfigureRequest events (at least the constrained version of the
4985 * ConfigureRequest, since that is guaranteed to be onscreen) so we
4986 * set user_rect here.
4987 *
4988 * See also bug 426519.
4989 */
4990 save_user_window_placement (window);
4991}
4992
4993gboolean
4994meta_window_configure_request (MetaWindow *window,
4995 XEvent *event)
4996{
4997 /* Note that x, y is the corner of the window border,
4998 * and width, height is the size of the window inside
4999 * its border, but that we always deny border requests
5000 * and give windows a border of 0. But we save the
5001 * requested border here.
5002 */
5003 if (event->xconfigurerequest.value_mask & CWBorderWidth(1<<4))
5004 window->border_width = event->xconfigurerequest.border_width;
5005
5006 meta_window_move_resize_request(window,
5007 event->xconfigurerequest.value_mask,
5008 window->size_hints.win_gravity,
5009 event->xconfigurerequest.x,
5010 event->xconfigurerequest.y,
5011 event->xconfigurerequest.width,
5012 event->xconfigurerequest.height);
5013
5014 /* Handle stacking. We only handle raises/lowers, mostly because
5015 * stack.c really can't deal with anything else. I guess we'll fix
5016 * that if a client turns up that really requires it. Only a very
5017 * few clients even require the raise/lower (and in fact all client
5018 * attempts to deal with stacking order are essentially broken,
5019 * since they have no idea what other clients are involved or how
5020 * the stack looks).
5021 *
5022 * I'm pretty sure no interesting client uses TopIf, BottomIf, or
5023 * Opposite anyway, so the only possible missing thing is
5024 * Above/Below with a sibling set. For now we just pretend there's
5025 * never a sibling set and always do the full raise/lower instead of
5026 * the raise-just-above/below-sibling.
5027 */
5028 if (event->xconfigurerequest.value_mask & CWStackMode(1<<6))
5029 {
5030 MetaWindow *active_window;
5031 active_window = window->display->expected_focus_window;
5032 if (meta_prefs_get_disable_workarounds ())
5033 {
5034 meta_topicmeta_topic_real (META_DEBUG_STACK,
5035 "%s sent an xconfigure stacking request; this is "
5036 "broken behavior and the request is being ignored.\n",
5037 window->desc);
5038 }
5039 else if (active_window &&
5040 !meta_window_same_application (window, active_window) &&
5041 !meta_window_same_client (window, active_window) &&
5042 XSERVER_TIME_IS_BEFORE (window->net_wm_user_time,( (window->net_wm_user_time) == 0 || (( (( (window->net_wm_user_time
) < (active_window->net_wm_user_time) ) && ( (active_window
->net_wm_user_time) - (window->net_wm_user_time) < (
(guint32)-1)/2 )) || (( (window->net_wm_user_time) > (active_window
->net_wm_user_time) ) && ( (window->net_wm_user_time
) - (active_window->net_wm_user_time) > ((guint32)-1)/2
)) ) && (active_window->net_wm_user_time) != 0) )
5043 active_window->net_wm_user_time)( (window->net_wm_user_time) == 0 || (( (( (window->net_wm_user_time
) < (active_window->net_wm_user_time) ) && ( (active_window
->net_wm_user_time) - (window->net_wm_user_time) < (
(guint32)-1)/2 )) || (( (window->net_wm_user_time) > (active_window
->net_wm_user_time) ) && ( (window->net_wm_user_time
) - (active_window->net_wm_user_time) > ((guint32)-1)/2
)) ) && (active_window->net_wm_user_time) != 0) )
)
5044 {
5045 meta_topicmeta_topic_real (META_DEBUG_STACK,
5046 "Ignoring xconfigure stacking request from %s (with "
5047 "user_time %u); currently active application is %s (with "
5048 "user_time %u).\n",
5049 window->desc,
5050 window->net_wm_user_time,
5051 active_window->desc,
5052 active_window->net_wm_user_time);
5053 if (event->xconfigurerequest.detail == Above0)
5054 meta_window_set_demands_attention(window);
5055 }
5056 else
5057 {
5058 switch (event->xconfigurerequest.detail)
5059 {
5060 case Above0:
5061 meta_window_raise (window);
5062 break;
5063 case Below1:
5064 meta_window_lower (window);
5065 break;
5066 case TopIf2:
5067 case BottomIf3:
5068 case Opposite4:
5069 break;
5070 }
5071 }
5072 }
5073
5074 return TRUE(!(0));
5075}
5076
5077gboolean
5078meta_window_property_notify (MetaWindow *window,
5079 XEvent *event)
5080{
5081 return process_property_notify (window, &event->xproperty);
5082}
5083
5084#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT0 0
5085#define _NET_WM_MOVERESIZE_SIZE_TOP1 1
5086#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT2 2
5087#define _NET_WM_MOVERESIZE_SIZE_RIGHT3 3
5088#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT4 4
5089#define _NET_WM_MOVERESIZE_SIZE_BOTTOM5 5
5090#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT6 6
5091#define _NET_WM_MOVERESIZE_SIZE_LEFT7 7
5092#define _NET_WM_MOVERESIZE_MOVE8 8
5093#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD9 9
5094#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD10 10
5095#define _NET_WM_MOVERESIZE_CANCEL11 11
5096
5097gboolean
5098meta_window_client_message (MetaWindow *window,
5099 XEvent *event)
5100{
5101 MetaDisplay *display;
5102
5103 display = window->display;
5104
5105 if (event->xclient.message_type ==
5106 display->atom__NET_CLOSE_WINDOW)
5107 {
5108 guint32 timestamp;
5109
5110 if (event->xclient.data.l[0] != 0)
5111 timestamp = event->xclient.data.l[0];
5112 else
5113 {
5114 meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without "
5115 "a timestamp! This means some buggy (outdated) "
5116 "application is on the loose!\n",
5117 window->desc);
5118 timestamp = meta_display_get_current_time (window->display);
5119 }
5120
5121 meta_window_delete (window, timestamp);
5122
5123 return TRUE(!(0));
5124 }
5125 else if (event->xclient.message_type ==
5126 display->atom__NET_WM_DESKTOP)
5127 {
5128 int space;
5129 MetaWorkspace *workspace;
5130
5131 space = event->xclient.data.l[0];
5132
5133 meta_verbosemeta_verbose_real ("Request to move %s to workspace %d\n",
5134 window->desc, space);
5135
5136 workspace =
5137 meta_screen_get_workspace_by_index (window->screen,
5138 space);
5139
5140 if (workspace)
5141 {
5142 if (window->on_all_workspaces)
5143 meta_window_unstick (window);
5144 meta_window_change_workspace (window, workspace);
5145 }
5146 else if (space == (int) 0xFFFFFFFF)
5147 {
5148 meta_window_stick (window);
5149 }
5150 else
5151 {
5152 meta_verbosemeta_verbose_real ("No such workspace %d for screen\n", space);
5153 }
5154
5155 meta_verbosemeta_verbose_real ("Window %s now on_all_workspaces = %d\n",
5156 window->desc, window->on_all_workspaces);
5157
5158 return TRUE(!(0));
5159 }
5160 else if (event->xclient.message_type ==
5161 display->atom__NET_WM_STATE)
5162 {
5163 gulong action;
5164 Atom first;
5165 Atom second;
5166
5167 action = event->xclient.data.l[0];
5168 first = event->xclient.data.l[1];
5169 second = event->xclient.data.l[2];
5170
5171 if (meta_is_verbose ())
5172 {
5173 char *str1;
5174 char *str2;
5175
5176 meta_error_trap_push (display);
5177 str1 = XGetAtomName (display->xdisplay, first);
5178 if (meta_error_trap_pop_with_return (display, TRUE(!(0))) != Success0)
5179 str1 = NULL((void*)0);
5180
5181 meta_error_trap_push (display);
5182 str2 = XGetAtomName (display->xdisplay, second);
5183 if (meta_error_trap_pop_with_return (display, TRUE(!(0))) != Success0)
5184 str2 = NULL((void*)0);
5185
5186 meta_verbosemeta_verbose_real ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n",
5187 action,
5188 str1 ? str1 : "(unknown)",
5189 str2 ? str2 : "(unknown)");
5190
5191 meta_XFree (str1)do { if ((str1)) XFree ((str1)); } while (0);
5192 meta_XFree (str2)do { if ((str2)) XFree ((str2)); } while (0);
5193 }
5194
5195 if (first == display->atom__NET_WM_STATE_SHADED ||
5196 second == display->atom__NET_WM_STATE_SHADED)
5197 {
5198 gboolean shade;
5199 guint32 timestamp;
5200
5201 /* Stupid protocol has no timestamp; of course, shading
5202 * sucks anyway so who really cares that we're forced to do
5203 * a roundtrip here?
5204 */
5205 timestamp = meta_display_get_current_time_roundtrip (window->display);
5206
5207 shade = (action == _NET_WM_STATE_ADD1 ||
5208 (action == _NET_WM_STATE_TOGGLE2 && !window->shaded));
5209 if (shade && window->has_shade_func)
5210 meta_window_shade (window, timestamp);
5211 else
5212 meta_window_unshade (window, timestamp);
5213 }
5214
5215 if (first == display->atom__NET_WM_STATE_FULLSCREEN ||
5216 second == display->atom__NET_WM_STATE_FULLSCREEN)
5217 {
5218 gboolean make_fullscreen;
5219
5220 make_fullscreen = (action == _NET_WM_STATE_ADD1 ||
5221 (action == _NET_WM_STATE_TOGGLE2 && !window->fullscreen));
5222 if (make_fullscreen && window->has_fullscreen_func)
5223 meta_window_make_fullscreen (window);
5224 else
5225 meta_window_unmake_fullscreen (window);
5226 }
5227
5228 if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ ||
5229 second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ)
5230 {
5231 gboolean max;
5232
5233 max = (action == _NET_WM_STATE_ADD1 ||
5234 (action == _NET_WM_STATE_TOGGLE2 &&
5235 !window->maximized_horizontally));
5236 if (max && window->has_maximize_func)
5237 {
5238 if (meta_prefs_get_raise_on_click ())
5239 meta_window_raise (window);
5240 meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
5241 }
5242 else
5243 {
5244 if (meta_prefs_get_raise_on_click ())
5245 meta_window_raise (window);
5246 meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
5247 }
5248 }
5249
5250 if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT ||
5251 second == display->atom__NET_WM_STATE_MAXIMIZED_VERT)
5252 {
5253 gboolean max;
5254
5255 max = (action == _NET_WM_STATE_ADD1 ||
5256 (action == _NET_WM_STATE_TOGGLE2 &&
5257 !window->maximized_vertically));
5258 if (max && window->has_maximize_func)
5259 {
5260 if (meta_prefs_get_raise_on_click ())
5261 meta_window_raise (window);
5262 meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
5263 }
5264 else
5265 {
5266 if (meta_prefs_get_raise_on_click ())
5267 meta_window_raise (window);
5268 meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
5269 }
5270 }
5271
5272 if (first == display->atom__NET_WM_STATE_MODAL ||
5273 second == display->atom__NET_WM_STATE_MODAL)
5274 {
5275 window->wm_state_modal =
5276 (action == _NET_WM_STATE_ADD1) ||
5277 (action == _NET_WM_STATE_TOGGLE2 && !window->wm_state_modal);
5278
5279 recalc_window_type (window);
5280 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
5281 }
5282
5283 if (first == display->atom__NET_WM_STATE_SKIP_PAGER ||
5284 second == display->atom__NET_WM_STATE_SKIP_PAGER)
5285 {
5286 window->wm_state_skip_pager =
5287 (action == _NET_WM_STATE_ADD1) ||
5288 (action == _NET_WM_STATE_TOGGLE2 && !window->skip_pager);
5289
5290 recalc_window_features (window);
5291 set_net_wm_state (window);
5292 }
5293
5294 if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR ||
5295 second == display->atom__NET_WM_STATE_SKIP_TASKBAR)
5296 {
5297 window->wm_state_skip_taskbar =
5298 (action == _NET_WM_STATE_ADD1) ||
5299 (action == _NET_WM_STATE_TOGGLE2 && !window->skip_taskbar);
5300
5301 recalc_window_features (window);
5302 set_net_wm_state (window);
5303 }
5304
5305 if (first == display->atom__NET_WM_STATE_ABOVE ||
5306 second == display->atom__NET_WM_STATE_ABOVE)
5307 {
5308 window->wm_state_above =
5309 (action == _NET_WM_STATE_ADD1) ||
5310 (action == _NET_WM_STATE_TOGGLE2 && !window->wm_state_above);
5311
5312 meta_window_update_layer (window);
5313 set_net_wm_state (window);
5314 }
5315
5316 if (first == display->atom__NET_WM_STATE_BELOW ||
5317 second == display->atom__NET_WM_STATE_BELOW)
5318 {
5319 window->wm_state_below =
5320 (action == _NET_WM_STATE_ADD1) ||
5321 (action == _NET_WM_STATE_TOGGLE2 && !window->wm_state_below);
5322
5323 meta_window_update_layer (window);
5324 set_net_wm_state (window);
5325 }
5326
5327 if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION ||
5328 second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION)
5329 {
5330 if ((action == _NET_WM_STATE_ADD1) ||
5331 (action == _NET_WM_STATE_TOGGLE2 && !window->wm_state_demands_attention))
5332 meta_window_set_demands_attention (window);
5333 else
5334 meta_window_unset_demands_attention (window);
5335 }
5336
5337 if (first == display->atom__NET_WM_STATE_STICKY ||
5338 second == display->atom__NET_WM_STATE_STICKY)
5339 {
5340 if ((action == _NET_WM_STATE_ADD1) ||
5341 (action == _NET_WM_STATE_TOGGLE2 && !window->on_all_workspaces))
5342 meta_window_stick (window);
5343 else
5344 meta_window_unstick (window);
5345 }
5346
5347 return TRUE(!(0));
5348 }
5349 else if (event->xclient.message_type ==
5350 display->atom_WM_CHANGE_STATE)
5351 {
5352 meta_verbosemeta_verbose_real ("WM_CHANGE_STATE client message, state: %ld\n",
5353 event->xclient.data.l[0]);
5354 if (event->xclient.data.l[0] == IconicState3)
5355 meta_window_minimize (window);
5356
5357 return TRUE(!(0));
5358 }
5359 else if (event->xclient.message_type ==
5360 display->atom__NET_WM_MOVERESIZE)
5361 {
5362 int x_root;
5363 int y_root;
5364 int action;
5365 MetaGrabOp op;
5366 int button;
5367 guint32 timestamp;
5368
5369 /* _NET_WM_MOVERESIZE messages are almost certainly going to come from
5370 * clients when users click on the fake "frame" that the client has,
5371 * thus we should also treat such messages as though it were a
5372 * "frame action".
5373 */
5374 gboolean const frame_action = TRUE(!(0));
5375
5376 x_root = event->xclient.data.l[0];
5377 y_root = event->xclient.data.l[1];
5378 action = event->xclient.data.l[2];
5379 button = event->xclient.data.l[3];
5380
5381 /* FIXME: What a braindead protocol; no timestamp?!? */
5382 timestamp = meta_display_get_current_time_roundtrip (display);
5383 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
5384 "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n",
5385 window->desc,
5386 x_root, y_root, action, button);
5387
5388 op = META_GRAB_OP_NONE;
5389 switch (action)
5390 {
5391 case _NET_WM_MOVERESIZE_SIZE_TOPLEFT0:
5392 op = META_GRAB_OP_RESIZING_NW;
5393 break;
5394 case _NET_WM_MOVERESIZE_SIZE_TOP1:
5395 op = META_GRAB_OP_RESIZING_N;
5396 break;
5397 case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT2:
5398 op = META_GRAB_OP_RESIZING_NE;
5399 break;
5400 case _NET_WM_MOVERESIZE_SIZE_RIGHT3:
5401 op = META_GRAB_OP_RESIZING_E;
5402 break;
5403 case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT4:
5404 op = META_GRAB_OP_RESIZING_SE;
5405 break;
5406 case _NET_WM_MOVERESIZE_SIZE_BOTTOM5:
5407 op = META_GRAB_OP_RESIZING_S;
5408 break;
5409 case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT6:
5410 op = META_GRAB_OP_RESIZING_SW;
5411 break;
5412 case _NET_WM_MOVERESIZE_SIZE_LEFT7:
5413 op = META_GRAB_OP_RESIZING_W;
5414 break;
5415 case _NET_WM_MOVERESIZE_MOVE8:
5416 op = META_GRAB_OP_MOVING;
5417 break;
5418 case _NET_WM_MOVERESIZE_SIZE_KEYBOARD9:
5419 op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN;
5420 break;
5421 case _NET_WM_MOVERESIZE_MOVE_KEYBOARD10:
5422 op = META_GRAB_OP_KEYBOARD_MOVING;
5423 break;
5424 case _NET_WM_MOVERESIZE_CANCEL11:
5425 /* handled below */
5426 break;
5427 default:
5428 break;
5429 }
5430
5431 if (action == _NET_WM_MOVERESIZE_CANCEL11)
5432 {
5433 meta_display_end_grab_op (window->display, timestamp);
5434 }
5435 else if (op != META_GRAB_OP_NONE &&
5436 ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) ||
5437 (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN)))
5438 {
5439 meta_window_begin_grab_op (window, op, frame_action, timestamp);
5440 }
5441 else if (op != META_GRAB_OP_NONE &&
5442 ((window->has_move_func && op == META_GRAB_OP_MOVING) ||
5443 (window->has_resize_func &&
5444 (op != META_GRAB_OP_MOVING &&
5445 op != META_GRAB_OP_KEYBOARD_MOVING))))
5446 {
5447 /*
5448 * the button SHOULD already be included in the message
5449 */
5450 if (button == 0)
5451 {
5452 int x, y, query_root_x, query_root_y;
5453 Window root, child;
5454 guint mask;
5455
5456 /* The race conditions in this _NET_WM_MOVERESIZE thing
5457 * are mind-boggling
5458 */
5459 mask = 0;
5460 meta_error_trap_push (window->display);
5461 XQueryPointer (window->display->xdisplay,
5462 window->xwindow,
5463 &root, &child,
5464 &query_root_x, &query_root_y,
5465 &x, &y,
5466 &mask);
5467 meta_error_trap_pop (window->display, TRUE(!(0)));
5468
5469 if (mask & Button1Mask(1<<8))
5470 button = 1;
5471 else if (mask & Button2Mask(1<<9))
5472 button = 2;
5473 else if (mask & Button3Mask(1<<10))
5474 button = 3;
5475 else
5476 button = 0;
5477 }
5478
5479 if (button != 0)
5480 {
5481 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
5482 "Beginning move/resize with button = %d\n", button);
5483 meta_display_begin_grab_op (window->display,
5484 window->screen,
5485 window,
5486 op,
5487 FALSE(0),
5488 frame_action,
5489 button, 0,
5490 timestamp,
5491 x_root,
5492 y_root);
5493 }
5494 }
5495
5496 return TRUE(!(0));
5497 }
5498 else if (event->xclient.message_type ==
5499 display->atom__NET_MOVERESIZE_WINDOW)
5500 {
5501 int gravity;
5502 guint value_mask;
5503
5504 gravity = (event->xclient.data.l[0] & 0xff);
5505 value_mask = (event->xclient.data.l[0] & 0xf00) >> 8;
5506
5507 if (gravity == 0)
5508 gravity = window->size_hints.win_gravity;
5509
5510 meta_window_move_resize_request(window,
5511 value_mask,
5512 gravity,
5513 event->xclient.data.l[1], /* x */
5514 event->xclient.data.l[2], /* y */
5515 event->xclient.data.l[3], /* width */
5516 event->xclient.data.l[4]); /* height */
5517 }
5518 else if (event->xclient.message_type ==
5519 display->atom__NET_ACTIVE_WINDOW)
5520 {
5521 MetaClientType source_indication;
5522 guint32 timestamp;
5523
5524 meta_verbosemeta_verbose_real ("_NET_ACTIVE_WINDOW request for window '%s', activating\n",
5525 window->desc);
5526
5527 source_indication = event->xclient.data.l[0];
5528 timestamp = event->xclient.data.l[1];
5529
5530 if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED)
5531 source_indication = META_CLIENT_TYPE_UNKNOWN;
5532
5533 if (timestamp == 0)
5534 {
5535 /* Client using older EWMH _NET_ACTIVE_WINDOW without a timestamp */
5536 meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a "
5537 "timestamp of 0 for %s\n",
5538 window->desc);
5539 timestamp = meta_display_get_current_time (display);
5540 }
5541
5542 window_activate (window, timestamp, source_indication, NULL((void*)0));
5543 return TRUE(!(0));
5544 }
5545 else if (event->xclient.message_type ==
5546 display->atom__NET_WM_FULLSCREEN_MONITORS)
5547 {
5548 gulong top, bottom, left, right;
5549
5550 meta_verbosemeta_verbose_real ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n",
5551 window->desc);
5552
5553 top = event->xclient.data.l[0];
5554 bottom = event->xclient.data.l[1];
5555 left = event->xclient.data.l[2];
5556 right = event->xclient.data.l[3];
5557 /* source_indication = event->xclient.data.l[4]; */
5558
5559 meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
5560 }
5561 else if (event->xclient.message_type ==
5562 display->atom__GTK_SHOW_WINDOW_MENU)
5563 {
5564 gulong x_root, y_root;
5565 guint32 timestamp;
5566 int button;
5567
5568 if (meta_prefs_get_raise_on_click ())
5569 meta_window_raise (window);
5570
5571 timestamp = meta_display_get_current_time_roundtrip (display);
5572 x_root = event->xclient.data.l[1];
5573 y_root = event->xclient.data.l[2];
5574 button = 3;
5575
5576 meta_window_show_menu (window,
5577 x_root,
5578 y_root,
5579 button,
5580 timestamp);
5581 }
5582
5583 return FALSE(0);
5584}
5585
5586static void
5587meta_window_appears_focused_changed (MetaWindow *window)
5588{
5589 set_net_wm_state (window);
5590
5591 if (window->frame)
5592 meta_frame_queue_draw (window->frame);
5593}
5594
5595static void
5596check_ancestor_focus_appearance (MetaWindow *window)
5597{
5598 MetaWindow *parent = meta_window_get_transient_for (window);
5599
5600 if (!meta_prefs_get_attach_modal_dialogs ())
5601 return;
5602
5603 if (window->type != META_WINDOW_MODAL_DIALOG || !parent || parent == window)
5604 return;
5605
5606 if (parent->frame)
5607 meta_frame_queue_draw (parent->frame);
5608
5609 check_ancestor_focus_appearance (parent);
5610}
5611
5612gboolean
5613meta_window_notify_focus (MetaWindow *window,
5614 XEvent *event)
5615{
5616 /* note the event can be on either the window or the frame,
5617 * we focus the frame for shaded windows
5618 */
5619
5620 /* The event can be FocusIn, FocusOut, or UnmapNotify.
5621 * On UnmapNotify we have to pretend it's focus out,
5622 * because we won't get a focus out if it occurs, apparently.
5623 */
5624
5625 /* We ignore grabs, though this is questionable.
5626 * It may be better to increase the intelligence of
5627 * the focus window tracking.
5628 *
5629 * The problem is that keybindings for windows are done with
5630 * XGrabKey, which means focus_window disappears and the front of
5631 * the MRU list gets confused from what the user expects once a
5632 * keybinding is used.
5633 */
5634 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
5635 "Focus %s event received on %s 0x%lx (%s) "
5636 "mode %s detail %s\n",
5637 event->type == FocusIn9 ? "in" :
5638 event->type == FocusOut10 ? "out" :
5639 event->type == UnmapNotify18 ? "unmap" :
5640 "???",
5641 window->desc, event->xany.window,
5642 event->xany.window == window->xwindow ?
5643 "client window" :
5644 (window->frame && event->xany.window == window->frame->xwindow) ?
5645 "frame window" :
5646 "unknown window",
5647 event->type != UnmapNotify18 ?
5648 meta_event_mode_to_string (event->xfocus.mode) : "n/a",
5649 event->type != UnmapNotify18 ?
5650 meta_event_detail_to_string (event->xfocus.detail) : "n/a");
5651
5652 /* FIXME our pointer tracking is broken; see how
5653 * gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c
5654 * handle it for the correct way. In brief you need to track
5655 * pointer focus and regular focus, and handle EnterNotify in
5656 * PointerRoot mode with no window manager. However as noted above,
5657 * accurate focus tracking will break things because we want to keep
5658 * windows "focused" when using keybindings on them, and also we
5659 * sometimes "focus" a window by focusing its frame or
5660 * no_focus_window; so this all needs rethinking massively.
5661 *
5662 * My suggestion is to change it so that we clearly separate
5663 * actual keyboard focus tracking using the xterm algorithm,
5664 * and marco's "pretend" focus window, and go through all
5665 * the code and decide which one should be used in each place;
5666 * a hard bit is deciding on a policy for that.
5667 *
5668 * http://bugzilla.gnome.org/show_bug.cgi?id=90382
5669 */
5670
5671 if ((event->type == FocusIn9 ||
5672 event->type == FocusOut10) &&
5673 (event->xfocus.mode == NotifyGrab1 ||
5674 event->xfocus.mode == NotifyUngrab2 ||
5675 /* From WindowMaker, ignore all funky pointer root events */
5676 event->xfocus.detail > NotifyNonlinearVirtual4))
5677 {
5678 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
5679 "Ignoring focus event generated by a grab or other weirdness\n");
5680 return TRUE(!(0));
5681 }
5682
5683 if (event->type == FocusIn9)
5684 {
5685 if (window != window->display->focus_window)
5686 {
5687 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
5688 "* Focus --> %s\n", window->desc);
5689 window->display->focus_window = window;
5690 window->has_focus = TRUE(!(0));
5691 meta_compositor_set_active_window (window->display->compositor,
5692 window->screen, window);
5693
5694 /* Move to the front of the focusing workspace's MRU list.
5695 * We should only be "removing" it from the MRU list if it's
5696 * not already there. Note that it's possible that we might
5697 * be processing this FocusIn after we've changed to a
5698 * different workspace; we should therefore update the MRU
5699 * list only if the window is actually on the active
5700 * workspace.
5701 */
5702 if (window->screen->active_workspace &&
5703 meta_window_located_on_workspace (window,
5704 window->screen->active_workspace))
5705 {
5706 GList* link;
5707 link = g_list_find (window->screen->active_workspace->mru_list,
5708 window);
5709 g_assert (link)do { if (link) ; else g_assertion_message_expr ("marco", "core/window.c"
, 5709, ((const char*) (__func__)), "link"); } while (0)
;
5710
5711 window->screen->active_workspace->mru_list =
5712 g_list_remove_link (window->screen->active_workspace->mru_list,
5713 link);
5714 g_list_free (link);
5715
5716 window->screen->active_workspace->mru_list =
5717 g_list_prepend (window->screen->active_workspace->mru_list,
5718 window);
5719 }
5720
5721 meta_window_appears_focused_changed (window);
5722
5723 meta_error_trap_push (window->display);
5724 XInstallColormap (window->display->xdisplay,
5725 window->colormap);
5726 meta_error_trap_pop (window->display, FALSE(0));
5727
5728 /* move into FOCUSED_WINDOW layer */
5729 meta_window_update_layer (window);
5730
5731 /* Ungrab click to focus button since the sync grab can interfere
5732 * with some things you might do inside the focused window, by
5733 * causing the client to get funky enter/leave events.
5734 *
5735 * The reason we usually have a passive grab on the window is
5736 * so that we can intercept clicks and raise the window in
5737 * response. For click-to-focus we don't need that since the
5738 * focused window is already raised. When raise_on_click is
5739 * FALSE we also don't need that since we don't do anything
5740 * when the window is clicked.
5741 *
5742 * There is dicussion in bugs 102209, 115072, and 461577
5743 */
5744 if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK ||
5745 !meta_prefs_get_raise_on_click())
5746 meta_display_ungrab_focus_window_button (window->display, window);
5747
5748 /* parent window become active. */
5749 check_ancestor_focus_appearance (window);
5750 }
5751 }
5752 else if (event->type == FocusOut10 ||
5753 event->type == UnmapNotify18)
5754 {
5755 if (event->type == FocusOut10 &&
5756 event->xfocus.detail == NotifyInferior2)
5757 {
5758 /* This event means the client moved focus to a subwindow */
5759 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
5760 "Ignoring focus out on %s with NotifyInferior\n",
5761 window->desc);
5762 return TRUE(!(0));
5763 }
5764
5765 if (window == window->display->focus_window)
5766 {
5767 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
5768 "%s is now the previous focus window due to being focused out or unmapped\n",
5769 window->desc);
5770
5771 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
5772 "* Focus --> NULL (was %s)\n", window->desc);
5773
5774 window->display->focus_window = NULL((void*)0);
5775 window->has_focus = FALSE(0);
5776
5777 /* parent window become active. */
5778 check_ancestor_focus_appearance (window);
5779
5780 meta_window_appears_focused_changed (window);
5781
5782 meta_compositor_set_active_window (window->display->compositor,
5783 window->screen, NULL((void*)0));
5784
5785 meta_error_trap_push (window->display);
5786 XUninstallColormap (window->display->xdisplay,
5787 window->colormap);
5788 meta_error_trap_pop (window->display, FALSE(0));
5789
5790 /* move out of FOCUSED_WINDOW layer */
5791 meta_window_update_layer (window);
5792
5793 /* Re-grab for click to focus and raise-on-click, if necessary */
5794 if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK ||
5795 !meta_prefs_get_raise_on_click ())
5796 meta_display_grab_focus_window_button (window->display, window);
5797 }
5798 }
5799
5800 /* Now set _NET_ACTIVE_WINDOW hint */
5801 meta_display_update_active_window_hint (window->display);
5802
5803 return FALSE(0);
5804}
5805
5806static gboolean
5807process_property_notify (MetaWindow *window,
5808 XPropertyEvent *event)
5809{
5810 Window xid = window->xwindow;
5811
5812 if (meta_is_verbose ()) /* avoid looking up the name if we don't have to */
5813 {
5814 char *property_name = XGetAtomName (window->display->xdisplay,
5815 event->atom);
5816
5817 meta_verbosemeta_verbose_real ("Property notify on %s for %s\n",
5818 window->desc, property_name);
5819 XFree (property_name);
5820 }
5821
5822 if (event->atom == window->display->atom__NET_WM_USER_TIME &&
5823 window->user_time_window)
5824 {
5825 xid = window->user_time_window;
5826 }
5827
5828 meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE(0));
5829
5830 return TRUE(!(0));
5831}
5832
5833static void
5834send_configure_notify (MetaWindow *window)
5835{
5836 XEvent event;
5837
5838 /* from twm */
5839
5840 event.type = ConfigureNotify22;
5841 event.xconfigure.display = window->display->xdisplay;
5842 event.xconfigure.event = window->xwindow;
5843 event.xconfigure.window = window->xwindow;
5844 event.xconfigure.x = window->rect.x - window->border_width;
5845 event.xconfigure.y = window->rect.y - window->border_width;
5846 if (window->frame)
5847 {
5848 if (window->withdrawn)
5849 {
5850 MetaFrameBorders borders;
5851 /* We reparent the client window and put it to the position
5852 * where the visible top-left of the frame window currently is.
5853 */
5854
5855 meta_frame_calc_borders (window->frame, &borders);
5856
5857 event.xconfigure.x = window->frame->rect.x + borders.invisible.left;
5858 event.xconfigure.y = window->frame->rect.y + borders.invisible.top;
5859 }
5860 else
5861 {
5862 /* Need to be in root window coordinates */
5863 event.xconfigure.x += window->frame->rect.x;
5864 event.xconfigure.y += window->frame->rect.y;
5865 }
5866 }
5867 event.xconfigure.width = window->rect.width;
5868 event.xconfigure.height = window->rect.height;
5869 event.xconfigure.border_width = window->border_width; /* requested not actual */
5870 event.xconfigure.above = None0L; /* FIXME */
5871 event.xconfigure.override_redirect = False0;
5872
5873 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY,
5874 "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n",
5875 window->desc,
5876 event.xconfigure.x, event.xconfigure.y,
5877 event.xconfigure.width, event.xconfigure.height);
5878
5879 meta_error_trap_push (window->display);
5880 XSendEvent (window->display->xdisplay,
5881 window->xwindow,
5882 False0, StructureNotifyMask(1L<<17), &event);
5883 meta_error_trap_pop (window->display, FALSE(0));
5884}
5885
5886gboolean
5887meta_window_get_icon_geometry (MetaWindow *window,
5888 MetaRectangle *rect)
5889{
5890 gulong *geometry = NULL((void*)0);
5891 int nitems;
5892
5893 if (meta_prop_get_cardinal_list (window->display,
5894 window->xwindow,
5895 window->display->atom__NET_WM_ICON_GEOMETRY,
5896 &geometry, &nitems))
5897 {
5898 if (nitems != 4)
5899 {
5900 meta_verbosemeta_verbose_real ("_NET_WM_ICON_GEOMETRY on %s has %d values instead of 4\n",
5901 window->desc, nitems);
5902 meta_XFree (geometry)do { if ((geometry)) XFree ((geometry)); } while (0);
5903 return FALSE(0);
5904 }
5905
5906 if (rect)
5907 {
5908 rect->x = geometry[0];
5909 rect->y = geometry[1];
5910 rect->width = geometry[2];
5911 rect->height = geometry[3];
5912 }
5913
5914 meta_XFree (geometry)do { if ((geometry)) XFree ((geometry)); } while (0);
5915
5916 return TRUE(!(0));
5917 }
5918
5919 return FALSE(0);
5920}
5921
5922static Window
5923read_client_leader (MetaDisplay *display,
5924 Window xwindow)
5925{
5926 Window retval = None0L;
5927
5928 meta_prop_get_window (display, xwindow,
5929 display->atom_WM_CLIENT_LEADER,
5930 &retval);
5931
5932 return retval;
5933}
5934
5935typedef struct
5936{
5937 Window leader;
5938} ClientLeaderData;
5939
5940static gboolean
5941find_client_leader_func (MetaWindow *ancestor,
5942 void *data)
5943{
5944 ClientLeaderData *d;
5945
5946 d = data;
5947
5948 d->leader = read_client_leader (ancestor->display,
5949 ancestor->xwindow);
5950
5951 /* keep going if no client leader found */
5952 return d->leader == None0L;
5953}
5954
5955static void
5956update_sm_hints (MetaWindow *window)
5957{
5958 Window leader;
5959
5960 window->xclient_leader = None0L;
5961 window->sm_client_id = NULL((void*)0);
5962
5963 /* If not on the current window, we can get the client
5964 * leader from transient parents. If we find a client
5965 * leader, we read the SM_CLIENT_ID from it.
5966 */
5967 leader = read_client_leader (window->display, window->xwindow);
5968 if (leader == None0L)
5969 {
5970 ClientLeaderData d;
5971 d.leader = None0L;
5972 meta_window_foreach_ancestor (window, find_client_leader_func,
5973 &d);
5974 leader = d.leader;
5975 }
5976
5977 if (leader != None0L)
5978 {
5979 char *str;
5980
5981 window->xclient_leader = leader;
5982
5983 if (meta_prop_get_latin1_string (window->display, leader,
5984 window->display->atom_SM_CLIENT_ID,
5985 &str))
5986 {
5987 window->sm_client_id = g_strdup (str)g_strdup_inline (str);
5988 meta_XFree (str)do { if ((str)) XFree ((str)); } while (0);
5989 }
5990 }
5991 else
5992 {
5993 meta_verbosemeta_verbose_real ("Didn't find a client leader for %s\n", window->desc);
5994
5995 if (!meta_prefs_get_disable_workarounds ())
5996 {
5997 /* Some broken apps (kdelibs fault?) set SM_CLIENT_ID on the app
5998 * instead of the client leader
5999 */
6000 char *str;
6001
6002 str = NULL((void*)0);
6003 if (meta_prop_get_latin1_string (window->display, window->xwindow,
6004 window->display->atom_SM_CLIENT_ID,
6005 &str))
6006 {
6007 if (window->sm_client_id == NULL((void*)0)) /* first time through */
6008 meta_warning (_("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n")((char *) g_dgettext ("marco", "Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n"
))
,
6009 window->desc);
6010
6011 window->sm_client_id = g_strdup (str)g_strdup_inline (str);
6012 meta_XFree (str)do { if ((str)) XFree ((str)); } while (0);
6013 }
6014 }
6015 }
6016
6017 meta_verbosemeta_verbose_real ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n",
6018 window->desc, window->xclient_leader,
6019 window->sm_client_id ? window->sm_client_id : "none");
6020}
6021
6022void
6023meta_window_update_role (MetaWindow *window)
6024{
6025 char *str;
6026
6027 if (window->role)
6028 g_free (window->role);
6029 window->role = NULL((void*)0);
6030
6031 if (meta_prop_get_latin1_string (window->display, window->xwindow,
6032 window->display->atom_WM_WINDOW_ROLE,
6033 &str))
6034 {
6035 window->role = g_strdup (str)g_strdup_inline (str);
6036 meta_XFree (str)do { if ((str)) XFree ((str)); } while (0);
6037 }
6038
6039 meta_verbosemeta_verbose_real ("Updated role of %s to '%s'\n",
6040 window->desc, window->role ? window->role : "null");
6041}
6042
6043void
6044meta_window_update_net_wm_type (MetaWindow *window)
6045{
6046 int n_atoms;
6047 Atom *atoms;
6048 int i;
6049
6050 window->type_atom = None0L;
6051 n_atoms = 0;
6052 atoms = NULL((void*)0);
6053
6054 meta_prop_get_atom_list (window->display, window->xwindow,
6055 window->display->atom__NET_WM_WINDOW_TYPE,
6056 &atoms, &n_atoms);
6057
6058 i = 0;
6059 while (i < n_atoms)
6060 {
6061 /* We break as soon as we find one we recognize,
6062 * supposed to prefer those near the front of the list
6063 */
6064 if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP ||
6065 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK ||
6066 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR ||
6067 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU ||
6068 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG ||
6069 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL ||
6070 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY ||
6071 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
6072 {
6073 window->type_atom = atoms[i];
6074 break;
6075 }
6076
6077 ++i;
6078 }
6079
6080 meta_XFree (atoms)do { if ((atoms)) XFree ((atoms)); } while (0);
6081
6082 if (meta_is_verbose ())
6083 {
6084 char *str;
6085
6086 str = NULL((void*)0);
6087 if (window->type_atom != None0L)
6088 {
6089 meta_error_trap_push (window->display);
6090 str = XGetAtomName (window->display->xdisplay, window->type_atom);
6091 meta_error_trap_pop (window->display, TRUE(!(0)));
6092 }
6093
6094 meta_verbosemeta_verbose_real ("Window %s type atom %s\n", window->desc,
6095 str ? str : "(none)");
6096
6097 if (str)
6098 meta_XFree (str)do { if ((str)) XFree ((str)); } while (0);
6099 }
6100
6101 meta_window_recalc_window_type (window);
6102}
6103
6104static void
6105redraw_icon (MetaWindow *window)
6106{
6107 /* We could probably be smart and just redraw the icon here,
6108 * instead of the whole frame.
6109 */
6110 if (window->frame && (window->mapped || window->frame->mapped))
6111 meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
6112}
6113
6114static gchar*
6115meta_window_get_desktop_id (MetaWindow *window)
6116{
6117 gchar* desktop_id = NULL((void*)0);
6118
6119 if (window->gtk_application_id != NULL((void*)0))
6120 {
6121 meta_verbosemeta_verbose_real ("Request desktop ID from _GTK_APPLICATION_ID '%s'\n", window->gtk_application_id);
6122
6123 /* Generate a desktop extension to the application ID (e.g. org.mate.Caja.desktop). */
6124 desktop_id = g_strconcat(window->gtk_application_id, ".desktop", NULL((void*)0));
6125 }
6126 else if (window->bamf_desktop_file != NULL((void*)0))
6127 {
6128 meta_verbosemeta_verbose_real ("Request desktop ID from _BAMF_DESKTOP_FILE '%s'\n", window->bamf_desktop_file);
6129
6130 /* Remove any paths to separate the application ID */
6131 gchar **path_parts = g_strsplit (window->bamf_desktop_file, "/", -1);
6132 /* Generate a desktop ID the application ID (e.g. org.mate.Caja.desktop). */
6133 if (g_strv_length(path_parts) > 0)
6134 desktop_id = g_strdup (path_parts[g_strv_length(path_parts)-1])g_strdup_inline (path_parts[g_strv_length(path_parts)-1]);
6135 g_strfreev (path_parts);
6136 }
6137
6138 return desktop_id;
6139}
6140
6141void
6142meta_window_update_icon_now (MetaWindow *window)
6143{
6144 GdkPixbuf *icon;
6145 GdkPixbuf *mini_icon;
6146
6147 icon = NULL((void*)0);
6148 mini_icon = NULL((void*)0);
6149
6150 int icon_size = meta_prefs_get_icon_size();
6151 gchar* desktop_id = meta_window_get_desktop_id (window);
6152
6153 if (meta_read_icons (window->screen,
6154 window->xwindow,
6155 desktop_id,
6156 &window->icon_cache,
6157 window->wm_hints_pixmap,
6158 window->wm_hints_mask,
6159 &icon,
6160 icon_size, /* width */
6161 icon_size, /* height */
6162 &mini_icon,
6163 META_MINI_ICON_WIDTH16,
6164 META_MINI_ICON_HEIGHT16))
6165 {
6166 if (window->icon)
6167 g_object_unref (G_OBJECT (window->icon)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->icon)), (((GType) ((20) << (2))))))))
);
6168
6169 if (window->mini_icon)
6170 g_object_unref (G_OBJECT (window->mini_icon)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window->mini_icon)), (((GType) ((20) << (2)))))
)))
);
6171
6172 window->icon = icon;
6173 window->mini_icon = mini_icon;
6174
6175 redraw_icon (window);
6176 }
6177
6178 g_free (desktop_id);
6179
6180 g_assert (window->icon)do { if (window->icon) ; else g_assertion_message_expr ("marco"
, "core/window.c", 6180, ((const char*) (__func__)), "window->icon"
); } while (0)
;
6181 g_assert (window->mini_icon)do { if (window->mini_icon) ; else g_assertion_message_expr
("marco", "core/window.c", 6181, ((const char*) (__func__)),
"window->mini_icon"); } while (0)
;
6182}
6183
6184static gboolean
6185idle_update_icon (gpointer data)
6186{
6187 GSList *tmp;
6188 GSList *copy;
6189 guint queue_index = GPOINTER_TO_INT (data)((gint) (glong) (data));
6190
6191 meta_topicmeta_topic_real (META_DEBUG_GEOMETRY, "Clearing the update_icon queue\n");
6192
6193 /* Work with a copy, for reentrancy. The allowed reentrancy isn't
6194 * complete; destroying a window while we're in here would result in
6195 * badness. But it's OK to queue/unqueue update_icons.
6196 */
6197 copy = g_slist_copy (queue_pending[queue_index]);
6198 g_slist_free (queue_pending[queue_index]);
6199 queue_pending[queue_index] = NULL((void*)0);
6200 queue_idle[queue_index] = 0;
6201
6202 destroying_windows_disallowed += 1;
6203
6204 tmp = copy;
6205 while (tmp != NULL((void*)0))
6206 {
6207 MetaWindow *window;
6208
6209 window = tmp->data;
6210
6211 meta_window_update_icon_now (window);
6212 window->is_in_queues &= ~META_QUEUE_UPDATE_ICON;
6213
6214 tmp = tmp->next;
6215 }
6216
6217 g_slist_free (copy);
6218
6219 destroying_windows_disallowed -= 1;
6220
6221 return FALSE(0);
6222}
6223
6224MetaWorkspace *
6225meta_window_get_workspace (MetaWindow *window)
6226{
6227 if (window->on_all_workspaces)
6228 return window->screen->active_workspace;
6229 else
6230 return window->workspace;
6231}
6232
6233GList*
6234meta_window_get_workspaces (MetaWindow *window)
6235{
6236 if (window->on_all_workspaces)
6237 return window->screen->workspaces;
6238 else
6239 return window->workspace->list_containing_self;
6240}
6241
6242static void
6243invalidate_work_areas (MetaWindow *window)
6244{
6245 GList *tmp;
6246
6247 tmp = meta_window_get_workspaces (window);
6248
6249 while (tmp != NULL((void*)0))
6250 {
6251 meta_workspace_invalidate_work_area (tmp->data);
6252 tmp = tmp->next;
6253 }
6254}
6255
6256void
6257meta_window_update_struts (MetaWindow *window)
6258{
6259 GSList *old_struts;
6260 GSList *new_struts;
6261 GSList *old_iter, *new_iter;
6262 gulong *struts = NULL((void*)0);
6263 int nitems;
6264 gboolean changed;
6265
6266 meta_verbosemeta_verbose_real ("Updating struts for %s\n", window->desc);
6267
6268 old_struts = window->struts;
6269 new_struts = NULL((void*)0);
6270
6271 if (meta_prop_get_cardinal_list (window->display,
6272 window->xwindow,
6273 window->display->atom__GNOME_WM_STRUT_AREA,
6274 &struts, &nitems))
6275 {
6276 if (nitems != 4)
6277 {
6278 meta_verbosemeta_verbose_real ("_GNOME_WM_STRUT_AREA on %s has %d values instead of 4\n",
6279 window->desc, nitems);
6280 }
6281 else
6282 {
6283 MetaStrut *temp;
6284 MetaSide side;
6285 gboolean valid;
6286 int i;
6287
6288 temp = g_new (MetaStrut, 1)((MetaStrut *) g_malloc_n ((1), sizeof (MetaStrut)));
6289
6290 temp->rect.x = struts[0];
6291 temp->rect.y = struts[1];
6292 temp->rect.width = struts[2];
6293 temp->rect.height = struts[3];
6294
6295 side = META_SIDE_LEFT;
6296 valid = FALSE(0);
6297
6298 for (i = 0; i < window->screen->n_xinerama_infos; i++)
6299 {
6300 MetaRectangle monitor;
6301
6302 monitor = window->screen->xinerama_infos[i].rect;
6303 if (!meta_rectangle_contains_rect (&monitor, &temp->rect))
6304 continue;
6305
6306 if (temp->rect.height > temp->rect.width)
6307 {
6308 if (temp->rect.x == monitor.x)
6309 {
6310 side = META_SIDE_LEFT;
6311 valid = TRUE(!(0));
6312 }
6313 else if (temp->rect.x + temp->rect.width == monitor.x + monitor.width)
6314 {
6315 side = META_SIDE_RIGHT;
6316 valid = TRUE(!(0));
6317 }
6318 }
6319 else
6320 {
6321 if (temp->rect.y == monitor.y)
6322 {
6323 side = META_SIDE_TOP;
6324 valid = TRUE(!(0));
6325 }
6326 else if (temp->rect.y + temp->rect.height == monitor.y + monitor.height)
6327 {
6328 side = META_SIDE_BOTTOM;
6329 valid = TRUE(!(0));
6330 }
6331 }
6332 }
6333
6334 if (valid)
6335 {
6336 temp->side = side;
6337 temp->edge = META_EDGE_XINERAMA;
6338
6339 new_struts = g_slist_prepend (new_struts, temp);
6340 }
6341 else
6342 {
6343 g_free (temp);
6344 }
6345 }
6346
6347 meta_XFree (struts)do { if ((struts)) XFree ((struts)); } while (0);
6348 }
6349 else
6350 {
6351 meta_verbosemeta_verbose_real ("No _GNOME_WM_STRUT_AREA property for %s\n",
6352 window->desc);
6353 }
6354
6355 if (!new_struts &&
6356 meta_prop_get_cardinal_list (window->display,
6357 window->xwindow,
6358 window->display->atom__NET_WM_STRUT_PARTIAL,
6359 &struts, &nitems))
6360 {
6361 if (nitems != 12)
6362 meta_verbosemeta_verbose_real ("_NET_WM_STRUT_PARTIAL on %s has %d values instead "
6363 "of 12\n",
6364 window->desc, nitems);
6365 else
6366 {
6367 /* Pull out the strut info for each side in the hint */
6368 int i;
6369 for (i=0; i<4; i++)
6370 {
6371 MetaStrut *temp;
6372 int thickness, strut_begin, strut_end;
6373
6374 thickness = struts[i];
6375 if (thickness == 0)
6376 continue;
6377 strut_begin = struts[4+(i*2)];
6378 strut_end = struts[4+(i*2)+1];
6379
6380 temp = g_new (MetaStrut, 1)((MetaStrut *) g_malloc_n ((1), sizeof (MetaStrut)));
6381 temp->side = 1 << i; /* See MetaSide def. Matches nicely, eh? */
6382 temp->edge = META_EDGE_SCREEN;
6383 temp->rect = window->screen->rect;
6384 switch (temp->side)
6385 {
6386 case META_SIDE_RIGHT:
6387 temp->rect.x = BOX_RIGHT(temp->rect)((temp->rect).x + (temp->rect).width) - thickness;
6388 /* Intentionally fall through without breaking */
6389 case META_SIDE_LEFT:
6390 temp->rect.width = thickness;
6391 temp->rect.y = strut_begin;
6392 temp->rect.height = strut_end - strut_begin + 1;
6393 break;
6394 case META_SIDE_BOTTOM:
6395 temp->rect.y = BOX_BOTTOM(temp->rect)((temp->rect).y + (temp->rect).height) - thickness;
6396 /* Intentionally fall through without breaking */
6397 case META_SIDE_TOP:
6398 temp->rect.height = thickness;
6399 temp->rect.x = strut_begin;
6400 temp->rect.width = strut_end - strut_begin + 1;
6401 break;
6402 default:
6403 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/window.c", 6403
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6404 }
6405
6406 new_struts = g_slist_prepend (new_struts, temp);
6407 }
6408
6409 meta_verbosemeta_verbose_real ("_NET_WM_STRUT_PARTIAL struts %lu %lu %lu %lu for "
6410 "window %s\n",
6411 struts[0], struts[1], struts[2], struts[3],
6412 window->desc);
6413 }
6414 meta_XFree (struts)do { if ((struts)) XFree ((struts)); } while (0);
6415 }
6416 else
6417 {
6418 meta_verbosemeta_verbose_real ("No _NET_WM_STRUT property for %s\n",
6419 window->desc);
6420 }
6421
6422 if (!new_struts &&
6423 meta_prop_get_cardinal_list (window->display,
6424 window->xwindow,
6425 window->display->atom__NET_WM_STRUT,
6426 &struts, &nitems))
6427 {
6428 if (nitems != 4)
6429 meta_verbosemeta_verbose_real ("_NET_WM_STRUT on %s has %d values instead of 4\n",
6430 window->desc, nitems);
6431 else
6432 {
6433 /* Pull out the strut info for each side in the hint */
6434 int i;
6435 for (i=0; i<4; i++)
6436 {
6437 MetaStrut *temp;
6438 int thickness;
6439
6440 thickness = struts[i];
6441 if (thickness == 0)
6442 continue;
6443
6444 temp = g_new (MetaStrut, 1)((MetaStrut *) g_malloc_n ((1), sizeof (MetaStrut)));
6445 temp->side = 1 << i;
6446 temp->edge = META_EDGE_SCREEN;
6447 temp->rect = window->screen->rect;
6448 switch (temp->side)
6449 {
6450 case META_SIDE_RIGHT:
6451 temp->rect.x = BOX_RIGHT(temp->rect)((temp->rect).x + (temp->rect).width) - thickness;
6452 /* Intentionally fall through without breaking */
6453 case META_SIDE_LEFT:
6454 temp->rect.width = thickness;
6455 break;
6456 case META_SIDE_BOTTOM:
6457 temp->rect.y = BOX_BOTTOM(temp->rect)((temp->rect).y + (temp->rect).height) - thickness;
6458 /* Intentionally fall through without breaking */
6459 case META_SIDE_TOP:
6460 temp->rect.height = thickness;
6461 break;
6462 default:
6463 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/window.c", 6463
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6464 }
6465
6466 new_struts = g_slist_prepend (new_struts, temp);
6467 }
6468
6469 meta_verbosemeta_verbose_real ("_NET_WM_STRUT struts %lu %lu %lu %lu for window %s\n",
6470 struts[0], struts[1], struts[2], struts[3],
6471 window->desc);
6472 }
6473 meta_XFree (struts)do { if ((struts)) XFree ((struts)); } while (0);
6474 }
6475 else if (!new_struts)
6476 {
6477 meta_verbosemeta_verbose_real ("No _NET_WM_STRUT property for %s\n",
6478 window->desc);
6479 }
6480
6481 /* Determine whether old_struts and new_struts are the same */
6482 old_iter = old_struts;
6483 new_iter = new_struts;
6484 while (old_iter && new_iter)
6485 {
6486 MetaStrut *old_strut = (MetaStrut*) old_iter->data;
6487 MetaStrut *new_strut = (MetaStrut*) new_iter->data;
6488
6489 if (old_strut->side != new_strut->side ||
6490 old_strut->edge != new_strut->edge ||
6491 !meta_rectangle_equal (&old_strut->rect, &new_strut->rect))
6492 break;
6493
6494 old_iter = old_iter->next;
6495 new_iter = new_iter->next;
6496 }
6497 changed = (old_iter != NULL((void*)0) || new_iter != NULL((void*)0));
6498
6499 /* Update appropriately */
6500 g_slist_free_full (old_struts, g_free);
6501 window->struts = new_struts;
6502 if (changed)
6503 {
6504 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
6505 "Invalidating work areas of window %s due to struts update\n",
6506 window->desc);
6507 invalidate_work_areas (window);
6508 }
6509 else
6510 {
6511 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
6512 "Struts on %s were unchanged\n", window->desc);
6513 }
6514}
6515
6516void
6517meta_window_recalc_window_type (MetaWindow *window)
6518{
6519 recalc_window_type (window);
6520}
6521
6522static void
6523recalc_window_type (MetaWindow *window)
6524{
6525 MetaWindowType old_type;
6526
6527 old_type = window->type;
6528
6529 if (window->type_atom != None0L)
6530 {
6531 if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
6532 window->type = META_WINDOW_DESKTOP;
6533 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK)
6534 window->type = META_WINDOW_DOCK;
6535 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
6536 window->type = META_WINDOW_TOOLBAR;
6537 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU)
6538 window->type = META_WINDOW_MENU;
6539 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG)
6540 window->type = META_WINDOW_DIALOG;
6541 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
6542 window->type = META_WINDOW_NORMAL;
6543 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY)
6544 window->type = META_WINDOW_UTILITY;
6545 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
6546 window->type = META_WINDOW_SPLASHSCREEN;
6547 else
6548 meta_bug ("Set a type atom for %s that wasn't handled in recalc_window_type\n",
6549 window->desc);
6550 }
6551 else if (window->xtransient_for != None0L)
6552 {
6553 window->type = META_WINDOW_DIALOG;
6554 }
6555 else
6556 {
6557 window->type = META_WINDOW_NORMAL;
6558 }
6559
6560 if (window->type == META_WINDOW_DIALOG &&
6561 window->wm_state_modal)
6562 window->type = META_WINDOW_MODAL_DIALOG;
6563
6564 meta_verbosemeta_verbose_real ("Calculated type %u for %s, old type %u\n",
6565 window->type, window->desc, old_type);
6566
6567 if (old_type != window->type)
6568 {
6569 recalc_window_features (window);
6570
6571 set_net_wm_state (window);
6572
6573 /* Update frame */
6574 if (window->decorated)
6575 meta_window_ensure_frame (window);
6576 else
6577 meta_window_destroy_frame (window);
6578
6579 /* update stacking constraints */
6580 meta_window_update_layer (window);
6581
6582 meta_window_grab_keys (window);
6583 }
6584}
6585
6586static void
6587set_allowed_actions_hint (MetaWindow *window)
6588{
6589#define MAX_N_ACTIONS 12
6590 unsigned long data[MAX_N_ACTIONS];
6591 int i;
6592
6593 i = 0;
6594 if (window->has_move_func &&
6595 !window->minimized)
6596 {
6597 data[i] = window->display->atom__NET_WM_ACTION_MOVE;
6598 ++i;
6599 }
6600 if (window->has_resize_func &&
6601 !window->minimized &&
6602 !window->shaded &&
6603 !window->tiled &&
6604 !(window->maximized_horizontally && window->maximized_vertically))
6605 {
6606 data[i] = window->display->atom__NET_WM_ACTION_RESIZE;
6607 ++i;
6608 }
6609 if (window->has_fullscreen_func &&
6610 !window->minimized &&
6611 !window->shaded)
6612 {
6613 data[i] = window->display->atom__NET_WM_ACTION_FULLSCREEN;
6614 ++i;
6615 }
6616 if (window->has_minimize_func)
6617 {
6618 data[i] = window->display->atom__NET_WM_ACTION_MINIMIZE;
6619 ++i;
6620 }
6621 if (window->has_shade_func &&
6622 !window->minimized)
6623 {
6624 data[i] = window->display->atom__NET_WM_ACTION_SHADE;
6625 ++i;
6626 }
6627 /* sticky according to EWMH is different from marco's sticky;
6628 * marco doesn't support EWMH sticky
6629 */
6630 if (window->has_maximize_func &&
6631 !window->minimized &&
6632 !window->shaded)
6633 {
6634 data[i] = window->display->atom__NET_WM_ACTION_MAXIMIZE_HORZ;
6635 ++i;
6636 data[i] = window->display->atom__NET_WM_ACTION_MAXIMIZE_VERT;
6637 ++i;
6638 }
6639 /* We always allow this */
6640 data[i] = window->display->atom__NET_WM_ACTION_CHANGE_DESKTOP;
6641 ++i;
6642 if (window->has_close_func)
6643 {
6644 data[i] = window->display->atom__NET_WM_ACTION_CLOSE;
6645 ++i;
6646 }
6647
6648 /* I guess we always allow above/below operations */
6649 data[i] = window->display->atom__NET_WM_ACTION_ABOVE;
6650 ++i;
6651 data[i] = window->display->atom__NET_WM_ACTION_BELOW;
6652 ++i;
6653
6654 g_assert (i <= MAX_N_ACTIONS)do { if (i <= MAX_N_ACTIONS) ; else g_assertion_message_expr
("marco", "core/window.c", 6654, ((const char*) (__func__)),
"i <= MAX_N_ACTIONS"); } while (0)
;
6655
6656 meta_verbosemeta_verbose_real ("Setting _NET_WM_ALLOWED_ACTIONS with %d atoms\n", i);
6657
6658 meta_error_trap_push (window->display);
6659 XChangeProperty (window->display->xdisplay, window->xwindow,
6660 window->display->atom__NET_WM_ALLOWED_ACTIONS,
6661 XA_ATOM((Atom) 4),
6662 32, PropModeReplace0, (guchar*) data, i);
6663 meta_error_trap_pop (window->display, FALSE(0));
6664#undef MAX_N_ACTIONS
6665}
6666
6667void
6668meta_window_recalc_features (MetaWindow *window)
6669{
6670 recalc_window_features (window);
6671}
6672
6673static void
6674recalc_window_features (MetaWindow *window)
6675{
6676 gboolean old_has_close_func;
6677 gboolean old_has_minimize_func;
6678 gboolean old_has_move_func;
6679 gboolean old_has_resize_func;
6680 gboolean old_has_shade_func;
6681 gboolean old_always_sticky;
6682
6683 old_has_close_func = window->has_close_func;
6684 old_has_minimize_func = window->has_minimize_func;
6685 old_has_move_func = window->has_move_func;
6686 old_has_resize_func = window->has_resize_func;
6687 old_has_shade_func = window->has_shade_func;
6688 old_always_sticky = window->always_sticky;
6689
6690 /* Use MWM hints initially */
6691 window->decorated = window->mwm_decorated;
6692 window->border_only = window->mwm_border_only;
6693 window->has_close_func = window->mwm_has_close_func;
6694 window->has_minimize_func = window->mwm_has_minimize_func;
6695 window->has_maximize_func = window->mwm_has_maximize_func;
6696 window->has_move_func = window->mwm_has_move_func;
6697
6698 window->has_resize_func = TRUE(!(0));
6699
6700 /* If min_size == max_size, then don't allow resize */
6701 if (window->size_hints.min_width == window->size_hints.max_width &&
6702 window->size_hints.min_height == window->size_hints.max_height)
6703 window->has_resize_func = FALSE(0);
6704 else if (!window->mwm_has_resize_func)
6705 {
6706 /* We ignore mwm_has_resize_func because WM_NORMAL_HINTS is the
6707 * authoritative source for that info. Some apps such as mplayer or
6708 * xine disable resize via MWM but not WM_NORMAL_HINTS, but that
6709 * leads to e.g. us not fullscreening their windows. Apps that set
6710 * MWM but not WM_NORMAL_HINTS are basically broken. We complain
6711 * about these apps but make them work.
6712 */
6713
6714 meta_warning (_("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n")((char *) g_dgettext ("marco", "Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n"
))
,
6715 window->desc,
6716 window->size_hints.min_width,
6717 window->size_hints.min_height,
6718 window->size_hints.max_width,
6719 window->size_hints.max_height);
6720 }
6721
6722 window->has_shade_func = TRUE(!(0));
6723 window->has_fullscreen_func = TRUE(!(0));
6724
6725 window->always_sticky = FALSE(0);
6726
6727 /* Semantic category overrides the MWM hints */
6728 if (window->type == META_WINDOW_TOOLBAR)
6729 window->decorated = FALSE(0);
6730
6731 if (window->type == META_WINDOW_MODAL_DIALOG && meta_prefs_get_attach_modal_dialogs ())
6732 {
6733 MetaWindow *parent = meta_window_get_transient_for (window);
6734 if (parent)
6735 {
6736 window->has_resize_func = FALSE(0);
6737 window->border_only = TRUE(!(0));
6738 }
6739 }
6740
6741 if (window->type == META_WINDOW_DESKTOP ||
6742 window->type == META_WINDOW_DOCK)
6743 window->always_sticky = TRUE(!(0));
6744
6745 if (window->type == META_WINDOW_DESKTOP ||
6746 window->type == META_WINDOW_DOCK ||
6747 window->type == META_WINDOW_SPLASHSCREEN)
6748 {
6749 window->decorated = FALSE(0);
6750 window->has_close_func = FALSE(0);
6751 window->has_shade_func = FALSE(0);
6752
6753 /* FIXME this keeps panels and things from using
6754 * NET_WM_MOVERESIZE; the problem is that some
6755 * panels (edge panels) have fixed possible locations,
6756 * and others ("floating panels") do not.
6757 *
6758 * Perhaps we should require edge panels to explicitly
6759 * disable movement?
6760 */
6761 window->has_move_func = FALSE(0);
6762 window->has_resize_func = FALSE(0);
6763 }
6764
6765 if (window->type != META_WINDOW_NORMAL &&
6766 window->type != META_WINDOW_DIALOG)
6767 {
6768 window->has_minimize_func = FALSE(0);
6769 window->has_maximize_func = FALSE(0);
6770 window->has_fullscreen_func = FALSE(0);
6771 }
6772
6773 if (!window->has_resize_func)
6774 {
6775 window->has_maximize_func = FALSE(0);
6776
6777 /* don't allow fullscreen if we can't resize, unless the size
6778 * is entire screen size (kind of broken, because we
6779 * actually fullscreen to xinerama head size not screen size)
6780 */
6781 if (window->size_hints.min_width == window->screen->rect.width &&
6782 window->size_hints.min_height == window->screen->rect.height)
6783 ; /* leave fullscreen available */
6784 else
6785 window->has_fullscreen_func = FALSE(0);
6786 }
6787
6788 /* We leave fullscreen windows decorated, just push the frame outside
6789 * the screen. This avoids flickering to unparent them.
6790 *
6791 * Note that setting has_resize_func = FALSE here must come after the
6792 * above code that may disable fullscreen, because if the window
6793 * is not resizable purely due to fullscreen, we don't want to
6794 * disable fullscreen mode.
6795 */
6796 if (window->fullscreen)
6797 {
6798 window->has_shade_func = FALSE(0);
6799 window->has_move_func = FALSE(0);
6800 window->has_resize_func = FALSE(0);
6801 window->has_maximize_func = FALSE(0);
6802 }
6803
6804 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
6805 "Window %s fullscreen = %d not resizable, maximizable = %d fullscreenable = %d min size %dx%d max size %dx%d\n",
6806 window->desc,
6807 window->fullscreen,
6808 window->has_maximize_func, window->has_fullscreen_func,
6809 window->size_hints.min_width,
6810 window->size_hints.min_height,
6811 window->size_hints.max_width,
6812 window->size_hints.max_height);
6813
6814 /* no shading if not decorated */
6815 if (!window->decorated || window->border_only)
6816 window->has_shade_func = FALSE(0);
6817
6818 window->skip_taskbar = FALSE(0);
6819 window->skip_pager = FALSE(0);
6820
6821 if (window->wm_state_skip_taskbar)
6822 window->skip_taskbar = TRUE(!(0));
6823
6824 if (window->wm_state_skip_pager)
6825 window->skip_pager = TRUE(!(0));
6826
6827 switch (window->type)
6828 {
6829 /* Force skip taskbar/pager on these window types */
6830 case META_WINDOW_DESKTOP:
6831 case META_WINDOW_DOCK:
6832 case META_WINDOW_TOOLBAR:
6833 case META_WINDOW_MENU:
6834 case META_WINDOW_UTILITY:
6835 case META_WINDOW_SPLASHSCREEN:
6836 window->skip_taskbar = TRUE(!(0));
6837 window->skip_pager = TRUE(!(0));
6838 break;
6839
6840 case META_WINDOW_DIALOG:
6841 case META_WINDOW_MODAL_DIALOG:
6842 /* only skip taskbar if we have a real transient parent */
6843 if (window->xtransient_for != None0L &&
6844 window->xtransient_for != window->screen->xroot)
6845 window->skip_taskbar = TRUE(!(0));
6846 break;
6847
6848 case META_WINDOW_NORMAL:
6849 break;
6850 }
6851
6852 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
6853 "Window %s decorated = %d border_only = %d has_close = %d has_minimize = %d has_maximize = %d has_move = %d has_shade = %d skip_taskbar = %d skip_pager = %d\n",
6854 window->desc,
6855 window->decorated,
6856 window->border_only,
6857 window->has_close_func,
6858 window->has_minimize_func,
6859 window->has_maximize_func,
6860 window->has_move_func,
6861 window->has_shade_func,
6862 window->skip_taskbar,
6863 window->skip_pager);
6864
6865 /* FIXME:
6866 * Lame workaround for recalc_window_features
6867 * being used overzealously. The fix is to
6868 * only recalc_window_features when something
6869 * has actually changed.
6870 */
6871 if (window->constructing ||
6872 old_has_close_func != window->has_close_func ||
6873 old_has_minimize_func != window->has_minimize_func ||
6874 old_has_move_func != window->has_move_func ||
6875 old_has_resize_func != window->has_resize_func ||
6876 old_has_shade_func != window->has_shade_func ||
6877 old_always_sticky != window->always_sticky)
6878 set_allowed_actions_hint (window);
6879
6880 /* FIXME perhaps should ensure if we don't have a shade func,
6881 * we aren't shaded, etc.
6882 */
6883}
6884
6885static void
6886menu_callback (MetaWindowMenu *menu,
6887 Display *xdisplay,
6888 Window client_xwindow,
6889 guint32 timestamp,
6890 MetaMenuOp op,
6891 int workspace_index,
6892 gpointer data)
6893{
6894 MetaDisplay *display;
6895 MetaWindow *window;
6896 MetaWorkspace *workspace;
6897
6898 display = meta_display_for_x_display (xdisplay);
6899 window = meta_display_lookup_x_window (display, client_xwindow);
6900 workspace = NULL((void*)0);
6901
6902 if (window != NULL((void*)0)) /* window can be NULL */
6903 {
6904 meta_verbosemeta_verbose_real ("Menu op %u on %s\n", op, window->desc);
6905
6906 switch (op)
6907 {
6908 case META_MENU_OP_NONE:
6909 /* nothing */
6910 break;
6911
6912 case META_MENU_OP_DELETE:
6913 meta_window_delete (window, timestamp);
6914 break;
6915
6916 case META_MENU_OP_MINIMIZE:
6917 meta_window_minimize (window);
6918 break;
6919
6920 case META_MENU_OP_UNMAXIMIZE:
6921 meta_window_unmaximize (window,
6922 META_MAXIMIZE_HORIZONTAL |
6923 META_MAXIMIZE_VERTICAL);
6924 break;
6925
6926 case META_MENU_OP_MAXIMIZE:
6927 meta_window_maximize (window,
6928 META_MAXIMIZE_HORIZONTAL |
6929 META_MAXIMIZE_VERTICAL);
6930 break;
6931
6932 case META_MENU_OP_UNSHADE:
6933 meta_window_unshade (window, timestamp);
6934 break;
6935
6936 case META_MENU_OP_SHADE:
6937 meta_window_shade (window, timestamp);
6938 break;
6939
6940 case META_MENU_OP_MOVE_LEFT:
6941 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
6942 META_MOTION_LEFT);
6943 break;
6944
6945 case META_MENU_OP_MOVE_RIGHT:
6946 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
6947 META_MOTION_RIGHT);
6948 break;
6949
6950 case META_MENU_OP_MOVE_UP:
6951 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
6952 META_MOTION_UP);
6953 break;
6954
6955 case META_MENU_OP_MOVE_DOWN:
6956 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
6957 META_MOTION_DOWN);
6958 break;
6959
6960 case META_MENU_OP_WORKSPACES:
6961 workspace = meta_screen_get_workspace_by_index (window->screen,
6962 workspace_index);
6963 break;
6964
6965 case META_MENU_OP_STICK:
6966 meta_window_stick (window);
6967 break;
6968
6969 case META_MENU_OP_UNSTICK:
6970 meta_window_unstick (window);
6971 break;
6972
6973 case META_MENU_OP_ABOVE:
6974 case META_MENU_OP_UNABOVE:
6975 if (!window->wm_state_above)
6976 meta_window_make_above (window);
6977 else
6978 meta_window_unmake_above (window);
6979 break;
6980
6981 case META_MENU_OP_MOVE:
6982 meta_window_begin_grab_op (window,
6983 META_GRAB_OP_KEYBOARD_MOVING,
6984 TRUE(!(0)),
6985 timestamp);
6986 break;
6987
6988 case META_MENU_OP_RESIZE:
6989 meta_window_begin_grab_op (window,
6990 META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
6991 TRUE(!(0)),
6992 timestamp);
6993 break;
6994
6995 case META_MENU_OP_RECOVER:
6996 meta_window_shove_titlebar_onscreen (window);
6997 break;
6998
6999 default:
7000 meta_warning (G_STRLOC"core/window.c" ":" "7000"": Unknown window op\n");
7001 break;
7002 }
7003
7004 if (workspace)
7005 {
7006 meta_window_change_workspace (window,
7007 workspace);
7008#if 0
7009 meta_workspace_activate (workspace);
7010 meta_window_raise (window);
7011#endif
7012 }
7013 }
7014 else
7015 {
7016 meta_verbosemeta_verbose_real ("Menu callback on nonexistent window\n");
7017 }
7018
7019 if (display->window_menu == menu)
7020 {
7021 display->window_menu = NULL((void*)0);
7022 display->window_with_menu = NULL((void*)0);
7023 }
7024
7025 meta_ui_window_menu_free (menu);
7026}
7027
7028void
7029meta_window_show_menu (MetaWindow *window,
7030 int root_x,
7031 int root_y,
7032 int button,
7033 guint32 timestamp)
7034{
7035 MetaMenuOp ops;
7036 MetaMenuOp insensitive;
7037 MetaWindowMenu *menu;
7038 MetaWorkspaceLayout layout;
7039 int n_workspaces;
7040 gboolean ltr;
7041
7042 if (window->display->window_menu)
7043 {
7044 meta_ui_window_menu_free (window->display->window_menu);
7045 window->display->window_menu = NULL((void*)0);
7046 window->display->window_with_menu = NULL((void*)0);
7047 }
7048
7049 ops = META_MENU_OP_NONE;
7050 insensitive = META_MENU_OP_NONE;
7051
7052 ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE);
7053
7054 if (!meta_window_titlebar_is_onscreen (window) &&
7055 window->type != META_WINDOW_DOCK &&
7056 window->type != META_WINDOW_DESKTOP)
7057 ops |= META_MENU_OP_RECOVER;
7058
7059 n_workspaces = meta_screen_get_n_workspaces (window->screen);
7060
7061 if (n_workspaces > 1)
7062 ops |= META_MENU_OP_WORKSPACES;
7063
7064 meta_screen_calc_workspace_layout (window->screen,
7065 n_workspaces,
7066 meta_workspace_index ( window->screen->active_workspace),
7067 &layout);
7068
7069 if (!window->on_all_workspaces)
7070 {
7071 ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
7072
7073 if (layout.current_col > 0)
7074 ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT;
7075 if ((layout.current_col < layout.cols - 1) &&
7076 (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces))
7077 ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT;
7078 if (layout.current_row > 0)
7079 ops |= META_MENU_OP_MOVE_UP;
7080 if ((layout.current_row < layout.rows - 1) &&
7081 ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces))
7082 ops |= META_MENU_OP_MOVE_DOWN;
7083 }
7084
7085 meta_screen_free_workspace_layout (&layout);
7086
7087 if (META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
)
7088 ops |= META_MENU_OP_UNMAXIMIZE;
7089 else
7090 ops |= META_MENU_OP_MAXIMIZE;
7091
7092#if 0
7093 if (window->shaded)
7094 ops |= META_MENU_OP_UNSHADE;
7095 else
7096 ops |= META_MENU_OP_SHADE;
7097#endif
7098
7099 ops |= META_MENU_OP_UNSTICK;
7100 ops |= META_MENU_OP_STICK;
7101
7102 if (window->wm_state_above)
7103 ops |= META_MENU_OP_UNABOVE;
7104 else
7105 ops |= META_MENU_OP_ABOVE;
7106
7107 if (!window->has_maximize_func)
7108 insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE;
7109
7110 if (!window->has_minimize_func)
7111 insensitive |= META_MENU_OP_MINIMIZE;
7112
7113 /*if (!window->has_close_func)
7114 insensitive |= META_MENU_OP_DELETE;*/
7115
7116 if (!window->has_shade_func)
7117 insensitive |= META_MENU_OP_SHADE | META_MENU_OP_UNSHADE;
7118
7119 if (!META_WINDOW_ALLOWS_MOVE (window)((window)->has_move_func && !(window)->fullscreen
)
)
7120 insensitive |= META_MENU_OP_MOVE;
7121
7122 if (!META_WINDOW_ALLOWS_RESIZE (window)(((window)->has_resize_func && !((window)->maximized_horizontally
&& (window)->maximized_vertically) && !(window
)->fullscreen && !(window)->shaded) && (
((window)->size_hints.min_width < (window)->size_hints
.max_width) || ((window)->size_hints.min_height < (window
)->size_hints.max_height)))
)
7123 insensitive |= META_MENU_OP_RESIZE;
7124
7125 if (window->always_sticky)
7126 insensitive |= META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES;
7127
7128 if ((window->type == META_WINDOW_DESKTOP) ||
7129 (window->type == META_WINDOW_DOCK) ||
7130 (window->type == META_WINDOW_SPLASHSCREEN))
7131 insensitive |= META_MENU_OP_ABOVE | META_MENU_OP_UNABOVE;
7132
7133 /* If all operations are disabled, just quit without showing the menu.
7134 * This is the case, for example, with META_WINDOW_DESKTOP windows.
7135 */
7136 if ((ops & ~insensitive) == 0)
7137 return;
7138
7139 menu =
7140 meta_ui_window_menu_new (window->screen->ui,
7141 window->xwindow,
7142 ops,
7143 insensitive,
7144 meta_window_get_net_wm_desktop (window),
7145 meta_screen_get_n_workspaces (window->screen),
7146 menu_callback,
7147 NULL((void*)0));
7148
7149 window->display->window_menu = menu;
7150 window->display->window_with_menu = window;
7151
7152 meta_verbosemeta_verbose_real ("Popping up window menu for %s\n", window->desc);
7153
7154 meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp);
7155}
7156
7157void
7158meta_window_shove_titlebar_onscreen (MetaWindow *window)
7159{
7160 MetaRectangle outer_rect;
7161 GList *onscreen_region;
7162 int horiz_amount, vert_amount;
7163 int newx, newy;
7164
7165 /* If there's no titlebar, don't bother */
7166 if (!window->frame)
7167 return;
7168
7169 /* Get the basic info we need */
7170 meta_window_get_outer_rect (window, &outer_rect);
7171 onscreen_region = window->screen->active_workspace->screen_region;
7172
7173 /* Extend the region (just in case the window is too big to fit on the
7174 * screen), then shove the window on screen, then return the region to
7175 * normal.
7176 */
7177 horiz_amount = outer_rect.width;
7178 vert_amount = outer_rect.height;
7179 meta_rectangle_expand_region (onscreen_region,
7180 horiz_amount,
7181 horiz_amount,
7182 0,
7183 vert_amount);
7184 meta_rectangle_shove_into_region(onscreen_region,
7185 FIXED_DIRECTION_X,
7186 &outer_rect);
7187 meta_rectangle_expand_region (onscreen_region,
7188 -horiz_amount,
7189 -horiz_amount,
7190 0,
7191 -vert_amount);
7192
7193 newx = outer_rect.x + window->frame->child_x;
7194 newy = outer_rect.y + window->frame->child_y;
7195 meta_window_move_resize (window,
7196 FALSE(0),
7197 newx,
7198 newy,
7199 window->rect.width,
7200 window->rect.height);
7201}
7202
7203gboolean
7204meta_window_titlebar_is_onscreen (MetaWindow *window)
7205{
7206 MetaRectangle titlebar_rect;
7207 GList *onscreen_region;
7208 gboolean is_onscreen;
7209
7210 const int min_height_needed = 8;
7211 const double min_width_percent = 0.5;
7212 const int min_width_absolute = 50;
7213
7214 /* Titlebar can't be offscreen if there is no titlebar... */
7215 if (!window->frame)
7216 return TRUE(!(0));
7217
7218 /* Get the rectangle corresponding to the titlebar */
7219 meta_window_get_outer_rect (window, &titlebar_rect);
7220 titlebar_rect.height = window->frame->child_y;
7221
7222 /* Run through the spanning rectangles for the screen and see if one of
7223 * them overlaps with the titlebar sufficiently to consider it onscreen.
7224 */
7225 is_onscreen = FALSE(0);
7226 onscreen_region = window->screen->active_workspace->screen_region;
7227 while (onscreen_region)
7228 {
7229 MetaRectangle *spanning_rect = onscreen_region->data;
7230 MetaRectangle overlap;
7231
7232 meta_rectangle_intersect (&titlebar_rect, spanning_rect, &overlap);
7233 if (overlap.height > MIN (titlebar_rect.height, min_height_needed)(((titlebar_rect.height) < (min_height_needed)) ? (titlebar_rect
.height) : (min_height_needed))
&&
7234 overlap.width > MIN ((int) (min_width_percent * (double) titlebar_rect.width),((((int) (min_width_percent * (double) titlebar_rect.width)) <
(min_width_absolute)) ? ((int) (min_width_percent * (double)
titlebar_rect.width)) : (min_width_absolute))
7235 min_width_absolute)((((int) (min_width_percent * (double) titlebar_rect.width)) <
(min_width_absolute)) ? ((int) (min_width_percent * (double)
titlebar_rect.width)) : (min_width_absolute))
)
7236 {
7237 is_onscreen = TRUE(!(0));
7238 break;
7239 }
7240
7241 onscreen_region = onscreen_region->next;
7242 }
7243
7244 return is_onscreen;
7245}
7246
7247static double
7248time_diff (const gint64 first,
7249 const gint64 second)
7250{
7251 return (first - second) / 1000.0;
7252}
7253
7254static gboolean
7255check_moveresize_frequency (MetaWindow *window,
7256 gdouble *remaining)
7257{
7258 gint64 current_time;
7259 current_time = g_get_real_time ();
7260
7261#ifdef HAVE_XSYNC
7262 if (!window->disable_sync &&
7263 window->display->grab_sync_request_alarm != None0L)
7264 {
7265 if (window->sync_request_time != 0)
7266 {
7267 double elapsed =
7268 time_diff (current_time, window->sync_request_time);
7269
7270 if (elapsed < 1000.0)
7271 {
7272 /* We want to be sure that the timeout happens at
7273 * a time where elapsed will definitely be
7274 * greater than 1000, so we can disable sync
7275 */
7276 if (remaining)
7277 *remaining = 1000.0 - elapsed + 100;
7278
7279 return FALSE(0);
7280 }
7281 else
7282 {
7283 /* We have now waited for more than a second for the
7284 * application to respond to the sync request
7285 */
7286 window->disable_sync = TRUE(!(0));
7287 return TRUE(!(0));
7288 }
7289 }
7290 else
7291 {
7292 /* No outstanding sync requests. Go ahead and resize
7293 */
7294 return TRUE(!(0));
7295 }
7296 }
7297 else
7298#endif /* HAVE_XSYNC */
7299 {
7300 const double max_resizes_per_second = 25.0;
7301 const double ms_between_resizes = 1000.0 / max_resizes_per_second;
7302 double elapsed;
7303
7304 elapsed = time_diff (current_time, window->display->grab_last_moveresize_time);
7305
7306 if (elapsed >= 0.0 && elapsed < ms_between_resizes)
7307 {
7308 meta_topicmeta_topic_real (META_DEBUG_RESIZING,
7309 "Delaying move/resize as only %g of %g ms elapsed\n",
7310 elapsed, ms_between_resizes);
7311
7312 if (remaining)
7313 *remaining = (ms_between_resizes - elapsed);
7314
7315 return FALSE(0);
7316 }
7317
7318 meta_topicmeta_topic_real (META_DEBUG_RESIZING,
7319 " Checked moveresize freq, allowing move/resize now (%g of %g seconds elapsed)\n",
7320 elapsed / 1000.0, 1.0 / max_resizes_per_second);
7321
7322 return TRUE(!(0));
7323 }
7324}
7325
7326static gboolean
7327update_move_timeout (gpointer data)
7328{
7329 MetaWindow *window = data;
7330
7331 update_move (window,
7332 window->display->grab_last_user_action_was_snap != FALSE(0),
7333 window->display->grab_latest_motion_x,
7334 window->display->grab_latest_motion_y);
7335
7336 return FALSE(0);
7337}
7338
7339static void
7340update_move (MetaWindow *window,
7341 gboolean snap,
7342 int x,
7343 int y)
7344{
7345 int dx, dy;
7346 int new_x, new_y;
7347 MetaRectangle old;
7348 int shake_threshold;
7349 MetaDisplay *display = window->display;
7350
7351 display->grab_latest_motion_x = x;
7352 display->grab_latest_motion_y = y;
7353
7354 dx = x - display->grab_anchor_root_x;
7355 dy = y - display->grab_anchor_root_y;
7356
7357 new_x = display->grab_anchor_window_pos.x + dx;
7358 new_y = display->grab_anchor_window_pos.y + dy;
7359
7360 meta_verbosemeta_verbose_real ("x,y = %d,%d anchor ptr %d,%d anchor pos %d,%d dx,dy %d,%d\n",
7361 x, y,
7362 display->grab_anchor_root_x,
7363 display->grab_anchor_root_y,
7364 display->grab_anchor_window_pos.x,
7365 display->grab_anchor_window_pos.y,
7366 dx, dy);
7367
7368 /* Don't bother doing anything if no move has been specified. (This
7369 * happens often, even in keyboard moving, due to the warping of the
7370 * pointer.
7371 */
7372 if (dx == 0 && dy == 0)
7373 return;
7374
7375 /* Originally for detaching maximized windows, but we use this
7376 * for the zones at the sides of the monitor where trigger tiling
7377 * because it's about the right size
7378 */
7379
7380#define DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR2 2
7381 shake_threshold = meta_ui_get_drag_threshold (window->screen->ui) *
7382 DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR2;
7383
7384 if (snap)
7385 {
7386 /* We don't want to tile while snapping. Also, clear any previous tile
7387 request. */
7388 window->tile_mode = META_TILE_NONE;
7389 window->tile_monitor_number = -1;
7390 window->tile_cycle = META_TILE_CYCLE_NONE;
7391 }
7392 else if (meta_prefs_get_allow_tiling () &&
7393 !META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
&&
7394 !META_WINDOW_TILED (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) || ((window)->
tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT)))
)
7395 {
7396 const MetaXineramaScreenInfo *monitor;
7397 MetaRectangle work_area;
7398
7399 /* For side-by-side tiling we are interested in the inside vertical
7400 * edges of the work area of the monitor where the pointer is located,
7401 * and in the outside top edge for maximized tiling.
7402 *
7403 * For maximized tiling we use the outside edge instead of the
7404 * inside edge, because we don't want to force users to maximize
7405 * windows they are placing near the top of their screens.
7406 *
7407 * The "current" idea of meta_window_get_work_area_for_xinerama() and
7408 * meta_screen_get_current_xinerama() is slightly different: the former
7409 * refers to the monitor which contains the largest part of the window,
7410 * the latter to the one where the pointer is located.
7411 */
7412 monitor = meta_screen_get_current_xinerama (window->screen);
7413 meta_window_get_work_area_for_xinerama (window,
7414 monitor->number,
7415 &work_area);
7416
7417 /* Check if the cursor is in a position which triggers tiling
7418 * and set tile_mode accordingly.
7419 */
7420 MetaTileMode old_tile_mode = window->tile_mode;
7421 window->tile_mode = calculate_tiling_mode(x, y, window, monitor,
7422 work_area, shake_threshold);
7423
7424 if (window->tile_mode != META_TILE_NONE)
7425 window->tile_monitor_number = monitor->number;
7426
7427 /* Reset resized and cycle flags when changing tile mode */
7428 if (old_tile_mode != window->tile_mode)
7429 {
7430 window->tile_resized = FALSE(0);
7431 window->tile_cycle = META_TILE_CYCLE_NONE;
7432 }
7433 }
7434
7435 /* shake loose (unmaximize) maximized or tiled window if dragged beyond
7436 * the threshold in the Y direction. Tiled windows can also be pulled
7437 * loose via X motion.
7438 */
7439
7440 if ((META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
&& ABS (dy)(((dy) < 0) ? -(dy) : (dy)) >= shake_threshold) ||
7441 (META_WINDOW_TILED (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) || ((window)->
tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT)))
&& (MAX (ABS (dx), ABS (dy))((((((dx) < 0) ? -(dx) : (dx))) > ((((dy) < 0) ? -(dy
) : (dy)))) ? ((((dx) < 0) ? -(dx) : (dx))) : ((((dy) <
0) ? -(dy) : (dy))))
>= shake_threshold)))
7442 {
7443 double prop;
7444
7445 /* Shake loose, so that the window snaps back to maximized
7446 * when dragged near the top; do not snap back if the window
7447 * was tiled.
7448 */
7449 window->shaken_loose = META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
;
7450 window->tile_mode = META_TILE_NONE;
7451 window->tile_cycle = META_TILE_CYCLE_NONE;
7452 window->tiled = FALSE(0);
7453
7454 /* move the unmaximized window to the cursor */
7455 prop =
7456 ((double)(x - display->grab_initial_window_pos.x)) /
7457 ((double)display->grab_initial_window_pos.width);
7458
7459 display->grab_initial_window_pos.x =
7460 x - (int) (prop * (double) window->saved_rect.width);
7461 display->grab_initial_window_pos.y = y;
7462
7463 if (window->frame)
7464 {
7465 display->grab_initial_window_pos.y += window->frame->child_y / 2;
7466 }
7467
7468 window->saved_rect.x = display->grab_initial_window_pos.x;
7469 window->saved_rect.y = display->grab_initial_window_pos.y;
7470 display->grab_anchor_root_x = x;
7471 display->grab_anchor_root_y = y;
7472
7473 meta_window_unmaximize (window,
7474 META_MAXIMIZE_HORIZONTAL |
7475 META_MAXIMIZE_VERTICAL);
7476
7477 return;
7478 }
7479 /* remaximize window on an other xinerama monitor if window has
7480 * been shaken loose or it is still maximized (then move straight)
7481 */
7482 else if (window->shaken_loose || META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
)
7483 {
7484 const MetaXineramaScreenInfo *wxinerama;
7485 MetaRectangle work_area;
7486 int monitor;
7487
7488 wxinerama = meta_screen_get_xinerama_for_window (window->screen, window);
7489
7490 for (monitor = 0; monitor < window->screen->n_xinerama_infos; monitor++)
7491 {
7492 meta_window_get_work_area_for_xinerama (window, monitor, &work_area);
7493
7494 /* check if cursor is near the top of a xinerama work area */
7495 if (x >= work_area.x + shake_threshold &&
7496 x < (work_area.x + work_area.width - shake_threshold) &&
7497 y >= work_area.y &&
7498 y < (work_area.y + shake_threshold))
7499 {
7500 /* move the saved rect if window will become maximized on an
7501 * other monitor so user isn't surprised on a later unmaximize
7502 */
7503 if (wxinerama->number != monitor)
7504 {
7505 window->saved_rect.x = work_area.x;
7506 window->saved_rect.y = work_area.y;
7507
7508 if (window->frame)
7509 {
7510 window->saved_rect.x += window->frame->child_x;
7511 window->saved_rect.y += window->frame->child_y;
7512 }
7513
7514 window->user_rect.x = window->saved_rect.x;
7515 window->user_rect.y = window->saved_rect.y;
7516
7517 meta_window_unmaximize (window,
7518 META_MAXIMIZE_HORIZONTAL |
7519 META_MAXIMIZE_VERTICAL);
7520 }
7521
7522 display->grab_initial_window_pos = work_area;
7523 display->grab_anchor_root_x = x;
7524 display->grab_anchor_root_y = y;
7525 window->shaken_loose = FALSE(0);
7526
7527 window->tile_mode = META_TILE_NONE;
7528 window->tile_cycle = META_TILE_CYCLE_NONE;
7529
7530 meta_window_maximize (window,
7531 META_MAXIMIZE_HORIZONTAL |
7532 META_MAXIMIZE_VERTICAL);
7533
7534 return;
7535 }
7536 }
7537 }
7538
7539 /* Delay showing the tile preview slightly to make it more unlikely to
7540 * trigger it unwittingly, e.g. when shaking loose the window or moving
7541 * it to another monitor.
7542 */
7543
7544 meta_screen_tile_preview_update (window->screen,
7545 window->tile_mode != META_TILE_NONE);
7546
7547 if (display->grab_wireframe_active)
7548 old = display->grab_wireframe_rect;
7549 else
7550 meta_window_get_client_root_coords (window, &old);
7551
7552 /* Don't allow movement in the maximized directions or while tiled */
7553
7554 if (window->maximized_horizontally || META_WINDOW_TILED (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) || ((window)->
tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT)))
)
7555 {
7556 new_x = old.x;
7557 }
7558
7559 if (window->maximized_vertically || META_WINDOW_CORNER_TILED(window)((window)->tiled && ((window)->tile_mode == META_TILE_BOTTOM_RIGHT
|| (window)->tile_mode == META_TILE_BOTTOM_LEFT || (window
)->tile_mode == META_TILE_TOP_RIGHT || (window)->tile_mode
== META_TILE_TOP_LEFT))
)
7560 {
7561 new_y = old.y;
7562 }
7563
7564 /* Do any edge resistance/snapping */
7565 meta_window_edge_resistance_for_move (window,
7566 old.x,
7567 old.y,
7568 &new_x,
7569 &new_y,
7570 update_move_timeout,
7571 snap,
7572 FALSE(0));
7573
7574 if (display->compositor)
7575 {
7576 int root_x = new_x - display->grab_anchor_window_pos.x + display->grab_anchor_root_x;
7577 int root_y = new_y - display->grab_anchor_window_pos.y + display->grab_anchor_root_y;
7578
7579 meta_compositor_update_move (display->compositor,
7580 window, root_x, root_y);
7581 }
7582
7583 if (display->grab_wireframe_active)
7584 meta_window_update_wireframe (window, new_x, new_y,
7585 display->grab_wireframe_rect.width,
7586 display->grab_wireframe_rect.height);
7587 else
7588 meta_window_move (window, TRUE(!(0)), new_x, new_y);
7589}
7590
7591static MetaTileMode calculate_tiling_mode(int x,
7592 int y,
7593 MetaWindow *window,
7594 const MetaXineramaScreenInfo *monitor,
7595 MetaRectangle work_area,
7596 int shake_threshold)
7597{
7598 if (meta_window_can_tile (window) &&
7599 x >= monitor->rect.x
7600 && x < (work_area.x + shake_threshold))
7601 {
7602 if(y >= monitor->rect.y && y < work_area.y + shake_threshold)
7603 return META_TILE_TOP_LEFT;
7604 else if(y < monitor->rect.y + monitor->rect.height
7605 && y > work_area.y + work_area.height - shake_threshold)
7606 return META_TILE_BOTTOM_LEFT;
7607 else
7608 return META_TILE_LEFT;
7609 }
7610
7611 else if (meta_window_can_tile (window) &&
7612 x >= work_area.x + work_area.width - shake_threshold &&
7613 x < (monitor->rect.x + monitor->rect.width))
7614 {
7615 if(y >= monitor->rect.y && y < work_area.y + shake_threshold)
7616 return META_TILE_TOP_RIGHT;
7617 else if(y < monitor->rect.y + monitor->rect.height
7618 && y > work_area.y + work_area.height - shake_threshold)
7619 return META_TILE_BOTTOM_RIGHT;
7620 else
7621 return META_TILE_RIGHT;
7622 }
7623 else if (meta_window_can_tile_maximized (window) &&
7624 y >= monitor->rect.y && y <= work_area.y &&
7625 meta_prefs_get_allow_top_tiling ())
7626 return META_TILE_MAXIMIZED;
7627 else
7628 return META_TILE_NONE;
7629
7630}
7631
7632static gboolean
7633update_resize_timeout (gpointer data)
7634{
7635 MetaWindow *window = data;
7636
7637 update_resize (window,
7638 window->display->grab_last_user_action_was_snap != FALSE(0),
7639 window->display->grab_latest_motion_x,
7640 window->display->grab_latest_motion_y,
7641 TRUE(!(0)));
7642 return FALSE(0);
7643}
7644
7645static void
7646update_resize (MetaWindow *window,
7647 gboolean snap,
7648 int x, int y,
7649 gboolean force)
7650{
7651 int dx, dy;
7652 int new_w, new_h;
7653 int gravity;
7654 MetaRectangle old;
7655 int new_x, new_y;
7656 double remaining;
7657
7658 window->display->grab_latest_motion_x = x;
7659 window->display->grab_latest_motion_y = y;
7660
7661 dx = x - window->display->grab_anchor_root_x;
7662 dy = y - window->display->grab_anchor_root_y;
7663
7664 new_w = window->display->grab_anchor_window_pos.width;
7665 new_h = window->display->grab_anchor_window_pos.height;
7666
7667 /* Don't bother doing anything if no move has been specified. (This
7668 * happens often, even in keyboard resizing, due to the warping of the
7669 * pointer.
7670 */
7671 if (dx == 0 && dy == 0)
7672 return;
7673
7674 /* FIXME this is only used in wireframe mode */
7675 new_x = window->display->grab_anchor_window_pos.x;
7676 new_y = window->display->grab_anchor_window_pos.y;
7677
7678 if (window->display->grab_op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN)
7679 {
7680 if ((dx > 0) && (dy > 0))
7681 {
7682 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SE;
7683 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7684 }
7685 else if ((dx < 0) && (dy > 0))
7686 {
7687 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SW;
7688 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7689 }
7690 else if ((dx > 0) && (dy < 0))
7691 {
7692 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NE;
7693 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7694 }
7695 else if ((dx < 0) && (dy < 0))
7696 {
7697 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NW;
7698 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7699 }
7700 else if (dx < 0)
7701 {
7702 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
7703 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7704 }
7705 else if (dx > 0)
7706 {
7707 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
7708 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7709 }
7710 else if (dy > 0)
7711 {
7712 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
7713 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7714 }
7715 else if (dy < 0)
7716 {
7717 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
7718 meta_window_update_keyboard_resize (window, TRUE(!(0)));
7719 }
7720 }
7721
7722 /* FIXME: This stupidity only needed because of wireframe mode and
7723 * the fact that wireframe isn't making use of
7724 * meta_rectangle_resize_with_gravity(). If we were to use that, we
7725 * could just increment new_w and new_h by dx and dy in all cases.
7726 */
7727 switch (window->display->grab_op)
7728 {
7729 case META_GRAB_OP_RESIZING_SE:
7730 case META_GRAB_OP_RESIZING_NE:
7731 case META_GRAB_OP_RESIZING_E:
7732 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
7733 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
7734 case META_GRAB_OP_KEYBOARD_RESIZING_E:
7735 new_w += dx;
7736 break;
7737
7738 case META_GRAB_OP_RESIZING_NW:
7739 case META_GRAB_OP_RESIZING_SW:
7740 case META_GRAB_OP_RESIZING_W:
7741 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
7742 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
7743 case META_GRAB_OP_KEYBOARD_RESIZING_W:
7744 new_w -= dx;
7745 new_x += dx;
7746 break;
7747
7748 default:
7749 break;
7750 }
7751
7752 switch (window->display->grab_op)
7753 {
7754 case META_GRAB_OP_RESIZING_SE:
7755 case META_GRAB_OP_RESIZING_S:
7756 case META_GRAB_OP_RESIZING_SW:
7757 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
7758 case META_GRAB_OP_KEYBOARD_RESIZING_S:
7759 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
7760 new_h += dy;
7761 break;
7762
7763 case META_GRAB_OP_RESIZING_N:
7764 case META_GRAB_OP_RESIZING_NE:
7765 case META_GRAB_OP_RESIZING_NW:
7766 case META_GRAB_OP_KEYBOARD_RESIZING_N:
7767 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
7768 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
7769 new_h -= dy;
7770 new_y += dy;
7771 break;
7772 default:
7773 break;
7774 }
7775
7776 if (!check_moveresize_frequency (window, &remaining) && !force)
7777 {
7778 /* we are ignoring an event here, so we schedule a
7779 * compensation event when we would otherwise not ignore
7780 * an event. Otherwise we can become stuck if the user never
7781 * generates another event.
7782 */
7783 if (!window->display->grab_resize_timeout_id)
7784 {
7785 window->display->grab_resize_timeout_id =
7786 g_timeout_add ((int)remaining, update_resize_timeout, window);
7787 }
7788
7789 return;
7790 }
7791
7792 /* If we get here, it means the client should have redrawn itself */
7793 if (window->display->compositor)
7794 meta_compositor_set_updates (window->display->compositor, window, TRUE(!(0)));
7795
7796 /* Remove any scheduled compensation events */
7797 if (window->display->grab_resize_timeout_id)
7798 {
7799 g_source_remove (window->display->grab_resize_timeout_id);
7800 window->display->grab_resize_timeout_id = 0;
7801 }
7802
7803 if (window->display->grab_wireframe_active)
7804 old = window->display->grab_wireframe_rect;
7805 else
7806 old = window->rect; /* Don't actually care about x,y */
7807
7808 /* One sided resizing ought to actually be one-sided, despite the fact that
7809 * aspect ratio windows don't interact nicely with the above stuff. So,
7810 * to avoid some nasty flicker, we enforce that.
7811 */
7812 switch (window->display->grab_op)
7813 {
7814 case META_GRAB_OP_RESIZING_S:
7815 case META_GRAB_OP_RESIZING_N:
7816 new_w = old.width;
7817 break;
7818
7819 case META_GRAB_OP_RESIZING_E:
7820 case META_GRAB_OP_RESIZING_W:
7821 new_h = old.height;
7822 break;
7823
7824 default:
7825 break;
7826 }
7827
7828 /* compute gravity of client during operation */
7829 gravity = meta_resize_gravity_from_grab_op (window->display->grab_op);
7830 g_assert (gravity >= 0)do { if (gravity >= 0) ; else g_assertion_message_expr ("marco"
, "core/window.c", 7830, ((const char*) (__func__)), "gravity >= 0"
); } while (0)
;
7831
7832 /* Do any edge resistance/snapping */
7833 meta_window_edge_resistance_for_resize (window,
7834 old.width,
7835 old.height,
7836 &new_w,
7837 &new_h,
7838 gravity,
7839 update_resize_timeout,
7840 snap,
7841 FALSE(0));
7842
7843 if (window->display->grab_wireframe_active)
7844 {
7845 if ((new_x + new_w <= new_x) || (new_y + new_h <= new_y))
7846 return;
7847
7848 /* FIXME This is crap. For example, the wireframe isn't
7849 * constrained in the way that a real resize would be. An
7850 * obvious elegant solution is to unmap the window during
7851 * wireframe, but still resize it; however, that probably
7852 * confuses broken clients that have problems with opaque
7853 * resize, they probably don't track their visibility.
7854 */
7855 meta_window_update_wireframe (window, new_x, new_y, new_w, new_h);
7856 }
7857 else
7858 {
7859 /* We don't need to update unless the specified width and height
7860 * are actually different from what we had before.
7861 */
7862 if (old.width != new_w || old.height != new_h)
7863 meta_window_resize_with_gravity (window, TRUE(!(0)), new_w, new_h, gravity);
7864 }
7865
7866 /* Store the latest resize time, if we actually resized. */
7867 if (window->rect.width != old.width || window->rect.height != old.height)
7868 window->display->grab_last_moveresize_time = g_get_real_time ();
7869}
7870
7871typedef struct
7872{
7873 const XEvent *current_event;
7874 int count;
7875 guint32 last_time;
7876} EventScannerData;
7877
7878static Boolint
7879find_last_time_predicate (Display *display,
7880 XEvent *xevent,
7881 XPointer arg)
7882{
7883 EventScannerData *esd = (void*) arg;
7884
7885 if (esd->current_event->type == xevent->type &&
7886 esd->current_event->xany.window == xevent->xany.window)
7887 {
7888 esd->count += 1;
7889 esd->last_time = xevent->xmotion.time;
7890 }
7891
7892 return False0;
7893}
7894
7895static gboolean
7896check_use_this_motion_notify (MetaWindow *window,
7897 XEvent *event)
7898{
7899 EventScannerData esd;
7900 XEvent useless;
7901
7902 /* This code is copied from Owen's GDK code. */
7903
7904 if (window->display->grab_motion_notify_time != 0)
7905 {
7906 /* == is really the right test, but I'm all for paranoia */
7907 if (window->display->grab_motion_notify_time <=
7908 event->xmotion.time)
7909 {
7910 meta_topicmeta_topic_real (META_DEBUG_RESIZING,
7911 "Arrived at event with time %u (waiting for %u), using it\n",
7912 (unsigned int)event->xmotion.time,
7913 window->display->grab_motion_notify_time);
7914
7915 window->display->grab_motion_notify_time = 0;
7916 return TRUE(!(0));
7917 }
7918 else
7919 return FALSE(0); /* haven't reached the saved timestamp yet */
7920 }
7921
7922 esd.current_event = event;
7923 esd.count = 0;
7924 esd.last_time = 0;
7925
7926 /* "useless" isn't filled in because the predicate never returns True */
7927 XCheckIfEvent (window->display->xdisplay,
7928 &useless,
7929 find_last_time_predicate,
7930 (XPointer) &esd);
7931
7932 if (esd.count > 0)
7933 meta_topicmeta_topic_real (META_DEBUG_RESIZING,
7934 "Will skip %d motion events and use the event with time %u\n",
7935 esd.count, (unsigned int) esd.last_time);
7936
7937 if (esd.last_time == 0)
7938 return TRUE(!(0));
7939 else
7940 {
7941 /* Save this timestamp, and ignore all motion notify
7942 * until we get to the one with this stamp.
7943 */
7944 window->display->grab_motion_notify_time = esd.last_time;
7945 return FALSE(0);
7946 }
7947}
7948
7949static void
7950update_tile_mode (MetaWindow *window)
7951{
7952 switch (window->tile_mode)
7953 {
7954 case META_TILE_LEFT:
7955 case META_TILE_RIGHT:
7956 if (!META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
)
7957 window->tile_mode = META_TILE_NONE;
7958 break;
7959 }
7960}
7961
7962void
7963meta_window_handle_mouse_grab_op_event (MetaWindow *window,
7964 XEvent *event)
7965{
7966#ifdef HAVE_XSYNC
7967 if (event->type == (window->display->xsync_event_base + XSyncAlarmNotify1))
7968 {
7969 meta_topicmeta_topic_real (META_DEBUG_RESIZING,
7970 "Alarm event received last motion x = %d y = %d\n",
7971 window->display->grab_latest_motion_x,
7972 window->display->grab_latest_motion_y);
7973
7974 /* If sync was previously disabled, turn it back on and hope
7975 * the application has come to its senses (maybe it was just
7976 * busy with a pagefault or a long computation).
7977 */
7978 window->disable_sync = FALSE(0);
7979 window->sync_request_time = 0;
7980
7981 /* This means we are ready for another configure. */
7982 switch (window->display->grab_op)
7983 {
7984 case META_GRAB_OP_RESIZING_E:
7985 case META_GRAB_OP_RESIZING_W:
7986 case META_GRAB_OP_RESIZING_S:
7987 case META_GRAB_OP_RESIZING_N:
7988 case META_GRAB_OP_RESIZING_SE:
7989 case META_GRAB_OP_RESIZING_SW:
7990 case META_GRAB_OP_RESIZING_NE:
7991 case META_GRAB_OP_RESIZING_NW:
7992 case META_GRAB_OP_KEYBOARD_RESIZING_S:
7993 case META_GRAB_OP_KEYBOARD_RESIZING_N:
7994 case META_GRAB_OP_KEYBOARD_RESIZING_W:
7995 case META_GRAB_OP_KEYBOARD_RESIZING_E:
7996 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
7997 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
7998 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
7999 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
8000 /* no pointer round trip here, to keep in sync */
8001 update_resize (window,
8002 window->display->grab_last_user_action_was_snap != FALSE(0),
8003 window->display->grab_latest_motion_x,
8004 window->display->grab_latest_motion_y,
8005 TRUE(!(0)));
8006 break;
8007
8008 default:
8009 break;
8010 }
8011 }
8012#endif /* HAVE_XSYNC */
8013
8014 switch (event->type)
8015 {
8016 case ButtonRelease5:
8017 meta_display_check_threshold_reached (window->display,
8018 event->xbutton.x_root,
8019 event->xbutton.y_root);
8020 /* If the user was snap moving then ignore the button release
8021 * because they may have let go of shift before releasing the
8022 * mouse button and they almost certainly do not want a
8023 * non-snapped movement to occur from the button release.
8024 */
8025 if (!window->display->grab_last_user_action_was_snap)
8026 {
8027 if (meta_grab_op_is_moving (window->display->grab_op))
8028 {
8029 if (window->tile_mode == META_TILE_MAXIMIZED)
8030 {
8031 meta_window_maximize (window, META_MAXIMIZE_VERTICAL |
8032 META_MAXIMIZE_HORIZONTAL);
8033 window->tile_mode = META_TILE_NONE;
8034 }
8035 else if (window->tile_mode != META_TILE_NONE)
8036 {
8037 meta_window_tile (window);
8038 }
8039 else if (event->xbutton.root == window->screen->xroot)
8040 update_move (window, event->xbutton.state & ShiftMask(1<<0),
8041 event->xbutton.x_root, event->xbutton.y_root);
8042 }
8043 else if (meta_grab_op_is_resizing (window->display->grab_op))
8044 {
8045 if (event->xbutton.root == window->screen->xroot)
8046 update_resize (window,
8047 event->xbutton.state & ShiftMask(1<<0),
8048 event->xbutton.x_root,
8049 event->xbutton.y_root,
8050 TRUE(!(0)));
8051 if (window->display->compositor)
8052 meta_compositor_set_updates (window->display->compositor, window, TRUE(!(0)));
8053
8054 /* If a tiled window has been dragged free with a
8055 * mouse resize without snapping back to the tiled
8056 * state, it will end up with an inconsistent tile
8057 * mode on mouse release; cleaning the mode earlier
8058 * would break the ability to snap back to the tiled
8059 * state, so we wait until mouse release.
8060 */
8061 update_tile_mode (window);
8062 }
8063 }
8064
8065 meta_display_end_grab_op (window->display, event->xbutton.time);
8066 break;
8067
8068 case MotionNotify6:
8069 meta_display_check_threshold_reached (window->display,
8070 event->xmotion.x_root,
8071 event->xmotion.y_root);
8072 if (meta_grab_op_is_moving (window->display->grab_op))
8073 {
8074 if (event->xmotion.root == window->screen->xroot)
8075 {
8076 if (check_use_this_motion_notify (window,
8077 event))
8078 update_move (window,
8079 event->xmotion.state & ShiftMask(1<<0),
8080 event->xmotion.x_root,
8081 event->xmotion.y_root);
8082 }
8083 }
8084 else if (meta_grab_op_is_resizing (window->display->grab_op))
8085 {
8086 if (event->xmotion.root == window->screen->xroot)
8087 {
8088 if (check_use_this_motion_notify (window,
8089 event))
8090 update_resize (window,
8091 event->xmotion.state & ShiftMask(1<<0),
8092 event->xmotion.x_root,
8093 event->xmotion.y_root,
8094 FALSE(0));
8095 }
8096 }
8097 break;
8098
8099 default:
8100 break;
8101 }
8102}
8103
8104void
8105meta_window_set_gravity (MetaWindow *window,
8106 int gravity)
8107{
8108 XSetWindowAttributes attrs;
8109
8110 meta_verbosemeta_verbose_real ("Setting gravity of %s to %d\n", window->desc, gravity);
8111
8112 attrs.win_gravity = gravity;
8113
8114 meta_error_trap_push (window->display);
8115
8116 XChangeWindowAttributes (window->display->xdisplay,
8117 window->xwindow,
8118 CWWinGravity(1L<<5),
8119 &attrs);
8120
8121 meta_error_trap_pop (window->display, FALSE(0));
8122}
8123
8124static void
8125get_work_area_xinerama (MetaWindow *window,
8126 MetaRectangle *area,
8127 int which_xinerama)
8128{
8129 GList *tmp;
8130
8131 g_assert (which_xinerama >= 0)do { if (which_xinerama >= 0) ; else g_assertion_message_expr
("marco", "core/window.c", 8131, ((const char*) (__func__)),
"which_xinerama >= 0"); } while (0)
;
8132
8133 /* Initialize to the whole xinerama */
8134 *area = window->screen->xinerama_infos[which_xinerama].rect;
8135
8136 tmp = meta_window_get_workspaces (window);
8137 while (tmp != NULL((void*)0))
8138 {
8139 MetaRectangle workspace_work_area;
8140 meta_workspace_get_work_area_for_xinerama (tmp->data,
8141 which_xinerama,
8142 &workspace_work_area);
8143 meta_rectangle_intersect (area,
8144 &workspace_work_area,
8145 area);
8146 tmp = tmp->next;
8147 }
8148
8149 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
8150 "Window %s xinerama %d has work area %d,%d %d x %d\n",
8151 window->desc, which_xinerama,
8152 area->x, area->y, area->width, area->height);
8153}
8154
8155void
8156meta_window_get_work_area_current_xinerama (MetaWindow *window,
8157 MetaRectangle *area)
8158{
8159 const MetaXineramaScreenInfo *xinerama = NULL((void*)0);
8160 xinerama = meta_screen_get_xinerama_for_window (window->screen,
8161 window);
8162
8163 meta_window_get_work_area_for_xinerama (window,
8164 xinerama->number,
8165 area);
8166}
8167
8168void
8169meta_window_get_work_area_for_xinerama (MetaWindow *window,
8170 int which_xinerama,
8171 MetaRectangle *area)
8172{
8173 g_return_if_fail (which_xinerama >= 0)do { if ((which_xinerama >= 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "which_xinerama >= 0"
); return; } } while (0)
;
8174
8175 get_work_area_xinerama (window,
8176 area,
8177 which_xinerama);
8178}
8179
8180void
8181meta_window_get_work_area_all_xineramas (MetaWindow *window,
8182 MetaRectangle *area)
8183{
8184 GList *tmp;
8185
8186 /* Initialize to the whole screen */
8187 *area = window->screen->rect;
8188
8189 tmp = meta_window_get_workspaces (window);
8190 while (tmp != NULL((void*)0))
8191 {
8192 MetaRectangle workspace_work_area;
8193 meta_workspace_get_work_area_all_xineramas (tmp->data,
8194 &workspace_work_area);
8195 meta_rectangle_intersect (area,
8196 &workspace_work_area,
8197 area);
8198 tmp = tmp->next;
8199 }
8200
8201 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
8202 "Window %s has whole-screen work area %d,%d %d x %d\n",
8203 window->desc, area->x, area->y, area->width, area->height);
8204}
8205
8206void
8207meta_window_get_current_tile_area (MetaWindow *window,
8208 MetaRectangle *tile_area)
8209{
8210 int tile_monitor_number;
8211 int width;
8212 double tile_ratio;
8213
8214 g_return_if_fail (window->tile_mode != META_TILE_NONE)do { if ((window->tile_mode != META_TILE_NONE)) { } else {
g_return_if_fail_warning ("marco", ((const char*) (__func__)
), "window->tile_mode != META_TILE_NONE"); return; } } while
(0)
;
8215
8216 /* I don't know how to detect monitor configuration changes, so I have to take into account that
8217 * tile_monitor_number might be invalid. If this happens, I replace it with whatever monitor
8218 * the window is currently on. This is usually the correct monitor anyway, only in some special
8219 * cases is the real monitor number actually required (e.g. the window is being moved with the mouse but
8220 * is still mostly on the wrong monitor).
8221 */
8222 if (window->tile_monitor_number >= window->screen->n_xinerama_infos)
8223 {
8224 window->tile_monitor_number = meta_screen_get_xinerama_for_window (window->screen, window)->number;
8225 }
8226
8227 tile_monitor_number = window->tile_monitor_number;
8228 if (tile_monitor_number < 0)
8229 {
8230 meta_warning ("%s called with an invalid monitor number; using 0 instead\n", G_STRFUNC((const char*) (__func__)));
8231 tile_monitor_number = 0;
8232 }
8233
8234 meta_window_get_work_area_for_xinerama (window, tile_monitor_number, tile_area);
8235
8236 width = tile_area->width;
8237
8238 switch (window->tile_cycle)
8239 {
8240 case META_TILE_CYCLE_33:
8241 tile_ratio = 1 / 3.0;
8242 break;
8243 case META_TILE_CYCLE_25:
8244 tile_ratio = 1 / 4.0;
8245 break;
8246 case META_TILE_CYCLE_100:
8247 tile_ratio = 1 / 1.0;
8248 break;
8249 case META_TILE_CYCLE_75:
8250 tile_ratio = 3 / 4.0;
8251 break;
8252 case META_TILE_CYCLE_66:
8253 tile_ratio = 2 / 3.0;
8254 break;
8255 case META_TILE_CYCLE_50:
8256 case META_TILE_CYCLE_NONE:
8257 default:
8258 tile_ratio = 1 / 2.0;
8259 break;
8260 }
8261
8262 if (window->tile_mode != META_TILE_NONE &&
8263 window->tile_mode != META_TILE_MAXIMIZED)
8264 width = (int)(tile_area->width * tile_ratio);
8265
8266 if(window->tile_mode == META_TILE_BOTTOM_LEFT ||
8267 window->tile_mode == META_TILE_BOTTOM_RIGHT ||
8268 window->tile_mode == META_TILE_TOP_LEFT ||
8269 window->tile_mode == META_TILE_TOP_RIGHT)
8270 tile_area->height /= 2;
8271
8272 if (window->tile_mode == META_TILE_RIGHT ||
8273 window->tile_mode == META_TILE_TOP_RIGHT ||
8274 window->tile_mode == META_TILE_BOTTOM_RIGHT)
8275 tile_area->x += tile_area->width - width;
8276
8277 if(window->tile_mode == META_TILE_BOTTOM_LEFT ||
8278 window->tile_mode == META_TILE_BOTTOM_RIGHT)
8279 tile_area->y += tile_area->height;
8280
8281 tile_area->width = width;
8282}
8283
8284gboolean
8285meta_window_same_application (MetaWindow *window,
8286 MetaWindow *other_window)
8287{
8288 MetaGroup *group = meta_window_get_group (window);
8289 MetaGroup *other_group = meta_window_get_group (other_window);
8290
8291 return
8292 group!=NULL((void*)0) &&
8293 other_group!=NULL((void*)0) &&
8294 group==other_group;
8295}
8296
8297/* Generally meta_window_same_application() is a better idea
8298 * of "sameness", since it handles the case where multiple apps
8299 * want to look like the same app or the same app wants to look
8300 * like multiple apps, but in the case of workarounds for legacy
8301 * applications (which likely aren't setting the group properly
8302 * anyways), it may be desirable to check this as well.
8303 */
8304static gboolean
8305meta_window_same_client (MetaWindow *window,
8306 MetaWindow *other_window)
8307{
8308 int resource_mask = window->display->xdisplay->resource_mask;
8309
8310 return ((window->xwindow & ~resource_mask) ==
8311 (other_window->xwindow & ~resource_mask));
8312}
8313
8314void
8315meta_window_refresh_resize_popup (MetaWindow *window)
8316{
8317 if (window->display->grab_op == META_GRAB_OP_NONE)
8318 return;
8319
8320 if (window->display->grab_window != window)
8321 return;
8322
8323 /* We shouldn't ever get called when the wireframe is active
8324 * because that's handled by a different code path in effects.c
8325 */
8326 if (window->display->grab_wireframe_active)
8327 {
8328 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
8329 "refresh_resize_popup called when wireframe active\n");
8330 return;
8331 }
8332
8333 switch (window->display->grab_op)
8334 {
8335 case META_GRAB_OP_RESIZING_SE:
8336 case META_GRAB_OP_RESIZING_S:
8337 case META_GRAB_OP_RESIZING_SW:
8338 case META_GRAB_OP_RESIZING_N:
8339 case META_GRAB_OP_RESIZING_NE:
8340 case META_GRAB_OP_RESIZING_NW:
8341 case META_GRAB_OP_RESIZING_W:
8342 case META_GRAB_OP_RESIZING_E:
8343 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
8344 case META_GRAB_OP_KEYBOARD_RESIZING_S:
8345 case META_GRAB_OP_KEYBOARD_RESIZING_N:
8346 case META_GRAB_OP_KEYBOARD_RESIZING_W:
8347 case META_GRAB_OP_KEYBOARD_RESIZING_E:
8348 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
8349 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
8350 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
8351 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
8352 break;
8353
8354 default:
8355 /* Not resizing */
8356 return;
8357 }
8358
8359 if (window->display->grab_resize_popup == NULL((void*)0))
8360 {
8361 gint scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
8362 /* Display the resize popup only for windows that report an
8363 * increment hint that's larger than the scale factor. */
8364 if (window->size_hints.width_inc > scale ||
8365 window->size_hints.height_inc > scale)
8366 window->display->grab_resize_popup =
8367 meta_ui_resize_popup_new (window->display->xdisplay,
8368 window->screen->number);
8369 }
8370
8371 if (window->display->grab_resize_popup != NULL((void*)0))
8372 {
8373 MetaRectangle rect;
8374
8375 if (window->display->grab_wireframe_active)
8376 rect = window->display->grab_wireframe_rect;
8377 else
8378 meta_window_get_client_root_coords (window, &rect);
8379
8380 meta_ui_resize_popup_set (window->display->grab_resize_popup,
8381 rect,
8382 window->size_hints.base_width,
8383 window->size_hints.base_height,
8384 window->size_hints.width_inc,
8385 window->size_hints.height_inc);
8386
8387 meta_ui_resize_popup_set_showing (window->display->grab_resize_popup,
8388 TRUE(!(0)));
8389 }
8390}
8391
8392void
8393meta_window_foreach_transient (MetaWindow *window,
8394 MetaWindowForeachFunc func,
8395 void *data)
8396{
8397 GSList *windows;
8398 GSList *tmp;
8399
8400 windows = meta_display_list_windows (window->display);
8401
8402 tmp = windows;
8403 while (tmp != NULL((void*)0))
8404 {
8405 MetaWindow *transient = tmp->data;
8406
8407 if (meta_window_is_ancestor_of_transient (window, transient))
8408 {
8409 if (!(* func) (transient, data))
8410 break;
8411 }
8412
8413 tmp = tmp->next;
8414 }
8415
8416 g_slist_free (windows);
8417}
8418
8419void
8420meta_window_foreach_ancestor (MetaWindow *window,
8421 MetaWindowForeachFunc func,
8422 void *data)
8423{
8424 MetaWindow *w;
8425 MetaWindow *tortoise;
8426
8427 w = window;
8428 tortoise = window;
8429 while (TRUE(!(0)))
8430 {
8431 if (w->xtransient_for == None0L ||
8432 w->transient_parent_is_root_window)
8433 break;
8434
8435 w = meta_display_lookup_x_window (w->display, w->xtransient_for);
8436
8437 if (w == NULL((void*)0) || w == tortoise)
8438 break;
8439
8440 if (!(* func) (w, data))
8441 break;
8442
8443 if (w->xtransient_for == None0L ||
8444 w->transient_parent_is_root_window)
8445 break;
8446
8447 w = meta_display_lookup_x_window (w->display, w->xtransient_for);
8448
8449 if (w == NULL((void*)0) || w == tortoise)
8450 break;
8451
8452 if (!(* func) (w, data))
8453 break;
8454
8455 tortoise = meta_display_lookup_x_window (tortoise->display,
8456 tortoise->xtransient_for);
8457
8458 /* "w" should have already covered all ground covered by the
8459 * tortoise, so the following must hold.
8460 */
8461 g_assert (tortoise != NULL)do { if (tortoise != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/window.c", 8461, ((const char*) (__func__)),
"tortoise != NULL"); } while (0)
;
8462 g_assert (tortoise->xtransient_for != None)do { if (tortoise->xtransient_for != 0L) ; else g_assertion_message_expr
("marco", "core/window.c", 8462, ((const char*) (__func__)),
"tortoise->xtransient_for != None"); } while (0)
;
8463 g_assert (!tortoise->transient_parent_is_root_window)do { if (!tortoise->transient_parent_is_root_window) ; else
g_assertion_message_expr ("marco", "core/window.c", 8463, ((
const char*) (__func__)), "!tortoise->transient_parent_is_root_window"
); } while (0)
;
8464 }
8465}
8466
8467typedef struct
8468{
8469 MetaWindow *ancestor;
8470 gboolean found;
8471} FindAncestorData;
8472
8473static gboolean
8474find_ancestor_func (MetaWindow *window,
8475 void *data)
8476{
8477 FindAncestorData *d = data;
8478
8479 if (window == d->ancestor)
8480 {
8481 d->found = TRUE(!(0));
8482 return FALSE(0);
8483 }
8484
8485 return TRUE(!(0));
8486}
8487
8488gboolean
8489meta_window_is_ancestor_of_transient (MetaWindow *window,
8490 MetaWindow *transient)
8491{
8492 FindAncestorData d;
8493
8494 d.ancestor = window;
8495 d.found = FALSE(0);
8496
8497 meta_window_foreach_ancestor (transient, find_ancestor_func, &d);
8498
8499 return d.found;
8500}
8501
8502/* Warp pointer to location appropriate for grab,
8503 * return root coordinates where pointer ended up.
8504 */
8505static gboolean
8506warp_grab_pointer (MetaWindow *window,
8507 MetaGrabOp grab_op,
8508 int *x,
8509 int *y)
8510{
8511 MetaRectangle rect;
8512 MetaDisplay *display;
8513
8514 display = window->display;
8515
8516 /* We may not have done begin_grab_op yet, i.e. may not be in a grab
8517 */
8518
8519 if (window == display->grab_window && display->grab_wireframe_active)
8520 {
8521 meta_window_get_xor_rect (window, &display->grab_wireframe_rect, &rect);
8522 }
8523 else
8524 {
8525 meta_window_get_outer_rect (window, &rect);
8526 }
8527
8528 switch (grab_op)
8529 {
8530 case META_GRAB_OP_KEYBOARD_MOVING:
8531 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
8532 *x = rect.width / 2;
8533 *y = rect.height / 2;
8534 break;
8535
8536 case META_GRAB_OP_KEYBOARD_RESIZING_S:
8537 *x = rect.width / 2;
8538 *y = rect.height - 1;
8539 break;
8540
8541 case META_GRAB_OP_KEYBOARD_RESIZING_N:
8542 *x = rect.width / 2;
8543 *y = 0;
8544 break;
8545
8546 case META_GRAB_OP_KEYBOARD_RESIZING_W:
8547 *x = 0;
8548 *y = rect.height / 2;
8549 break;
8550
8551 case META_GRAB_OP_KEYBOARD_RESIZING_E:
8552 *x = rect.width - 1;
8553 *y = rect.height / 2;
8554 break;
8555
8556 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
8557 *x = rect.width - 1;
8558 *y = rect.height - 1;
8559 break;
8560
8561 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
8562 *x = rect.width - 1;
8563 *y = 0;
8564 break;
8565
8566 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
8567 *x = 0;
8568 *y = rect.height - 1;
8569 break;
8570
8571 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
8572 *x = 0;
8573 *y = 0;
8574 break;
8575
8576 default:
8577 return FALSE(0);
8578 }
8579
8580 *x += rect.x;
8581 *y += rect.y;
8582
8583 /* Avoid weird bouncing at the screen edge; see bug 154706 */
8584 *x = CLAMP (*x, 0, window->screen->rect.width-1)(((*x) > (window->screen->rect.width-1)) ? (window->
screen->rect.width-1) : (((*x) < (0)) ? (0) : (*x)))
;
8585 *y = CLAMP (*y, 0, window->screen->rect.height-1)(((*y) > (window->screen->rect.height-1)) ? (window->
screen->rect.height-1) : (((*y) < (0)) ? (0) : (*y)))
;
8586
8587 meta_error_trap_push (display);
8588
8589 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
8590 "Warping pointer to %d,%d with window at %d,%d\n",
8591 *x, *y, rect.x, rect.y);
8592
8593 /* Need to update the grab positions so that the MotionNotify and other
8594 * events generated by the XWarpPointer() call below don't cause complete
8595 * funkiness. See bug 124582 and bug 122670.
8596 */
8597 display->grab_anchor_root_x = *x;
8598 display->grab_anchor_root_y = *y;
8599 display->grab_latest_motion_x = *x;
8600 display->grab_latest_motion_y = *y;
8601 if (display->grab_wireframe_active)
8602 display->grab_anchor_window_pos = display->grab_wireframe_rect;
8603 else
8604 meta_window_get_client_root_coords (window,
8605 &display->grab_anchor_window_pos);
8606
8607 XWarpPointer (display->xdisplay,
8608 None0L,
8609 window->screen->xroot,
8610 0, 0, 0, 0,
8611 *x, *y);
8612
8613 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
8614 {
8615 meta_verbosemeta_verbose_real ("Failed to warp pointer for window %s\n",
8616 window->desc);
8617 return FALSE(0);
8618 }
8619
8620 return TRUE(!(0));
8621}
8622
8623void
8624meta_window_begin_grab_op (MetaWindow *window,
8625 MetaGrabOp op,
8626 gboolean frame_action,
8627 guint32 timestamp)
8628{
8629 int x, y;
8630
8631 warp_grab_pointer (window,
8632 op, &x, &y);
8633
8634 meta_display_begin_grab_op (window->display,
8635 window->screen,
8636 window,
8637 op,
8638 FALSE(0),
8639 frame_action,
8640 0 /* button */,
8641 0,
8642 timestamp,
8643 x, y);
8644}
8645
8646void
8647meta_window_update_keyboard_resize (MetaWindow *window,
8648 gboolean update_cursor)
8649{
8650 int x, y;
8651
8652 warp_grab_pointer (window,
8653 window->display->grab_op,
8654 &x, &y);
8655
8656 if (update_cursor)
8657 {
8658 guint32 timestamp;
8659 /* FIXME: Using CurrentTime is really bad mojo */
8660 timestamp = CurrentTime0L;
8661 meta_display_set_grab_op_cursor (window->display,
8662 NULL((void*)0),
8663 window->display->grab_op,
8664 TRUE(!(0)),
8665 window->display->grab_xwindow,
8666 timestamp);
8667 }
8668}
8669
8670void
8671meta_window_update_keyboard_move (MetaWindow *window)
8672{
8673 int x, y;
8674
8675 warp_grab_pointer (window,
8676 window->display->grab_op,
8677 &x, &y);
8678}
8679
8680void
8681meta_window_update_layer (MetaWindow *window)
8682{
8683 MetaGroup *group;
8684
8685 meta_stack_freeze (window->screen->stack);
8686 group = meta_window_get_group (window);
8687 if (group)
8688 meta_group_update_layers (group);
8689 else
8690 meta_stack_update_layer (window->screen->stack, window);
8691 meta_stack_thaw (window->screen->stack);
8692}
8693
8694/* ensure_mru_position_after ensures that window appears after
8695 * below_this_one in the active_workspace's mru_list (i.e. it treats
8696 * window as having been less recently used than below_this_one)
8697 */
8698static void
8699ensure_mru_position_after (MetaWindow *window,
8700 MetaWindow *after_this_one)
8701{
8702 /* This is sort of slow since it runs through the entire list more
8703 * than once (especially considering the fact that we expect the
8704 * windows of interest to be the first two elements in the list),
8705 * but it doesn't matter while we're only using it on new window
8706 * map.
8707 */
8708
8709 GList* active_mru_list;
8710 GList* window_position;
8711 GList* after_this_one_position;
8712
8713 active_mru_list = window->screen->active_workspace->mru_list;
8714 window_position = g_list_find (active_mru_list, window);
8715 after_this_one_position = g_list_find (active_mru_list, after_this_one);
8716
8717 /* after_this_one_position is NULL when we switch workspaces, but in
8718 * that case we don't need to do any MRU shuffling so we can simply
8719 * return.
8720 */
8721 if (after_this_one_position == NULL((void*)0))
8722 return;
8723
8724 if (g_list_length (window_position) > g_list_length (after_this_one_position))
8725 {
8726 window->screen->active_workspace->mru_list =
8727 g_list_delete_link (window->screen->active_workspace->mru_list,
8728 window_position);
8729
8730 window->screen->active_workspace->mru_list =
8731 g_list_insert_before (window->screen->active_workspace->mru_list,
8732 after_this_one_position->next,
8733 window);
8734 }
8735}
8736
8737void
8738meta_window_stack_just_below (MetaWindow *window,
8739 MetaWindow *below_this_one)
8740{
8741 g_return_if_fail (window != NULL)do { if ((window != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "window != NULL"); return
; } } while (0)
;
8742 g_return_if_fail (below_this_one != NULL)do { if ((below_this_one != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "below_this_one != NULL"
); return; } } while (0)
;
8743
8744 if (window->stack_position > below_this_one->stack_position)
8745 {
8746 meta_topicmeta_topic_real (META_DEBUG_STACK,
8747 "Setting stack position of window %s to %d (making it below window %s).\n",
8748 window->desc,
8749 below_this_one->stack_position,
8750 below_this_one->desc);
8751 meta_window_set_stack_position (window, below_this_one->stack_position);
8752 }
8753 else
8754 {
8755 meta_topicmeta_topic_real (META_DEBUG_STACK,
8756 "Window %s was already below window %s.\n",
8757 window->desc, below_this_one->desc);
8758 }
8759}
8760
8761void
8762meta_window_set_user_time (MetaWindow *window,
8763 guint32 timestamp)
8764{
8765 /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow
8766 * us to sanity check the timestamp here and ensure it doesn't correspond to
8767 * a future time.
8768 */
8769
8770 /* Only update the time if this timestamp is newer... */
8771 if (window->net_wm_user_time_set &&
8772 XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time)( (timestamp) == 0 || (( (( (timestamp) < (window->net_wm_user_time
) ) && ( (window->net_wm_user_time) - (timestamp) <
((guint32)-1)/2 )) || (( (timestamp) > (window->net_wm_user_time
) ) && ( (timestamp) - (window->net_wm_user_time) >
((guint32)-1)/2 )) ) && (window->net_wm_user_time
) != 0) )
)
8773 {
8774 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
8775 "Window %s _NET_WM_USER_TIME not updated to %u, because it "
8776 "is less than %u\n",
8777 window->desc, timestamp, window->net_wm_user_time);
8778 }
8779 else
8780 {
8781 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
8782 "Window %s has _NET_WM_USER_TIME of %u\n",
8783 window->desc, timestamp);
8784 window->net_wm_user_time_set = TRUE(!(0));
8785 window->net_wm_user_time = timestamp;
8786 if (XSERVER_TIME_IS_BEFORE (window->display->last_user_time, timestamp)( (window->display->last_user_time) == 0 || (( (( (window
->display->last_user_time) < (timestamp) ) &&
( (timestamp) - (window->display->last_user_time) <
((guint32)-1)/2 )) || (( (window->display->last_user_time
) > (timestamp) ) && ( (window->display->last_user_time
) - (timestamp) > ((guint32)-1)/2 )) ) && (timestamp
) != 0) )
)
8787 window->display->last_user_time = timestamp;
8788
8789 /* If this is a terminal, user interaction with it means the user likely
8790 * doesn't want to have focus transferred for now due to new windows.
8791 */
8792 if (meta_prefs_get_focus_new_windows () ==
8793 META_FOCUS_NEW_WINDOWS_STRICT &&
8794 __window_is_terminal (window))
8795 window->display->allow_terminal_deactivation = FALSE(0);
8796 }
8797}
8798
8799/* Sets the demands_attention hint on a window, but only
8800 * if it's at least partially obscured (see #305882).
8801 */
8802void
8803meta_window_set_demands_attention (MetaWindow *window)
8804{
8805 MetaRectangle candidate_rect, other_rect;
8806 GList *stack = window->screen->stack->sorted;
8807 MetaWindow *other_window;
8808 gboolean obscured = FALSE(0);
8809
8810 MetaWorkspace *workspace = window->screen->active_workspace;
8811 if (workspace!=window->workspace)
8812 {
8813 /* windows on other workspaces are necessarily obscured */
8814 obscured = TRUE(!(0));
8815 }
8816 else if (window->minimized)
8817 {
8818 obscured = TRUE(!(0));
8819 }
8820 else
8821 {
8822 meta_window_get_outer_rect (window, &candidate_rect);
8823
8824 /* The stack is sorted with the top windows first. */
8825
8826 while (stack != NULL((void*)0) && stack->data != window)
8827 {
8828 other_window = stack->data;
8829 stack = stack->next;
8830
8831 if (other_window->on_all_workspaces ||
8832 window->on_all_workspaces ||
8833 other_window->workspace == window->workspace)
8834 {
8835 meta_window_get_outer_rect (other_window, &other_rect);
8836
8837 if (meta_rectangle_overlap (&candidate_rect, &other_rect))
8838 {
8839 obscured = TRUE(!(0));
8840 break;
8841 }
8842 }
8843 }
8844 }
8845
8846 if (obscured)
8847 {
8848 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
8849 "Marking %s as needing attention\n",
8850 window->desc);
8851
8852 window->wm_state_demands_attention = TRUE(!(0));
8853 set_net_wm_state (window);
8854 }
8855 else
8856 {
8857 /* If the window's in full view, there's no point setting the flag. */
8858
8859 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
8860 "Not marking %s as needing attention because "
8861 "it's in full view\n",
8862 window->desc);
8863 }
8864}
8865
8866void
8867meta_window_unset_demands_attention (MetaWindow *window)
8868{
8869 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
8870 "Marking %s as not needing attention\n", window->desc);
8871
8872 window->wm_state_demands_attention = FALSE(0);
8873 set_net_wm_state (window);
8874}
8875
8876MetaFrame *
8877meta_window_get_frame (MetaWindow *window)
8878{
8879 return window->frame;
8880}
8881
8882static gboolean
8883transient_has_focus (MetaWindow *window,
8884 void *data)
8885{
8886 if (window->type == META_WINDOW_MODAL_DIALOG && meta_window_appears_focused (window))
8887 *((gboolean *)data) = TRUE(!(0));
8888
8889 return FALSE(0);
8890}
8891
8892gboolean
8893meta_window_appears_focused (MetaWindow *window)
8894{
8895 if (!window->has_focus && meta_prefs_get_attach_modal_dialogs ())
8896 {
8897 gboolean focus = FALSE(0);
8898 meta_window_foreach_transient (window, transient_has_focus, &focus);
8899 return focus;
8900 }
8901
8902 if (window->has_focus)
8903 return TRUE(!(0));
8904
8905 if (window->type == META_WINDOW_DOCK ||
8906 window->type == META_WINDOW_SPLASHSCREEN)
8907 return TRUE(!(0));
8908
8909 return FALSE(0);
8910}
8911
8912gboolean
8913meta_window_has_focus (MetaWindow *window)
8914{
8915 return window->has_focus;
8916}
8917
8918gboolean
8919meta_window_is_shaded (MetaWindow *window)
8920{
8921 return window->shaded;
8922}
8923
8924MetaRectangle *
8925meta_window_get_rect (MetaWindow *window)
8926{
8927 return &window->rect;
8928}
8929
8930MetaScreen *
8931meta_window_get_screen (MetaWindow *window)
8932{
8933 return window->screen;
8934}
8935
8936MetaDisplay *
8937meta_window_get_display (MetaWindow *window)
8938{
8939 return window->display;
8940}
8941
8942Window
8943meta_window_get_xwindow (MetaWindow *window)
8944{
8945 return window->xwindow;
8946}
8947
8948/**
8949 * meta_window_get_transient_for:
8950 * @window: a #MetaWindow
8951 *
8952 * Returns the #MetaWindow for the window that is pointed to by the
8953 * WM_TRANSIENT_FOR hint on this window (see XGetTransientForHint()
8954 * or XSetTransientForHint()). Marco keeps transient windows above their
8955 * parents. A typical usage of this hint is for a dialog that wants to stay
8956 * above its associated window.
8957 *
8958 * Return value: (transfer none): the window this window is transient for, or
8959 * %NULL if the WM_TRANSIENT_FOR hint is unset or does not point to a toplevel
8960 * window that Marco knows about.
8961 */
8962MetaWindow *
8963meta_window_get_transient_for (MetaWindow *window)
8964{
8965 if (window->xtransient_for)
8966 return meta_display_lookup_x_window (window->display, window->xtransient_for);
8967 else
8968 return NULL((void*)0);
8969}
8970
8971gboolean
8972meta_window_is_maximized (MetaWindow *window)
8973{
8974 return META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
;
8975}
8976
8977gboolean
8978meta_window_is_tiled_left (MetaWindow *window)
8979{
8980 return META_WINDOW_TILED_LEFT (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) && (window
)->tile_mode == META_TILE_LEFT)
;
8981}
8982
8983gboolean
8984meta_window_is_tiled_right (MetaWindow *window)
8985{
8986 return META_WINDOW_TILED_RIGHT (window)(((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT)) && (window
)->tile_mode == META_TILE_RIGHT)
;
8987}
8988
8989/**
8990 * meta_window_is_client_decorated:
8991 *
8992 * Check if if the window has decorations drawn by the client.
8993 * (window->decorated refers only to whether we should add decorations)
8994 */
8995gboolean
8996meta_window_is_client_decorated (MetaWindow *window)
8997{
8998 /* Currently the implementation here is hackish -
8999 * has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set
9000 * to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for
9001 * client-side-decorated window, even if the value is 0 because
9002 * the window is maxized and has no invisible borders or shadows.
9003 */
9004 return window->has_custom_frame_extents;
9005}
9006
9007/**
9008 * meta_window_get_frame_bounds:
9009 *
9010 * Gets a region representing the outer bounds of the window's frame.
9011 *
9012 * Return value: (transfer none) (allow-none): a #cairo_region_t
9013 * holding the outer bounds of the window, or %NULL if the window
9014 * doesn't have a frame.
9015 */
9016cairo_region_t *
9017meta_window_get_frame_bounds (MetaWindow *window)
9018{
9019 if (!window->frame_bounds)
9020 {
9021 if (window->frame)
9022 window->frame_bounds = meta_frame_get_frame_bounds (window->frame);
9023 }
9024
9025 return window->frame_bounds;
9026}
9027
9028static void
9029meta_window_finalize (GObject *object)
9030{
9031 MetaWindow *window;
9032
9033 window = META_WINDOW (object);
9034
9035 g_clear_object (&window->icon)do { _Static_assert (sizeof *((&window->icon)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&window->icon))) _pp = ((&window->icon)); __typeof__
(*((&window->icon))) _ptr = *_pp; *_pp = ((void*)0); if
(_ptr) (g_object_unref) (_ptr); } while (0)
;
9036 g_clear_object (&window->mini_icon)do { _Static_assert (sizeof *((&window->mini_icon)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&window->mini_icon))) _pp = ((&window->mini_icon
)); __typeof__ (*((&window->mini_icon))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
9037
9038 g_clear_pointer (&window->frame_bounds, cairo_region_destroy)do { _Static_assert (sizeof *(&window->frame_bounds) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&window->frame_bounds)) _pp = (&window->frame_bounds
); __typeof__ (*(&window->frame_bounds)) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (cairo_region_destroy) (_ptr); } while
(0)
;
9039
9040 meta_icon_cache_free (&window->icon_cache);
9041
9042 g_clear_pointer (&window->sm_client_id, g_free)do { _Static_assert (sizeof *(&window->sm_client_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&window->sm_client_id)) _pp = (&window->sm_client_id
); __typeof__ (*(&window->sm_client_id)) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (0)
;
9043 g_clear_pointer (&window->wm_client_machine, g_free)do { _Static_assert (sizeof *(&window->wm_client_machine
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&window->wm_client_machine)) _pp = (&window->
wm_client_machine); __typeof__ (*(&window->wm_client_machine
)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr);
} while (0)
;
9044 g_clear_pointer (&window->startup_id, g_free)do { _Static_assert (sizeof *(&window->startup_id) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->startup_id)) _pp = (&window->startup_id); __typeof__
(*(&window->startup_id)) _ptr = *_pp; *_pp = ((void*)
0); if (_ptr) (g_free) (_ptr); } while (0)
;
9045 g_clear_pointer (&window->role, g_free)do { _Static_assert (sizeof *(&window->role) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->role)) _pp = (&window->role); __typeof__ (*
(&window->role)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr
) (g_free) (_ptr); } while (0)
;
9046 g_clear_pointer (&window->res_class, g_free)do { _Static_assert (sizeof *(&window->res_class) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->res_class)) _pp = (&window->res_class); __typeof__
(*(&window->res_class)) _ptr = *_pp; *_pp = ((void*)0
); if (_ptr) (g_free) (_ptr); } while (0)
;
9047 g_clear_pointer (&window->res_name, g_free)do { _Static_assert (sizeof *(&window->res_name) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->res_name)) _pp = (&window->res_name); __typeof__
(*(&window->res_name)) _ptr = *_pp; *_pp = ((void*)0)
; if (_ptr) (g_free) (_ptr); } while (0)
;
9048 g_clear_pointer (&window->title, g_free)do { _Static_assert (sizeof *(&window->title) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->title)) _pp = (&window->title); __typeof__ (
*(&window->title)) _ptr = *_pp; *_pp = ((void*)0); if (
_ptr) (g_free) (_ptr); } while (0)
;
9049 g_clear_pointer (&window->icon_name, g_free)do { _Static_assert (sizeof *(&window->icon_name) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->icon_name)) _pp = (&window->icon_name); __typeof__
(*(&window->icon_name)) _ptr = *_pp; *_pp = ((void*)0
); if (_ptr) (g_free) (_ptr); } while (0)
;
9050 g_clear_pointer (&window->desc, g_free)do { _Static_assert (sizeof *(&window->desc) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ ((&
window->desc)) _pp = (&window->desc); __typeof__ (*
(&window->desc)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr
) (g_free) (_ptr); } while (0)
;
9051 g_clear_pointer (&window->gtk_theme_variant, g_free)do { _Static_assert (sizeof *(&window->gtk_theme_variant
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&window->gtk_theme_variant)) _pp = (&window->
gtk_theme_variant); __typeof__ (*(&window->gtk_theme_variant
)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr);
} while (0)
;
9052 g_clear_pointer (&window->gtk_application_id, g_free)do { _Static_assert (sizeof *(&window->gtk_application_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&window->gtk_application_id)) _pp = (&window->
gtk_application_id); __typeof__ (*(&window->gtk_application_id
)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr);
} while (0)
;
9053 g_clear_pointer (&window->bamf_desktop_file, g_free)do { _Static_assert (sizeof *(&window->bamf_desktop_file
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&window->bamf_desktop_file)) _pp = (&window->
bamf_desktop_file); __typeof__ (*(&window->bamf_desktop_file
)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free) (_ptr);
} while (0)
;
9054
9055 G_OBJECT_CLASS (meta_window_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_window_parent_class)), (((GType) ((20) << (2)
)))))))
->finalize (object);
9056}
9057
9058static void
9059meta_window_class_init (MetaWindowClass *window_class)
9060{
9061 GObjectClass *object_class;
9062
9063 object_class = G_OBJECT_CLASS (window_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((window_class)), (((GType) ((20) << (2))))))))
;
9064
9065 object_class->finalize = meta_window_finalize;
9066}
9067
9068static void
9069meta_window_init (MetaWindow *window)
9070{
9071}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e47d9e.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e47d9e.html new file mode 100644 index 00000000..13b48a76 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e47d9e.html @@ -0,0 +1,3192 @@ + + + +core/prefs.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/prefs.c
Warning:line 1313, column 30
The right operand of '!=' is a garbage value
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name prefs.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/prefs.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco preferences */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7 * Copyright (C) 2006 Elijah Newren
8 * Copyright (C) 2008 Thomas Thurman
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26#include <config.h>
27#include <glib/gi18n-lib.h>
28
29#include "prefs.h"
30#include "ui.h"
31#include "util.h"
32#include <gdk/gdk.h>
33#include <gio/gio.h>
34#include <string.h>
35#include <stdlib.h>
36
37#define MAX_REASONABLE_WORKSPACES36 36
38
39#define MAX_COMMANDS(32 + 2) (32 + NUM_EXTRA_COMMANDS2)
40#define NUM_EXTRA_COMMANDS2 2
41#define SCREENSHOT_COMMAND_IDX((32 + 2) - 2) (MAX_COMMANDS(32 + 2) - 2)
42#define WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1) (MAX_COMMANDS(32 + 2) - 1)
43
44/* If you add a key, it needs updating in init() and in the GSettings
45 * notify listener and of course in the .gschema file.
46 *
47 * Keys which are handled by one of the unified handlers below are
48 * not given a name here, because the purpose of the unified handlers
49 * is that keys should be referred to exactly once.
50 */
51#define KEY_GENERAL_SCHEMA"org.mate.Marco.general" "org.mate.Marco.general"
52#define KEY_GENERAL_TITLEBAR_FONT"titlebar-font" "titlebar-font"
53#define KEY_GENERAL_NUM_WORKSPACES"num-workspaces" "num-workspaces"
54#define KEY_GENERAL_COMPOSITOR"compositing-manager" "compositing-manager"
55#define KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB"compositing-fast-alt-tab" "compositing-fast-alt-tab"
56#define KEY_GENERAL_CENTER_NEW_WINDOWS"center-new-windows" "center-new-windows"
57#define KEY_GENERAL_ICON_SIZE"icon-size" "icon-size"
58#define KEY_GENERAL_ALT_TAB_MAX_COLUMNS"alt-tab-max-columns" "alt-tab-max-columns"
59#define KEY_GENERAL_ALT_TAB_RAISE_WINDOWS"alt-tab-raise-windows" "alt-tab-raise-windows"
60#define KEY_GENERAL_ALT_TAB_EXPAND_TO_FIT_TITLE"alt-tab-expand-to-fit-title" "alt-tab-expand-to-fit-title"
61
62#define KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands" "org.mate.Marco.keybinding-commands"
63#define KEY_COMMAND_PREFIX"command-" "command-"
64
65#define KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings" "org.mate.Marco.global-keybindings"
66
67#define KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings" "org.mate.Marco.window-keybindings"
68
69#define KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names" "org.mate.Marco.workspace-names"
70#define KEY_WORKSPACE_NAME_PREFIX"name-" "name-"
71
72#define KEY_MATE_INTERFACE_SCHEMA"org.mate.interface" "org.mate.interface"
73#define KEY_MATE_INTERFACE_ACCESSIBILITY"accessibility" "accessibility"
74#define KEY_MATE_INTERFACE_ENABLE_ANIMATIONS"enable-animations" "enable-animations"
75
76#define KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal" "org.mate.applications-terminal"
77#define KEY_MATE_TERMINAL_COMMAND"exec" "exec"
78
79#define KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse" "org.mate.peripherals-mouse"
80#define KEY_MATE_MOUSE_CURSOR_THEME"cursor-theme" "cursor-theme"
81#define KEY_MATE_MOUSE_CURSOR_SIZE"cursor-size" "cursor-size"
82
83#define SETTINGS(s)g_hash_table_lookup (settings_schemas, (s)) g_hash_table_lookup (settings_schemas, (s))
84
85static GSettings *settings_general;
86static GSettings *settings_command;
87static GSettings *settings_screen_bindings;
88static GSettings *settings_window_bindings;
89static GSettings *settings_workspace_names;
90static GSettings *settings_mate_interface;
91static GSettings *settings_mate_terminal;
92static GSettings *settings_mate_mouse;
93static GHashTable *settings_schemas;
94
95static GList *changes = NULL((void*)0);
96static guint changed_idle;
97static GList *listeners = NULL((void*)0);
98
99static gboolean use_system_font = FALSE(0);
100static PangoFontDescription *titlebar_font = NULL((void*)0);
101static MetaVirtualModifier mouse_button_mods = Mod1Mask(1<<3);
102static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
103static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
104static gboolean raise_on_click = TRUE(!(0));
105static gboolean attach_modal_dialogs = FALSE(0);
106static char* current_theme = NULL((void*)0);
107static int num_workspaces = 4;
108static MetaWrapStyle wrap_style = META_WRAP_NONE;
109static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
110static MetaActionTitlebar action_middle_click_titlebar = META_ACTION_TITLEBAR_LOWER;
111static MetaActionTitlebar action_right_click_titlebar = META_ACTION_TITLEBAR_MENU;
112static gboolean application_based = FALSE(0);
113static gboolean disable_workarounds = FALSE(0);
114static gboolean auto_raise = FALSE(0);
115static gboolean auto_raise_delay = 500;
116static gboolean provide_visual_bell = FALSE(0);
117static gboolean bell_is_audible = TRUE(!(0));
118static gboolean reduced_resources = FALSE(0);
119static gboolean mate_accessibility = FALSE(0);
120static gboolean mate_animations = TRUE(!(0));
121static char *cursor_theme = NULL((void*)0);
122static int cursor_size = 24;
123static int icon_size = META_DEFAULT_ICON_SIZE48;
124static int alt_tab_max_columns = META_DEFAULT_ALT_TAB_MAX_COLUMNS5;
125static gboolean alt_tab_raise_windows = META_DEFAULT_ALT_TAB_RAISE_WINDOWS(0);
126static gboolean alt_tab_expand_to_fit_title = META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE(0);
127static gboolean use_force_compositor_manager = FALSE(0);
128static gboolean force_compositor_manager = FALSE(0);
129static gboolean compositing_manager = FALSE(0);
130static gboolean compositing_fast_alt_tab = FALSE(0);
131static gboolean resize_with_right_button = FALSE(0);
132static gboolean show_tab_border = FALSE(0);
133static gboolean center_new_windows = FALSE(0);
134static gboolean force_fullscreen = TRUE(!(0));
135static gboolean allow_tiling = FALSE(0);
136static gboolean allow_top_tiling = TRUE(!(0));
137static gboolean allow_tile_cycling = TRUE(!(0));
138static GList *show_desktop_skip_list = NULL((void*)0);
139
140static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
141static MetaButtonLayout button_layout;
142
143/* The screenshot commands are at the end */
144static char *commands[MAX_COMMANDS(32 + 2)] = { NULL((void*)0), };
145
146static char *terminal_command = NULL((void*)0);
147
148static char *workspace_names[MAX_REASONABLE_WORKSPACES36] = { NULL((void*)0), };
149
150static gboolean handle_preference_update_enum (const gchar *key, GSettings *settings);
151
152static gboolean update_key_binding (const char *name,
153 gchar *value);
154static gboolean update_command (const char *name,
155 const char *value);
156static gboolean update_workspace_name (const char *name,
157 const char *value);
158
159static void change_notify (GSettings *settings,
160 gchar *key,
161 gpointer user_data);
162
163static char* settings_key_for_workspace_name (int i);
164
165static void queue_changed (MetaPreference pref);
166
167#if 0
168static void cleanup_error (GError **error);
169#endif
170
171static void maybe_give_disable_workarounds_warning (void);
172
173static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
174static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
175static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
176static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
177static void show_desktop_skip_list_handler (MetaPreference, const gchar*, gboolean*);
178
179static gboolean update_binding (MetaKeyPref *binding,
180 gchar *value);
181
182static void init_bindings (GSettings *);
183static void init_screen_bindings (void);
184static void init_window_bindings (void);
185static void init_commands (void);
186static void init_workspace_names (void);
187
188static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_AUTOMATIC;
189
190typedef struct
191{
192 MetaPrefsChangedFunc func;
193 gpointer data;
194} MetaPrefsListener;
195
196/**
197 * The details of one preference which is constrained to be
198 * one of a small number of string values-- in other words,
199 * an enumeration.
200 *
201 * We could have done this other ways. One particularly attractive
202 * possibility would have been to represent the entire symbol table
203 * as a space-separated string literal in the list of symtabs, so
204 * the focus mode enums could have been represented simply by
205 * "click sloppy mouse". However, the simplicity gained would have
206 * been outweighed by the bugs caused when the ordering of the enum
207 * strings got out of sync with the actual enum statement. Also,
208 * there is existing library code to use this kind of symbol tables.
209 *
210 * Other things we might consider doing to clean this up in the
211 * future include:
212 *
213 * - most of the keys begin with the same prefix, and perhaps we
214 * could assume it if they don't start with a slash
215 *
216 * - there are several cases where a single identifier could be used
217 * to generate an entire entry, and perhaps this could be done
218 * with a macro. (This would reduce clarity, however, and is
219 * probably a bad thing.)
220 *
221 * - these types all begin with a gchar* (and contain a MetaPreference)
222 * and we can factor out the repeated code in the handlers by taking
223 * advantage of this using some kind of union arrangement.
224 */
225typedef struct
226{
227 gchar *key;
228 gchar *schema;
229 MetaPreference pref;
230 gint *target;
231} MetaEnumPreference;
232
233typedef struct
234{
235 gchar *key;
236 gchar *schema;
237 MetaPreference pref;
238 gboolean *target;
239 gboolean becomes_true_on_destruction;
240} MetaBoolPreference;
241
242typedef struct
243{
244 gchar *key;
245 gchar *schema;
246 MetaPreference pref;
247
248 /**
249 * A handler. Many of the string preferences aren't stored as
250 * strings and need parsing; others of them have default values
251 * which can't be solved in the general case. If you include a
252 * function pointer here, it will be called before the string
253 * value is written out to the target variable.
254 *
255 * The function is passed two arguments: the preference, and
256 * the new string as a gchar*. It returns a gboolean;
257 * only if this is true, the listeners will be informed that
258 * the preference has changed.
259 *
260 * This may be NULL. If it is, see "target", below.
261 */
262 void (*handler) (MetaPreference pref,
263 const gchar *string_value,
264 gboolean *inform_listeners);
265
266 /**
267 * Where to write the incoming string.
268 *
269 * This must be NULL if the handler is non-NULL.
270 * If the incoming string is NULL, no change will be made.
271 */
272 gchar **target;
273
274} MetaStringPreference;
275
276#define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY(-2147483647 -1) G_MININT(-2147483647 -1)
277
278typedef struct
279{
280 gchar *key;
281 gchar *schema;
282 MetaPreference pref;
283 gint *target;
284 /**
285 * Minimum and maximum values of the integer.
286 * If the new value is out of bounds, it will be discarded with a warning.
287 */
288 gint minimum, maximum;
289 /**
290 * Value to use if the key is destroyed.
291 * If this is METAINTPREFERENCE_NO_CHANGE_ON_DESTROY, it will
292 * not be changed when the key is destroyed.
293 */
294 gint value_if_destroyed;
295} MetaIntPreference;
296
297/* FIXMEs: */
298/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
299/* @@@ /apps/marco/general should be assumed if first char is not / */
300/* @@@ Will it ever be possible to merge init and update? If not, why not? */
301
302static MetaEnumPreference preferences_enum[] =
303 {
304 { "focus-new-windows",
305 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
306 META_PREF_FOCUS_NEW_WINDOWS,
307 (gint *) &focus_new_windows,
308 },
309 { "focus-mode",
310 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
311 META_PREF_FOCUS_MODE,
312 (gint *) &focus_mode,
313 },
314 { "wrap-style",
315 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
316 META_PREF_WRAP_STYLE,
317 (gint *) &wrap_style,
318 },
319 { "visual-bell-type",
320 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
321 META_PREF_VISUAL_BELL_TYPE,
322 (gint *) &visual_bell_type,
323 },
324 { "action-double-click-titlebar",
325 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
326 META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
327 (gint *) &action_double_click_titlebar,
328 },
329 { "action-middle-click-titlebar",
330 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
331 META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
332 (gint *) &action_middle_click_titlebar,
333 },
334 { "action-right-click-titlebar",
335 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
336 META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
337 (gint *) &action_right_click_titlebar,
338 },
339 { "placement-mode",
340 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
341 META_PREF_PLACEMENT_MODE,
342 (gint *) &placement_mode,
343 },
344 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0) },
345 };
346
347static MetaBoolPreference preferences_bool[] =
348 {
349 { "raise-on-click",
350 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
351 META_PREF_RAISE_ON_CLICK,
352 &raise_on_click,
353 TRUE(!(0)),
354 },
355 { "titlebar-uses-system-font",
356 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
357 META_PREF_TITLEBAR_FONT, /* note! shares a pref */
358 &use_system_font,
359 TRUE(!(0)),
360 },
361 { "application-based",
362 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
363 META_PREF_APPLICATION_BASED,
364 NULL((void*)0), /* feature is known but disabled */
365 FALSE(0),
366 },
367 { "disable-workarounds",
368 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
369 META_PREF_DISABLE_WORKAROUNDS,
370 &disable_workarounds,
371 FALSE(0),
372 },
373 { "auto-raise",
374 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
375 META_PREF_AUTO_RAISE,
376 &auto_raise,
377 FALSE(0),
378 },
379 { "visual-bell",
380 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
381 META_PREF_VISUAL_BELL,
382 &provide_visual_bell, /* FIXME: change the name: it's confusing */
383 FALSE(0),
384 },
385 { "audible-bell",
386 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
387 META_PREF_AUDIBLE_BELL,
388 &bell_is_audible, /* FIXME: change the name: it's confusing */
389 FALSE(0),
390 },
391 { "reduced-resources",
392 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
393 META_PREF_REDUCED_RESOURCES,
394 &reduced_resources,
395 FALSE(0),
396 },
397 { "accessibility",
398 KEY_MATE_INTERFACE_SCHEMA"org.mate.interface",
399 META_PREF_MATE_ACCESSIBILITY,
400 &mate_accessibility,
401 FALSE(0),
402 },
403 { "enable-animations",
404 KEY_MATE_INTERFACE_SCHEMA"org.mate.interface",
405 META_PREF_MATE_ANIMATIONS,
406 &mate_animations,
407 TRUE(!(0)),
408 },
409 { KEY_GENERAL_COMPOSITOR"compositing-manager",
410 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
411 META_PREF_COMPOSITING_MANAGER,
412 &compositing_manager,
413 FALSE(0),
414 },
415 { "compositing-fast-alt-tab",
416 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
417 META_PREF_COMPOSITING_FAST_ALT_TAB,
418 &compositing_fast_alt_tab,
419 FALSE(0),
420 },
421 { "resize-with-right-button",
422 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
423 META_PREF_RESIZE_WITH_RIGHT_BUTTON,
424 &resize_with_right_button,
425 FALSE(0),
426 },
427 { "show-tab-border",
428 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
429 META_PREF_SHOW_TAB_BORDER,
430 &show_tab_border,
431 FALSE(0),
432 },
433 { "center-new-windows",
434 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
435 META_PREF_CENTER_NEW_WINDOWS,
436 &center_new_windows,
437 FALSE(0),
438 },
439 { "allow-tiling",
440 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
441 META_PREF_ALLOW_TILING,
442 &allow_tiling,
443 FALSE(0),
444 },
445 { "allow-top-tiling",
446 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
447 META_PREF_ALLOW_TOP_TILING,
448 &allow_top_tiling,
449 FALSE(0),
450 },
451 { "allow-tile-cycling",
452 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
453 META_PREF_ALLOW_TILE_CYCLING,
454 &allow_tile_cycling,
455 FALSE(0),
456 },
457 { "alt-tab-expand-to-fit-title",
458 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
459 META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE,
460 &alt_tab_expand_to_fit_title,
461 META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE(0),
462 },
463 { "alt-tab-raise-windows",
464 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
465 META_PREF_ALT_TAB_RAISE_WINDOWS,
466 &alt_tab_raise_windows,
467 META_DEFAULT_ALT_TAB_RAISE_WINDOWS(0),
468 },
469 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), FALSE(0) },
470 };
471
472static MetaStringPreference preferences_string[] =
473 {
474 { "mouse-button-modifier",
475 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
476 META_PREF_MOUSE_BUTTON_MODS,
477 mouse_button_mods_handler,
478 NULL((void*)0),
479 },
480 { "theme",
481 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
482 META_PREF_THEME,
483 theme_name_handler,
484 NULL((void*)0),
485 },
486 { KEY_GENERAL_TITLEBAR_FONT"titlebar-font",
487 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
488 META_PREF_TITLEBAR_FONT,
489 titlebar_handler,
490 NULL((void*)0),
491 },
492 { KEY_MATE_TERMINAL_COMMAND"exec",
493 KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal",
494 META_PREF_TERMINAL_COMMAND,
495 NULL((void*)0),
496 &terminal_command,
497 },
498 { "button-layout",
499 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
500 META_PREF_BUTTON_LAYOUT,
501 button_layout_handler,
502 NULL((void*)0),
503 },
504 { "cursor-theme",
505 KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse",
506 META_PREF_CURSOR_THEME,
507 NULL((void*)0),
508 &cursor_theme,
509 },
510 { "show-desktop-skip-list",
511 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
512 META_PREF_SHOW_DESKTOP_SKIP_LIST,
513 &show_desktop_skip_list_handler,
514 NULL((void*)0),
515 },
516 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), NULL((void*)0) },
517 };
518
519static MetaIntPreference preferences_int[] =
520 {
521 { "num-workspaces",
522 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
523 META_PREF_NUM_WORKSPACES,
524 &num_workspaces,
525 /* I would actually recommend we change the destroy value to 4
526 * and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
527 * -- tthurman
528 */
529 1, MAX_REASONABLE_WORKSPACES36, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY(-2147483647 -1),
530 },
531 { "auto-raise-delay",
532 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
533 META_PREF_AUTO_RAISE_DELAY,
534 &auto_raise_delay,
535 0, 10000, 0,
536 /* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
537 },
538 { "cursor-size",
539 KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse",
540 META_PREF_CURSOR_SIZE,
541 &cursor_size,
542 1, 128, 24,
543 },
544 { "icon-size",
545 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
546 META_PREF_ICON_SIZE,
547 &icon_size,
548 META_MIN_ICON_SIZE8, META_MAX_ICON_SIZE256, META_DEFAULT_ICON_SIZE48,
549 },
550 { "alt-tab-max-columns",
551 KEY_GENERAL_SCHEMA"org.mate.Marco.general",
552 META_PREF_ALT_TAB_MAX_COLUMNS,
553 &alt_tab_max_columns,
554 META_MIN_ALT_TAB_MAX_COLUMNS1,
555 META_MAX_ALT_TAB_MAX_COLUMNS64,
556 META_DEFAULT_ALT_TAB_MAX_COLUMNS5,
557 },
558 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), 0, 0, 0, },
559 };
560
561static void
562handle_preference_init_enum (void)
563{
564 MetaEnumPreference *cursor = preferences_enum;
565
566 while (cursor->key!=NULL((void*)0))
567 {
568 gint value;
569
570 if (cursor->target==NULL((void*)0))
571 {
572 ++cursor;
573 continue;
574 }
575
576 value = g_settings_get_enum (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
577 cursor->key);
578 *cursor->target = value;
579
580 ++cursor;
581 }
582}
583
584static void
585handle_preference_init_bool (void)
586{
587 MetaBoolPreference *cursor = preferences_bool;
588
589 while (cursor->key!=NULL((void*)0))
590 {
591 if (cursor->target!=NULL((void*)0))
592 *cursor->target = g_settings_get_boolean (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)), cursor->key);
593
594 ++cursor;
595 }
596
597 maybe_give_disable_workarounds_warning ();
598}
599
600static void
601handle_preference_init_string (void)
602{
603 MetaStringPreference *cursor = preferences_string;
604
605 while (cursor->key!=NULL((void*)0))
606 {
607 gchar *value;
608 gboolean dummy = TRUE(!(0));
609
610 /* the string "value" will be newly allocated */
611 value = g_settings_get_string (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
612 cursor->key);
613
614 if (cursor->handler)
615 {
616 if (cursor->target)
617 meta_bug ("%s has both a target and a handler\n", cursor->key);
618
619 cursor->handler (cursor->pref, value, &dummy);
620
621 g_free (value);
622 }
623 else if (cursor->target)
624 {
625 if (*(cursor->target))
626 g_free (*(cursor->target));
627
628 *(cursor->target) = value;
629 }
630
631 ++cursor;
632 }
633}
634
635static void
636handle_preference_init_int (void)
637{
638 MetaIntPreference *cursor = preferences_int;
639
640 while (cursor->key!=NULL((void*)0))
641 {
642 gint value;
643
644 value = g_settings_get_int (SETTINGS (cursor->schema)g_hash_table_lookup (settings_schemas, (cursor->schema)),
645 cursor->key);
646
647 if (value < cursor->minimum || value > cursor->maximum)
648 {
649 /* FIXME: check if this can be avoided by GSettings */
650 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n")((char *) g_dgettext ("marco", "%d stored in GSettings key %s is out of range %d to %d\n"
))
,
651 value, cursor->key, cursor->minimum, cursor->maximum);
652 /* Former behaviour for out-of-range values was:
653 * - number of workspaces was clamped;
654 * - auto raise delay was always reset to zero even if too high!;
655 * - cursor size was ignored.
656 *
657 * These seem to be meaningless variations. If they did
658 * have meaning we could have put them into MetaIntPreference.
659 * The last of these is the closest to how we behave for
660 * other types, so I think we should standardise on that.
661 */
662 }
663 else if (cursor->target)
664 *cursor->target = value;
665
666 ++cursor;
667 }
668}
669
670static gboolean
671handle_preference_update_enum (const gchar *key, GSettings *settings)
672{
673 MetaEnumPreference *cursor = preferences_enum;
674 gint old_value;
675
676 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
677 ++cursor;
678
679 if (cursor->key==NULL((void*)0))
680 /* Didn't recognise that key. */
681 return FALSE(0);
682
683 /* We need to know whether the value changes, so
684 * store the current value away.
685 */
686
687 old_value = * ((gint *) cursor->target);
688
689 /* Now look it up... */
690 *cursor->target = g_settings_get_enum (settings, key);
691
692 /* Did it change? If so, tell the listeners about it. */
693
694 if (old_value != *((gint *) cursor->target))
695 queue_changed (cursor->pref);
696
697 return TRUE(!(0));
698}
699
700static gboolean
701handle_preference_update_bool (const gchar *key, GSettings *settings)
702{
703 MetaBoolPreference *cursor = preferences_bool;
704 gboolean old_value;
705
706 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
707 ++cursor;
708
709 if (cursor->key==NULL((void*)0))
710 /* Didn't recognise that key. */
711 return FALSE(0);
712
713 if (cursor->target==NULL((void*)0))
714 /* No work for us to do. */
715 return TRUE(!(0));
716
717 /* We need to know whether the value changes, so
718 * store the current value away.
719 */
720
721 old_value = * ((gboolean *) cursor->target);
722
723 /* Now look it up... */
724
725 *((gboolean *) cursor->target) = g_settings_get_boolean (settings, key);
726
727 /* Did it change? If so, tell the listeners about it. */
728
729 if (old_value != *((gboolean *) cursor->target))
730 queue_changed (cursor->pref);
731
732 if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
733 maybe_give_disable_workarounds_warning ();
734
735 return TRUE(!(0));
736}
737
738static gboolean
739handle_preference_update_string (const gchar *key, GSettings *settings)
740{
741 MetaStringPreference *cursor = preferences_string;
742 gchar *value;
743 gboolean inform_listeners = TRUE(!(0));
744
745 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
746 ++cursor;
747
748 if (cursor->key==NULL((void*)0))
749 /* Didn't recognise that key. */
750 return FALSE(0);
751
752 value = g_settings_get_string (settings, key);
753
754 if (cursor->handler)
755 cursor->handler (cursor->pref, value, &inform_listeners);
756 else if (cursor->target)
757 {
758 if (*(cursor->target))
759 g_free(*(cursor->target));
760
761 if (value!=NULL((void*)0))
762 *(cursor->target) = g_strdup (value)g_strdup_inline (value);
763 else
764 *(cursor->target) = NULL((void*)0);
765
766 inform_listeners =
767 (value==NULL((void*)0) && *(cursor->target)==NULL((void*)0)) ||
768 (value!=NULL((void*)0) && *(cursor->target)!=NULL((void*)0) &&
769 strcmp (value, *(cursor->target))==0);
770 }
771
772 if (inform_listeners)
773 queue_changed (cursor->pref);
774
775 g_free (value);
776
777 return TRUE(!(0));
778}
779
780static gboolean
781handle_preference_update_int (const gchar *key, GSettings *settings)
782{
783 MetaIntPreference *cursor = preferences_int;
784 gint value;
785
786 while (cursor->key!=NULL((void*)0) && strcmp (key, cursor->key)!=0)
787 ++cursor;
788
789 if (cursor->key==NULL((void*)0))
790 /* Didn't recognise that key. */
791 return FALSE(0);
792
793 if (cursor->target==NULL((void*)0))
794 /* No work for us to do. */
795 return TRUE(!(0));
796
797 value = g_settings_get_int (settings, key);
798
799 if (value < cursor->minimum || value > cursor->maximum)
800 {
801 /* FIXME! GSettings, instead of MateConf, has Minimum/Maximun in schema!
802 * But some preferences depends on costants for minimum/maximum values */
803 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n")((char *) g_dgettext ("marco", "%d stored in GSettings key %s is out of range %d to %d\n"
))
,
804 value, cursor->key,
805 cursor->minimum, cursor->maximum);
806 return TRUE(!(0));
807 }
808
809 /* Did it change? If so, tell the listeners about it. */
810
811 if (*cursor->target != value)
812 {
813 *cursor->target = value;
814 queue_changed (cursor->pref);
815 }
816
817 return TRUE(!(0));
818
819}
820
821/****************************************************************************/
822/* Listeners. */
823/****************************************************************************/
824
825void
826meta_prefs_add_listener (MetaPrefsChangedFunc func,
827 gpointer data)
828{
829 MetaPrefsListener *l;
830
831 l = g_new (MetaPrefsListener, 1)((MetaPrefsListener *) g_malloc_n ((1), sizeof (MetaPrefsListener
)))
;
832 l->func = func;
833 l->data = data;
834
835 listeners = g_list_prepend (listeners, l);
836}
837
838void
839meta_prefs_remove_listener (MetaPrefsChangedFunc func,
840 gpointer data)
841{
842 GList *tmp;
843
844 tmp = listeners;
845 while (tmp != NULL((void*)0))
846 {
847 MetaPrefsListener *l = tmp->data;
848
849 if (l->func == func &&
850 l->data == data)
851 {
852 g_free (l);
853 listeners = g_list_delete_link (listeners, tmp);
854
855 return;
856 }
857
858 tmp = tmp->next;
859 }
860
861 meta_bug ("Did not find listener to remove\n");
862}
863
864static void
865emit_changed (MetaPreference pref)
866{
867 GList *tmp;
868 GList *copy;
869
870 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
871 meta_preference_to_string (pref));
872
873 copy = g_list_copy (listeners);
874
875 tmp = copy;
876
877 while (tmp != NULL((void*)0))
878 {
879 MetaPrefsListener *l = tmp->data;
880
881 (* l->func) (pref, l->data);
882
883 tmp = tmp->next;
884 }
885
886 g_list_free (copy);
887}
888
889static gboolean
890changed_idle_handler (gpointer data)
891{
892 GList *tmp;
893 GList *copy;
894
895 changed_idle = 0;
896
897 copy = g_list_copy (changes); /* reentrancy paranoia */
898
899 g_list_free (changes);
900 changes = NULL((void*)0);
901
902 tmp = copy;
903 while (tmp != NULL((void*)0))
904 {
905 MetaPreference pref = GPOINTER_TO_INT (tmp->data)((gint) (glong) (tmp->data));
906
907 emit_changed (pref);
908
909 tmp = tmp->next;
910 }
911
912 g_list_free (copy);
913
914 return FALSE(0);
915}
916
917static void
918queue_changed (MetaPreference pref)
919{
920 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Queueing change of pref %s\n",
921 meta_preference_to_string (pref));
922
923 if (g_list_find (changes, GINT_TO_POINTER (pref)((gpointer) (glong) (pref))) == NULL((void*)0))
924 changes = g_list_prepend (changes, GINT_TO_POINTER (pref)((gpointer) (glong) (pref)));
925 else
926 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
927 meta_preference_to_string (pref));
928
929 /* add idle at priority below the GSettings notify idle */
930 /* FIXME is this needed for GSettings too? */
931 if (changed_idle == 0)
932 changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY(200 + 10),
933 changed_idle_handler, NULL((void*)0), NULL((void*)0));
934}
935
936/****************************************************************************/
937/* Initialisation. */
938/****************************************************************************/
939
940void
941meta_prefs_init (void)
942{
943 if (settings_general != NULL((void*)0))
944 return;
945
946 /* returns references which we hold forever */
947 settings_general = g_settings_new (KEY_GENERAL_SCHEMA"org.mate.Marco.general");
948 settings_command = g_settings_new (KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands");
949 settings_screen_bindings = g_settings_new (KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings");
950 settings_window_bindings = g_settings_new (KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings");
951 settings_workspace_names = g_settings_new (KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names");
952 settings_mate_interface = g_settings_new (KEY_MATE_INTERFACE_SCHEMA"org.mate.interface");
953 settings_mate_terminal = g_settings_new (KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal");
954 settings_mate_mouse = g_settings_new (KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse");
955
956 settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal, NULL((void*)0), g_object_unref);
957 g_hash_table_insert (settings_schemas, KEY_GENERAL_SCHEMA"org.mate.Marco.general", settings_general);
958 g_hash_table_insert (settings_schemas, KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands", settings_command);
959 g_hash_table_insert (settings_schemas, KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings", settings_screen_bindings);
960 g_hash_table_insert (settings_schemas, KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings", settings_window_bindings);
961 g_hash_table_insert (settings_schemas, KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names", settings_workspace_names);
962 g_hash_table_insert (settings_schemas, KEY_MATE_INTERFACE_SCHEMA"org.mate.interface", settings_mate_interface);
963 g_hash_table_insert (settings_schemas, KEY_MATE_TERMINAL_SCHEMA"org.mate.applications-terminal", settings_mate_terminal);
964 g_hash_table_insert (settings_schemas, KEY_MATE_MOUSE_SCHEMA"org.mate.peripherals-mouse", settings_mate_mouse);
965
966 g_signal_connect (settings_general, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_general), ("changed"), (((GCallback
) (change_notify))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
967 g_signal_connect (settings_command, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_command), ("changed"), (((GCallback
) (change_notify))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
968 g_signal_connect (settings_screen_bindings, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_screen_bindings), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
969 g_signal_connect (settings_window_bindings, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_window_bindings), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
970 g_signal_connect (settings_workspace_names, "changed", G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_workspace_names), ("changed"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
971
972 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ACCESSIBILITY, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_interface), ("changed::"
"accessibility"), (((GCallback) (change_notify))), (((void*)
0)), ((void*)0), (GConnectFlags) 0)
;
973 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ENABLE_ANIMATIONS, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_interface), ("changed::"
"enable-animations"), (((GCallback) (change_notify))), (((void
*)0)), ((void*)0), (GConnectFlags) 0)
;
974 g_signal_connect (settings_mate_terminal, "changed::" KEY_MATE_TERMINAL_COMMAND, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_terminal), ("changed::"
"exec"), (((GCallback) (change_notify))), (((void*)0)), ((void
*)0), (GConnectFlags) 0)
;
975 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_THEME, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_mouse), ("changed::" "cursor-theme"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
976 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_SIZE, G_CALLBACK (change_notify), NULL)g_signal_connect_data ((settings_mate_mouse), ("changed::" "cursor-size"
), (((GCallback) (change_notify))), (((void*)0)), ((void*)0),
(GConnectFlags) 0)
;
977
978 /* Pick up initial values. */
979
980 handle_preference_init_enum ();
981 handle_preference_init_bool ();
982 handle_preference_init_string ();
983 handle_preference_init_int ();
984
985 init_screen_bindings ();
986 init_window_bindings ();
987 init_commands ();
988 init_workspace_names ();
989}
990
991/****************************************************************************/
992/* Updates. */
993/****************************************************************************/
994
995gboolean (*preference_update_handler[]) (const gchar*, GSettings*) = {
996 handle_preference_update_enum,
997 handle_preference_update_bool,
998 handle_preference_update_string,
999 handle_preference_update_int,
1000 NULL((void*)0)
1001};
1002
1003static void
1004change_notify (GSettings *settings,
1005 gchar *key,
1006 gpointer user_data)
1007{
1008 gint i=0;
1009
1010 /* First, search for a handler that might know what to do. */
1011
1012 /* FIXME: When this is all working, since the first item in every
1013 * array is the gchar* of the key, there's no reason we can't
1014 * find the correct record for that key here and save code duplication.
1015 */
1016
1017 while (preference_update_handler[i]!=NULL((void*)0))
1018 {
1019 if (preference_update_handler[i] (key, settings))
1020 return; /* Get rid of this eventually */
1021
1022 i++;
1023 }
1024
1025 gchar *schema_name = NULL((void*)0);
1026 g_object_get (settings, "schema-id", &schema_name, NULL((void*)0));
1027
1028 if (g_strcmp0 (schema_name, KEY_WINDOW_BINDINGS_SCHEMA"org.mate.Marco.window-keybindings") == 0 ||
1029 g_strcmp0 (schema_name, KEY_SCREEN_BINDINGS_SCHEMA"org.mate.Marco.global-keybindings") == 0)
1030 {
1031 gchar *str;
1032 str = g_settings_get_string (settings, key);
1033
1034 if (update_key_binding (key, str))
1035 queue_changed (META_PREF_KEYBINDINGS);
1036
1037 g_free(str);
1038 }
1039 else if (g_strcmp0 (schema_name, KEY_COMMAND_SCHEMA"org.mate.Marco.keybinding-commands") == 0)
1040 {
1041 gchar *str;
1042 str = g_settings_get_string (settings, key);
1043
1044 if (update_command (key, str))
1045 queue_changed (META_PREF_COMMANDS);
1046
1047 g_free(str);
1048 }
1049 else if (g_strcmp0 (schema_name, KEY_WORKSPACE_NAME_SCHEMA"org.mate.Marco.workspace-names") == 0)
1050 {
1051 gchar *str;
1052 str = g_settings_get_string (settings, key);
1053
1054 if (update_workspace_name (key, str))
1055 queue_changed (META_PREF_WORKSPACE_NAMES);
1056
1057 g_free(str);
1058 }
1059 else
1060 {
1061 /* Is this possible with GSettings? I dont think so! */
1062 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Key %s doesn't mean anything to Marco\n",
1063 key);
1064 }
1065 g_free (schema_name);
1066}
1067
1068#if 0
1069static void
1070cleanup_error (GError **error)
1071{
1072 if (*error)
1073 {
1074 meta_warning ("%s\n", (*error)->message);
1075
1076 g_error_free (*error);
1077 *error = NULL((void*)0);
1078 }
1079}
1080#endif
1081
1082/**
1083 * Special case: give a warning the first time disable_workarounds
1084 * is turned on.
1085 */
1086static void
1087maybe_give_disable_workarounds_warning (void)
1088{
1089 static gboolean first_disable = TRUE(!(0));
1090
1091 if (first_disable && disable_workarounds)
1092 {
1093 first_disable = FALSE(0);
1094
1095 meta_warning (_("Workarounds for broken applications disabled. "((char *) g_dgettext ("marco", "Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"))
1096 "Some applications may not behave properly.\n")((char *) g_dgettext ("marco", "Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"))
);
1097 }
1098}
1099
1100MetaVirtualModifier
1101meta_prefs_get_mouse_button_mods (void)
1102{
1103 return mouse_button_mods;
1104}
1105
1106MetaFocusMode
1107meta_prefs_get_focus_mode (void)
1108{
1109 return focus_mode;
1110}
1111
1112MetaFocusNewWindows
1113meta_prefs_get_focus_new_windows (void)
1114{
1115 return focus_new_windows;
1116}
1117
1118gboolean
1119meta_prefs_get_attach_modal_dialogs (void)
1120{
1121 return attach_modal_dialogs;
1122}
1123
1124gboolean
1125meta_prefs_get_raise_on_click (void)
1126{
1127 return raise_on_click;
1128}
1129
1130const char*
1131meta_prefs_get_theme (void)
1132{
1133 return current_theme;
1134}
1135
1136const char*
1137meta_prefs_get_cursor_theme (void)
1138{
1139 return cursor_theme;
1140}
1141
1142int
1143meta_prefs_get_cursor_size (void)
1144{
1145 GdkWindow *window = gdk_get_default_root_window ();
1146 gint scale = gdk_window_get_scale_factor (window);
1147
1148 return cursor_size * scale;
1149}
1150
1151int
1152meta_prefs_get_icon_size (void)
1153{
1154 GdkWindow *window = gdk_get_default_root_window ();
1155 gint scale = gdk_window_get_scale_factor (window);
1156
1157 return icon_size * scale;
1158}
1159
1160int
1161meta_prefs_get_alt_tab_max_columns (void)
1162{
1163 return alt_tab_max_columns;
1164}
1165
1166gboolean
1167meta_prefs_get_alt_tab_expand_to_fit_title (void)
1168{
1169 return alt_tab_expand_to_fit_title;
1170}
1171
1172gboolean
1173meta_prefs_get_alt_tab_raise_windows (void)
1174{
1175 return alt_tab_raise_windows;
1176}
1177
1178gboolean
1179meta_prefs_is_in_skip_list (char *class)
1180{
1181 GList *item;
1182
1183 for (item = show_desktop_skip_list; item; item = item->next)
1184 {
1185 if (!g_ascii_strcasecmp (class, item->data))
1186 return TRUE(!(0));
1187 }
1188 return FALSE(0);
1189}
1190
1191/****************************************************************************/
1192/* Handlers for string preferences. */
1193/****************************************************************************/
1194
1195static void
1196titlebar_handler (MetaPreference pref,
1197 const gchar *string_value,
1198 gboolean *inform_listeners)
1199{
1200 PangoFontDescription *new_desc = NULL((void*)0);
1201
1202 if (string_value)
1203 new_desc = pango_font_description_from_string (string_value);
1204
1205 if (new_desc == NULL((void*)0))
1206 {
1207 meta_warning (_("Could not parse font description "((char *) g_dgettext ("marco", "Could not parse font description "
"\"%s\" from GSettings key %s\n"))
1208 "\"%s\" from GSettings key %s\n")((char *) g_dgettext ("marco", "Could not parse font description "
"\"%s\" from GSettings key %s\n"))
,
1209 string_value ? string_value : "(null)",
1210 KEY_GENERAL_TITLEBAR_FONT"titlebar-font");
1211
1212 *inform_listeners = FALSE(0);
1213
1214 return;
1215 }
1216
1217 /* Is the new description the same as the old? */
1218
1219 if (titlebar_font &&
1220 pango_font_description_equal (new_desc, titlebar_font))
1221 {
1222 pango_font_description_free (new_desc);
1223 *inform_listeners = FALSE(0);
1224 return;
1225 }
1226
1227 /* No, so free the old one and put ours in instead. */
1228
1229 if (titlebar_font)
1230 pango_font_description_free (titlebar_font);
1231
1232 titlebar_font = new_desc;
1233
1234}
1235
1236static void
1237theme_name_handler (MetaPreference pref,
1238 const gchar *string_value,
1239 gboolean *inform_listeners)
1240{
1241 g_free (current_theme);
1242
1243 /* Fallback crackrock */
1244 if (string_value == NULL((void*)0))
1245 current_theme = g_strdup ("ClearlooksRe")g_strdup_inline ("ClearlooksRe");
1246 else
1247 current_theme = g_strdup (string_value)g_strdup_inline (string_value);
1248}
1249
1250static void
1251mouse_button_mods_handler (MetaPreference pref,
1252 const gchar *string_value,
1253 gboolean *inform_listeners)
1254{
1255 MetaVirtualModifier mods;
1256
1257 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1258 "Mouse button modifier has new GSettings value \"%s\"\n",
1259 string_value);
1260 if (string_value && meta_ui_parse_modifier (string_value, &mods))
1261 {
1262 mouse_button_mods = mods;
1263 }
1264 else
1265 {
1266 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1267 "Failed to parse new GSettings value\n");
1268
1269 meta_warning (_("\"%s\" found in configuration database is "((char *) g_dgettext ("marco", "\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"))
1270 "not a valid value for mouse button modifier\n")((char *) g_dgettext ("marco", "\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"))
,
1271 string_value);
1272
1273 *inform_listeners = FALSE(0);
1274 }
1275}
1276
1277static void
1278show_desktop_skip_list_handler (MetaPreference pref,
1279 const gchar *string_value,
1280 gboolean *inform_listeners)
1281{
1282 gchar **tokens;
1283 gchar **tok;
1284 GList *item;
1285
1286 if (show_desktop_skip_list)
1287 {
1288 for (item = show_desktop_skip_list; item; item = item->next)
1289 g_free (item->data);
1290 g_list_free (show_desktop_skip_list);
1291 show_desktop_skip_list = NULL((void*)0);
1292 }
1293
1294 if (!(tokens = g_strsplit (string_value, ",", -1)))
1295 return;
1296 for (tok = tokens; tok && *tok; tok++)
1297 {
1298 gchar *stripped = g_strstrip (g_strdup (*tok))g_strchomp (g_strchug (g_strdup_inline (*tok)));
1299 show_desktop_skip_list = g_list_prepend (show_desktop_skip_list, stripped);
1300 }
1301 g_strfreev (tokens);
1302}
1303
1304static gboolean
1305button_layout_equal (const MetaButtonLayout *a,
1306 const MetaButtonLayout *b)
1307{
1308 int i;
1309
1310 i = 0;
5
The value 0 is assigned to 'i'
1311 while (i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST)
6
Loop condition is true. Entering loop body
1312 {
1313 if (a->left_buttons[i] != b->left_buttons[i])
7
The right operand of '!=' is a garbage value
1314 return FALSE(0);
1315 if (a->right_buttons[i] != b->right_buttons[i])
1316 return FALSE(0);
1317 if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1318 return FALSE(0);
1319 if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1320 return FALSE(0);
1321 ++i;
1322 }
1323
1324 return TRUE(!(0));
1325}
1326
1327static MetaButtonFunction
1328button_function_from_string (const char *str)
1329{
1330 /* FIXME: g_settings_get_enum is the obvious way to do this */
1331
1332 if (strcmp (str, "menu") == 0)
1333 return META_BUTTON_FUNCTION_MENU;
1334 else if (strcmp (str, "appmenu") == 0)
1335 return META_BUTTON_FUNCTION_APPMENU;
1336 else if (strcmp (str, "minimize") == 0)
1337 return META_BUTTON_FUNCTION_MINIMIZE;
1338 else if (strcmp (str, "maximize") == 0)
1339 return META_BUTTON_FUNCTION_MAXIMIZE;
1340 else if (strcmp (str, "close") == 0)
1341 return META_BUTTON_FUNCTION_CLOSE;
1342 else if (strcmp (str, "shade") == 0)
1343 return META_BUTTON_FUNCTION_SHADE;
1344 else if (strcmp (str, "above") == 0)
1345 return META_BUTTON_FUNCTION_ABOVE;
1346 else if (strcmp (str, "stick") == 0)
1347 return META_BUTTON_FUNCTION_STICK;
1348 else
1349 /* don't know; give up */
1350 return META_BUTTON_FUNCTION_LAST;
1351}
1352
1353static MetaButtonFunction
1354button_opposite_function (MetaButtonFunction ofwhat)
1355{
1356 switch (ofwhat)
1357 {
1358 case META_BUTTON_FUNCTION_SHADE:
1359 return META_BUTTON_FUNCTION_UNSHADE;
1360 case META_BUTTON_FUNCTION_UNSHADE:
1361 return META_BUTTON_FUNCTION_SHADE;
1362
1363 case META_BUTTON_FUNCTION_ABOVE:
1364 return META_BUTTON_FUNCTION_UNABOVE;
1365 case META_BUTTON_FUNCTION_UNABOVE:
1366 return META_BUTTON_FUNCTION_ABOVE;
1367
1368 case META_BUTTON_FUNCTION_STICK:
1369 return META_BUTTON_FUNCTION_UNSTICK;
1370 case META_BUTTON_FUNCTION_UNSTICK:
1371 return META_BUTTON_FUNCTION_STICK;
1372
1373 default:
1374 return META_BUTTON_FUNCTION_LAST;
1375 }
1376}
1377
1378static void
1379button_layout_handler (MetaPreference pref,
1380 const gchar *string_value,
1381 gboolean *inform_listeners)
1382{
1383 MetaButtonLayout new_layout;
1384 char **sides = NULL((void*)0);
1385 int i;
1386
1387 /* We need to ignore unknown button functions, for
1388 * compat with future versions
1389 */
1390
1391 if (string_value)
1
Assuming 'string_value' is null
1392 sides = g_strsplit (string_value, ":", 2);
1393
1394 if (sides
1.1
'sides' is equal to NULL
!= NULL((void*)0) && sides[0] != NULL((void*)0))
1395 {
1396 char **buttons;
1397 int b;
1398 gboolean used[META_BUTTON_FUNCTION_LAST];
1399
1400 i = 0;
1401 while (i < META_BUTTON_FUNCTION_LAST)
1402 {
1403 used[i] = FALSE(0);
1404 new_layout.left_buttons_has_spacer[i] = FALSE(0);
1405 ++i;
1406 }
1407
1408 buttons = g_strsplit (sides[0], ",", -1);
1409 i = 0;
1410 b = 0;
1411 while (buttons[b] != NULL((void*)0))
1412 {
1413 MetaButtonFunction f = button_function_from_string (buttons[b]);
1414 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1415 {
1416 new_layout.left_buttons_has_spacer[i-1] = TRUE(!(0));
1417 f = button_opposite_function (f);
1418
1419 if (f != META_BUTTON_FUNCTION_LAST)
1420 {
1421 new_layout.left_buttons_has_spacer[i-2] = TRUE(!(0));
1422 }
1423 }
1424 else
1425 {
1426 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1427 {
1428 new_layout.left_buttons[i] = f;
1429 used[f] = TRUE(!(0));
1430 ++i;
1431
1432 f = button_opposite_function (f);
1433
1434 if (f != META_BUTTON_FUNCTION_LAST)
1435 new_layout.left_buttons[i++] = f;
1436
1437 }
1438 else
1439 {
1440 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1441 buttons[b]);
1442 }
1443 }
1444
1445 ++b;
1446 }
1447
1448 new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1449 new_layout.left_buttons_has_spacer[i] = FALSE(0);
1450
1451 g_strfreev (buttons);
1452 }
1453
1454 if (sides
1.2
'sides' is equal to NULL
!= NULL((void*)0) && sides[0] != NULL((void*)0) && sides[1] != NULL((void*)0))
1455 {
1456 char **buttons;
1457 int b;
1458 gboolean used[META_BUTTON_FUNCTION_LAST];
1459
1460 i = 0;
1461 while (i < META_BUTTON_FUNCTION_LAST)
1462 {
1463 used[i] = FALSE(0);
1464 new_layout.right_buttons_has_spacer[i] = FALSE(0);
1465 ++i;
1466 }
1467
1468 buttons = g_strsplit (sides[1], ",", -1);
1469 i = 0;
1470 b = 0;
1471 while (buttons[b] != NULL((void*)0))
1472 {
1473 MetaButtonFunction f = button_function_from_string (buttons[b]);
1474 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1475 {
1476 new_layout.right_buttons_has_spacer[i-1] = TRUE(!(0));
1477 f = button_opposite_function (f);
1478 if (f != META_BUTTON_FUNCTION_LAST)
1479 {
1480 new_layout.right_buttons_has_spacer[i-2] = TRUE(!(0));
1481 }
1482 }
1483 else
1484 {
1485 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1486 {
1487 new_layout.right_buttons[i] = f;
1488 used[f] = TRUE(!(0));
1489 ++i;
1490
1491 f = button_opposite_function (f);
1492
1493 if (f != META_BUTTON_FUNCTION_LAST)
1494 new_layout.right_buttons[i++] = f;
1495
1496 }
1497 else
1498 {
1499 meta_topicmeta_topic_real (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1500 buttons[b]);
1501 }
1502 }
1503
1504 ++b;
1505 }
1506
1507 new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1508 new_layout.right_buttons_has_spacer[i] = FALSE(0);
1509
1510 g_strfreev (buttons);
1511 }
1512
1513 g_strfreev (sides);
1514
1515 /* Invert the button layout for RTL languages */
1516 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
2
Assuming the condition is false
3
Taking false branch
1517 {
1518 MetaButtonLayout rtl_layout;
1519 int j;
1520
1521 for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1522 for (j = 0; j < i; j++)
1523 {
1524 rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1525 if (j == 0)
1526 rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1527 else
1528 rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1529 }
1530 rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1531 rtl_layout.right_buttons_has_spacer[j] = FALSE(0);
1532
1533 for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1534 for (j = 0; j < i; j++)
1535 {
1536 rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1537 if (j == 0)
1538 rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1539 else
1540 rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1541 }
1542 rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1543 rtl_layout.left_buttons_has_spacer[j] = FALSE(0);
1544
1545 new_layout = rtl_layout;
1546 }
1547
1548 if (button_layout_equal (&button_layout, &new_layout))
4
Calling 'button_layout_equal'
1549 {
1550 /* Same as before, so duck out */
1551 *inform_listeners = FALSE(0);
1552 }
1553 else
1554 {
1555 button_layout = new_layout;
1556 }
1557}
1558
1559const PangoFontDescription*
1560meta_prefs_get_titlebar_font (void)
1561{
1562 if (use_system_font)
1563 return NULL((void*)0);
1564 else
1565 return titlebar_font;
1566}
1567
1568int
1569meta_prefs_get_num_workspaces (void)
1570{
1571 return num_workspaces;
1572}
1573
1574MetaWrapStyle
1575meta_prefs_get_wrap_style (void)
1576{
1577 return wrap_style;
1578}
1579
1580gboolean
1581meta_prefs_get_application_based (void)
1582{
1583 return FALSE(0); /* For now, we never want this to do anything */
1584
1585 return application_based;
1586}
1587
1588gboolean
1589meta_prefs_get_disable_workarounds (void)
1590{
1591 return disable_workarounds;
1592}
1593
1594#define MAX_REASONABLE_AUTO_RAISE_DELAY10000 10000
1595
1596#ifdef WITH_VERBOSE_MODE1
1597const char*
1598meta_preference_to_string (MetaPreference pref)
1599{
1600 /* FIXME: another case for g_settings_get_enum */
1601 switch (pref)
1602 {
1603 case META_PREF_MOUSE_BUTTON_MODS:
1604 return "MOUSE_BUTTON_MODS";
1605
1606 case META_PREF_FOCUS_MODE:
1607 return "FOCUS_MODE";
1608
1609 case META_PREF_FOCUS_NEW_WINDOWS:
1610 return "FOCUS_NEW_WINDOWS";
1611
1612 case META_PREF_ATTACH_MODAL_DIALOGS:
1613 return "ATTACH_MODAL_DIALOGS";
1614
1615 case META_PREF_RAISE_ON_CLICK:
1616 return "RAISE_ON_CLICK";
1617
1618 case META_PREF_THEME:
1619 return "THEME";
1620
1621 case META_PREF_TITLEBAR_FONT:
1622 return "TITLEBAR_FONT";
1623
1624 case META_PREF_NUM_WORKSPACES:
1625 return "NUM_WORKSPACES";
1626
1627 case META_PREF_WRAP_STYLE:
1628 return "WRAP_STYLE";
1629
1630 case META_PREF_APPLICATION_BASED:
1631 return "APPLICATION_BASED";
1632
1633 case META_PREF_KEYBINDINGS:
1634 return "KEYBINDINGS";
1635
1636 case META_PREF_DISABLE_WORKAROUNDS:
1637 return "DISABLE_WORKAROUNDS";
1638
1639 case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1640 return "ACTION_DOUBLE_CLICK_TITLEBAR";
1641
1642 case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1643 return "ACTION_MIDDLE_CLICK_TITLEBAR";
1644
1645 case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1646 return "ACTION_RIGHT_CLICK_TITLEBAR";
1647
1648 case META_PREF_AUTO_RAISE:
1649 return "AUTO_RAISE";
1650
1651 case META_PREF_AUTO_RAISE_DELAY:
1652 return "AUTO_RAISE_DELAY";
1653
1654 case META_PREF_COMMANDS:
1655 return "COMMANDS";
1656
1657 case META_PREF_TERMINAL_COMMAND:
1658 return "TERMINAL_COMMAND";
1659
1660 case META_PREF_BUTTON_LAYOUT:
1661 return "BUTTON_LAYOUT";
1662
1663 case META_PREF_WORKSPACE_NAMES:
1664 return "WORKSPACE_NAMES";
1665
1666 case META_PREF_VISUAL_BELL:
1667 return "VISUAL_BELL";
1668
1669 case META_PREF_AUDIBLE_BELL:
1670 return "AUDIBLE_BELL";
1671
1672 case META_PREF_VISUAL_BELL_TYPE:
1673 return "VISUAL_BELL_TYPE";
1674
1675 case META_PREF_REDUCED_RESOURCES:
1676 return "REDUCED_RESOURCES";
1677
1678 case META_PREF_MATE_ACCESSIBILITY:
1679 return "MATE_ACCESSIBILTY";
1680
1681 case META_PREF_MATE_ANIMATIONS:
1682 return "MATE_ANIMATIONS";
1683
1684 case META_PREF_CURSOR_THEME:
1685 return "CURSOR_THEME";
1686
1687 case META_PREF_CURSOR_SIZE:
1688 return "CURSOR_SIZE";
1689
1690 case META_PREF_ICON_SIZE:
1691 return "ICON_SIZE";
1692
1693 case META_PREF_ALT_TAB_MAX_COLUMNS:
1694 return "ALT_TAB_MAX_COLUMNS";
1695
1696 case META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE:
1697 return "ALT_TAB_EXPAND_TO_FIT_TITLE";
1698
1699 case META_PREF_ALT_TAB_RAISE_WINDOWS:
1700 return "ALT_TAB_RAISE_WINDOWS";
1701
1702 case META_PREF_COMPOSITING_MANAGER:
1703 return "COMPOSITING_MANAGER";
1704
1705 case META_PREF_COMPOSITING_FAST_ALT_TAB:
1706 return "COMPOSITING_FAST_ALT_TAB";
1707
1708 case META_PREF_CENTER_NEW_WINDOWS:
1709 return "CENTER_NEW_WINDOWS";
1710
1711 case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1712 return "RESIZE_WITH_RIGHT_BUTTON";
1713
1714 case META_PREF_SHOW_TAB_BORDER:
1715 return "SHOW_TAB_BORDER";
1716
1717 case META_PREF_FORCE_FULLSCREEN:
1718 return "FORCE_FULLSCREEN";
1719
1720 case META_PREF_ALLOW_TILING:
1721 return "ALLOW_TILING";
1722
1723 case META_PREF_ALLOW_TOP_TILING:
1724 return "ALLOW_TOP_TILING";
1725
1726 case META_PREF_ALLOW_TILE_CYCLING:
1727 return "ALLOW_TILE_CYCLING";
1728
1729 case META_PREF_PLACEMENT_MODE:
1730 return "PLACEMENT_MODE";
1731
1732 case META_PREF_SHOW_DESKTOP_SKIP_LIST:
1733 return "SHOW_DESKTOP_SKIP_LIST";
1734 }
1735
1736 return "(unknown)";
1737}
1738#endif /* WITH_VERBOSE_MODE */
1739
1740void
1741meta_prefs_set_num_workspaces (int n_workspaces)
1742{
1743 if (n_workspaces < 1)
1744 n_workspaces = 1;
1745 if (n_workspaces > MAX_REASONABLE_WORKSPACES36)
1746 n_workspaces = MAX_REASONABLE_WORKSPACES36;
1747
1748 g_settings_set_int (settings_general,
1749 KEY_GENERAL_NUM_WORKSPACES"num-workspaces",
1750 n_workspaces);
1751
1752}
1753
1754#define keybind(name, handler, param, flags) \
1755 { #name, NULL((void*)0), !!(flags & BINDING_REVERSES0x02), !!(flags & BINDING_PER_WINDOW0x01) },
1756static MetaKeyPref key_bindings[] = {
1757#include "all-keybindings.h"
1758 { NULL((void*)0), NULL((void*)0), FALSE(0) }
1759};
1760#undef keybind
1761
1762static void
1763init_bindings (GSettings *settings)
1764{
1765 GSettingsSchema *schema;
1766 gchar **list;
1767 gsize i;
1768
1769 g_object_get (settings, "settings-schema", &schema, NULL((void*)0));
1770 list = g_settings_schema_list_keys (schema);
1771 g_settings_schema_unref (schema);
1772
1773 for (i = 0; list[i] != NULL((void*)0); i++)
1774 {
1775 gchar *str_val;
1776
1777 str_val = g_settings_get_string (settings, list[i]);
1778 update_key_binding (list[i], str_val);
1779 g_free (str_val);
1780 }
1781
1782 g_strfreev (list);
1783}
1784
1785static void
1786init_screen_bindings (void)
1787{
1788 init_bindings (settings_screen_bindings);
1789}
1790
1791static void
1792init_window_bindings (void)
1793{
1794 init_bindings (settings_window_bindings);
1795}
1796
1797static void
1798init_commands (void)
1799{
1800 GSettingsSchema *schema;
1801 gchar **list;
1802 gsize i;
1803
1804 g_object_get (settings_command, "settings-schema", &schema, NULL((void*)0));
1805 list = g_settings_schema_list_keys (schema);
1806 g_settings_schema_unref (schema);
1807
1808 for (i = 0; list[i] != NULL((void*)0); i++)
1809 {
1810 gchar *str_val;
1811
1812 str_val = g_settings_get_string (settings_command, list[i]);
1813 update_command (list[i], str_val);
1814 g_free (str_val);
1815 }
1816
1817 g_strfreev (list);
1818}
1819
1820static void
1821init_workspace_names (void)
1822{
1823 GSettingsSchema *schema;
1824 gchar **list;
1825 gsize i;
1826
1827 g_object_get (settings_workspace_names, "settings-schema", &schema, NULL((void*)0));
1828 list = g_settings_schema_list_keys (schema);
1829 g_settings_schema_unref (schema);
1830
1831 for (i = 0; list[i] != NULL((void*)0); i++)
1832 {
1833 gchar *str_val;
1834
1835 str_val = g_settings_get_string (settings_workspace_names, list[i]);
1836 update_workspace_name (list[i], str_val);
1837 g_free (str_val);
1838 }
1839
1840 g_strfreev (list);
1841}
1842
1843static gboolean
1844update_binding (MetaKeyPref *binding,
1845 gchar *value)
1846{
1847 unsigned int keysym;
1848 unsigned int keycode;
1849 MetaVirtualModifier mods;
1850 MetaKeyCombo *combo;
1851 gboolean changed;
1852
1853 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1854 "Binding \"%s\" has new GSettings value \"%s\"\n",
1855 binding->name, value ? value : "none");
1856
1857 keysym = 0;
1858 keycode = 0;
1859 mods = 0;
1860 if (value)
1861 {
1862 if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
1863 {
1864 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1865 "Failed to parse new GSettings value\n");
1866 meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n")((char *) g_dgettext ("marco", "\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"
))
,
1867 value, binding->name);
1868
1869 return FALSE(0);
1870 }
1871 }
1872
1873 /* If there isn't already a first element, make one. */
1874 if (!binding->bindings)
1875 {
1876 MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
1877 binding->bindings = g_slist_alloc();
1878 binding->bindings->data = blank;
1879 }
1880
1881 combo = binding->bindings->data;
1882
1883 /* Bug 329676: Bindings which can be shifted must not have no modifiers,
1884 * nor only SHIFT as a modifier.
1885 */
1886
1887 if (binding->add_shift &&
1888 0 != keysym &&
1889 (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
1890 {
1891 gchar *old_setting;
1892
1893 meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
1894 "such as Ctrl or Alt.\n",
1895 binding->name,
1896 value);
1897
1898 old_setting = meta_ui_accelerator_name (combo->keysym,
1899 combo->modifiers);
1900
1901 if (!strcmp(old_setting, value))
1902 {
1903 /* We were about to set it to the same value
1904 * that it had originally! This must be caused
1905 * by getting an invalid string back from
1906 * meta_ui_accelerator_name. Bail out now
1907 * so we don't get into an infinite loop.
1908 */
1909 g_free (old_setting);
1910 return TRUE(!(0));
1911 }
1912
1913 meta_warning ("Reverting \"%s\" to %s.\n",
1914 binding->name,
1915 old_setting);
1916
1917 /* FIXME: add_shift is currently screen_bindings only, but
1918 * there's no really good reason it should always be.
1919 * So we shouldn't blindly add KEY_SCREEN_BINDINGS_PREFIX
1920 * onto here.
1921 */
1922 g_settings_set_string(settings_screen_bindings,
1923 binding->name,
1924 old_setting);
1925
1926 g_free (old_setting);
1927
1928 /* The call to g_settings_set_string() will cause this function
1929 * to be called again with the new value, so there's no need to
1930 * carry on.
1931 */
1932 return TRUE(!(0));
1933 }
1934
1935 changed = FALSE(0);
1936 if (keysym != combo->keysym ||
1937 keycode != combo->keycode ||
1938 mods != combo->modifiers)
1939 {
1940 changed = TRUE(!(0));
1941
1942 combo->keysym = keysym;
1943 combo->keycode = keycode;
1944 combo->modifiers = mods;
1945
1946 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1947 "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
1948 binding->name, combo->keysym, combo->keycode,
1949 combo->modifiers);
1950 }
1951 else
1952 {
1953 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
1954 "Keybinding for \"%s\" is unchanged\n", binding->name);
1955 }
1956
1957 return changed;
1958}
1959
1960static const gchar*
1961relative_key (const gchar* key)
1962{
1963 const gchar* end;
1964
1965 end = strrchr (key, '/');
1966
1967 ++end;
1968
1969 return end;
1970}
1971
1972/* Return value is TRUE if a preference changed and we need to
1973 * notify
1974 */
1975static gboolean
1976find_and_update_binding (MetaKeyPref *bindings,
1977 const char *name,
1978 gchar *value)
1979{
1980 const char *key;
1981 int i;
1982
1983 if (*name == '/')
1984 key = relative_key (name);
1985 else
1986 key = name;
1987
1988 i = 0;
1989 while (bindings[i].name &&
1990 strcmp (key, bindings[i].name) != 0)
1991 ++i;
1992
1993 if (bindings[i].name)
1994 return update_binding (&bindings[i], value);
1995 else
1996 return FALSE(0);
1997}
1998
1999static gboolean
2000update_key_binding (const char *name,
2001 gchar *value)
2002{
2003 return find_and_update_binding (key_bindings, name, value);
2004}
2005
2006static gboolean
2007update_command (const char *name,
2008 const char *value)
2009{
2010 char *p;
2011 int i;
2012
2013 p = strrchr (name, '-');
2014 if (p == NULL((void*)0))
2015 {
2016 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2017 "Command %s has no dash?\n", name);
2018 return FALSE(0);
2019 }
2020
2021 ++p;
2022
2023 if (g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0))
2024 {
2025 i = atoi (p);
2026 i -= 1; /* count from 0 not 1 */
2027 }
2028 else
2029 {
2030 if (strcmp (name, "command-screenshot") == 0)
2031 {
2032 i = SCREENSHOT_COMMAND_IDX((32 + 2) - 2);
2033 }
2034 else if (strcmp (name, "command-window-screenshot") == 0)
2035 {
2036 i = WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1);
2037 }
2038 else
2039 {
2040 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2041 "Command %s doesn't end in number?\n", name);
2042 return FALSE(0);
2043 }
2044 }
2045
2046 if (i >= MAX_COMMANDS(32 + 2))
2047 {
2048 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2049 "Command %d is too highly numbered, ignoring\n", i);
2050 return FALSE(0);
2051 }
2052
2053 if ((commands[i] == NULL((void*)0) && value == NULL((void*)0)) ||
2054 (commands[i] && value && strcmp (commands[i], value) == 0))
2055 {
2056 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2057 "Command %d is unchanged\n", i);
2058 return FALSE(0);
2059 }
2060
2061 g_free (commands[i]);
2062 commands[i] = g_strdup (value)g_strdup_inline (value);
2063
2064 meta_topicmeta_topic_real (META_DEBUG_KEYBINDINGS,
2065 "Updated command %d to \"%s\"\n",
2066 i, commands[i] ? commands[i] : "none");
2067
2068 return TRUE(!(0));
2069}
2070
2071const char*
2072meta_prefs_get_command (int i)
2073{
2074 g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL)do { if ((i >= 0 && i < (32 + 2))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_COMMANDS"
); return (((void*)0)); } } while (0)
;
2075
2076 return commands[i];
2077}
2078
2079char*
2080meta_prefs_get_settings_key_for_command (int i)
2081{
2082 char *key;
2083
2084 switch (i)
2085 {
2086 case SCREENSHOT_COMMAND_IDX((32 + 2) - 2):
2087 key = g_strdup (KEY_COMMAND_PREFIX "screenshot")g_strdup_inline ("command-" "screenshot");
2088 break;
2089 case WIN_SCREENSHOT_COMMAND_IDX((32 + 2) - 1):
2090 key = g_strdup (KEY_COMMAND_PREFIX "window-screenshot")g_strdup_inline ("command-" "window-screenshot");
2091 break;
2092 default:
2093 key = g_strdup_printf (KEY_COMMAND_PREFIX"command-""%d", i + 1);
2094 break;
2095 }
2096
2097 return key;
2098}
2099
2100const char*
2101meta_prefs_get_terminal_command (void)
2102{
2103 return terminal_command;
2104}
2105
2106const char*
2107meta_prefs_get_settings_key_for_terminal_command (void)
2108{
2109 return KEY_MATE_TERMINAL_COMMAND"exec";
2110}
2111
2112static gboolean
2113update_workspace_name (const char *name,
2114 const char *value)
2115{
2116 char *p;
2117 int i;
2118
2119 p = strrchr (name, '-');
2120 if (p == NULL((void*)0))
2121 {
2122 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2123 "Workspace name %s has no dash?\n", name);
2124 return FALSE(0);
2125 }
2126
2127 ++p;
2128
2129 if (!g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0))
2130 {
2131 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2132 "Workspace name %s doesn't end in number?\n", name);
2133 return FALSE(0);
2134 }
2135
2136 i = atoi (p);
2137 i -= 1; /* count from 0 not 1 */
2138
2139 if (i >= MAX_REASONABLE_WORKSPACES36)
2140 {
2141 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2142 "Workspace name %d is too highly numbered, ignoring\n", i);
2143 return FALSE(0);
2144 }
2145
2146 if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2147 {
2148 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2149 "Workspace name %d is unchanged\n", i);
2150 return FALSE(0);
2151 }
2152
2153 /* This is a bad hack. We have to treat empty string as
2154 * "unset" because the root window property can't contain
2155 * null. So it gets empty string instead and we don't want
2156 * that to result in setting the empty string as a value that
2157 * overrides "unset".
2158 */
2159 if (value != NULL((void*)0) && *value != '\0')
2160 {
2161 g_free (workspace_names[i]);
2162 workspace_names[i] = g_strdup (value)g_strdup_inline (value);
2163 }
2164 else
2165 {
2166 /* use a default name */
2167 char *d;
2168
2169 d = g_strdup_printf (_("Workspace %d")((char *) g_dgettext ("marco", "Workspace %d")), i + 1);
2170 if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2171 {
2172 g_free (d);
2173 return FALSE(0);
2174 }
2175 else
2176 {
2177 g_free (workspace_names[i]);
2178 workspace_names[i] = d;
2179 }
2180 }
2181
2182 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2183 "Updated workspace name %d to \"%s\"\n",
2184 i, workspace_names[i] ? workspace_names[i] : "none");
2185
2186 return TRUE(!(0));
2187}
2188
2189const char*
2190meta_prefs_get_workspace_name (int i)
2191{
2192 g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL)do { if ((i >= 0 && i < 36)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_REASONABLE_WORKSPACES"
); return (((void*)0)); } } while (0)
;
2193
2194 g_assert (workspace_names[i] != NULL)do { if (workspace_names[i] != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/prefs.c", 2194, ((const char*) (__func__)), "workspace_names[i] != NULL"
); } while (0)
;
2195
2196 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2197 "Getting workspace name for %d: \"%s\"\n",
2198 i, workspace_names[i]);
2199
2200 return workspace_names[i];
2201}
2202
2203void
2204meta_prefs_change_workspace_name (int i,
2205 const char *name)
2206{
2207 char *key;
2208
2209 g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES)do { if ((i >= 0 && i < 36)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "i >= 0 && i < MAX_REASONABLE_WORKSPACES"
); return; } } while (0)
;
2210
2211 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2212 "Changing name of workspace %d to %s\n",
2213 i, name ? name : "none");
2214
2215 if (name && *name == '\0')
2216 name = NULL((void*)0);
2217
2218 if ((name == NULL((void*)0) && workspace_names[i] == NULL((void*)0)) ||
2219 (name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2220 {
2221 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2222 "Workspace %d already has name %s\n",
2223 i, name ? name : "none");
2224 return;
2225 }
2226
2227 key = settings_key_for_workspace_name (i);
2228
2229 if (name != NULL((void*)0))
2230 g_settings_set_string (settings_workspace_names,
2231 key,
2232 name);
2233 else
2234 g_settings_set_string (settings_workspace_names,
2235 key,
2236 "");
2237
2238 g_free (key);
2239}
2240
2241static char*
2242settings_key_for_workspace_name (int i)
2243{
2244 char *key;
2245
2246 key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"name-""%d", i + 1);
2247
2248 return key;
2249}
2250
2251void
2252meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2253{
2254 *button_layout_p = button_layout;
2255}
2256
2257gboolean
2258meta_prefs_get_visual_bell (void)
2259{
2260 return provide_visual_bell;
2261}
2262
2263gboolean
2264meta_prefs_bell_is_audible (void)
2265{
2266 return bell_is_audible;
2267}
2268
2269MetaVisualBellType
2270meta_prefs_get_visual_bell_type (void)
2271{
2272 return visual_bell_type;
2273}
2274
2275void
2276meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2277 int *n_bindings)
2278{
2279
2280 *bindings = key_bindings;
2281 *n_bindings = (int) G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 1;
2282}
2283
2284MetaActionTitlebar
2285meta_prefs_get_action_double_click_titlebar (void)
2286{
2287 return action_double_click_titlebar;
2288}
2289
2290MetaActionTitlebar
2291meta_prefs_get_action_middle_click_titlebar (void)
2292{
2293 return action_middle_click_titlebar;
2294}
2295
2296MetaActionTitlebar
2297meta_prefs_get_action_right_click_titlebar (void)
2298{
2299 return action_right_click_titlebar;
2300}
2301
2302gboolean
2303meta_prefs_get_auto_raise (void)
2304{
2305 return auto_raise;
2306}
2307
2308int
2309meta_prefs_get_auto_raise_delay (void)
2310{
2311 return auto_raise_delay;
2312}
2313
2314gboolean
2315meta_prefs_get_reduced_resources (void)
2316{
2317 return reduced_resources;
2318}
2319
2320gboolean
2321meta_prefs_get_mate_accessibility ()
2322{
2323 return mate_accessibility;
2324}
2325
2326gboolean
2327meta_prefs_get_mate_animations ()
2328{
2329 return mate_animations;
2330}
2331
2332MetaKeyBindingAction
2333meta_prefs_get_keybinding_action (const char *name)
2334{
2335 int i;
2336
2337 i = G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 2; /* -2 for dummy entry at end */
2338 while (i >= 0)
2339 {
2340 if (strcmp (key_bindings[i].name, name) == 0)
2341 return (MetaKeyBindingAction) i;
2342
2343 --i;
2344 }
2345
2346 return META_KEYBINDING_ACTION_NONE;
2347}
2348
2349/* This is used by the menu system to decide what key binding
2350 * to display next to an option. We return the first non-disabled
2351 * binding, if any.
2352 */
2353void
2354meta_prefs_get_window_binding (const char *name,
2355 unsigned int *keysym,
2356 MetaVirtualModifier *modifiers)
2357{
2358 int i;
2359
2360 i = G_N_ELEMENTS (key_bindings)(sizeof (key_bindings) / sizeof ((key_bindings)[0])) - 2; /* -2 for dummy entry at end */
2361 while (i >= 0)
2362 {
2363 if (key_bindings[i].per_window &&
2364 strcmp (key_bindings[i].name, name) == 0)
2365 {
2366 GSList *s = key_bindings[i].bindings;
2367
2368 while (s)
2369 {
2370 MetaKeyCombo *c = s->data;
2371
2372 if (c->keysym!=0 || c->modifiers!=0)
2373 {
2374 *keysym = c->keysym;
2375 *modifiers = c->modifiers;
2376 return;
2377 }
2378
2379 s = s->next;
2380 }
2381
2382 /* Not found; return the disabled value */
2383 *keysym = *modifiers = 0;
2384 return;
2385 }
2386
2387 --i;
2388 }
2389
2390 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "core/prefs.c", 2390,
((const char*) (__func__)), ((void*)0)); } while (0)
;
2391}
2392
2393gboolean
2394meta_prefs_get_compositing_manager (void)
2395{
2396 if (use_force_compositor_manager)
2397 return force_compositor_manager;
2398 return compositing_manager;
2399}
2400
2401gboolean
2402meta_prefs_get_compositing_fast_alt_tab (void)
2403{
2404 return compositing_fast_alt_tab;
2405}
2406
2407gboolean
2408meta_prefs_get_center_new_windows (void)
2409{
2410 return center_new_windows;
2411}
2412
2413gboolean
2414meta_prefs_get_allow_tiling ()
2415{
2416 return allow_tiling;
2417}
2418
2419gboolean
2420meta_prefs_get_allow_top_tiling ()
2421{
2422 return allow_top_tiling;
2423}
2424
2425gboolean
2426meta_prefs_get_allow_tile_cycling ()
2427{
2428 return allow_tile_cycling;
2429}
2430
2431guint
2432meta_prefs_get_mouse_button_resize (void)
2433{
2434 return resize_with_right_button ? 3: 2;
2435}
2436
2437guint
2438meta_prefs_get_mouse_button_menu (void)
2439{
2440 return resize_with_right_button ? 2: 3;
2441}
2442
2443gboolean
2444meta_prefs_show_tab_border(void)
2445{
2446 return show_tab_border;
2447}
2448
2449gboolean
2450meta_prefs_get_force_fullscreen (void)
2451{
2452 return force_fullscreen;
2453}
2454
2455MetaPlacementMode
2456meta_prefs_get_placement_mode (void)
2457{
2458 return placement_mode;
2459}
2460
2461void
2462meta_prefs_set_force_compositing_manager (gboolean whether)
2463{
2464 use_force_compositor_manager = TRUE(!(0));
2465 force_compositor_manager = whether;
2466}
2467
2468void
2469meta_prefs_set_compositing_fast_alt_tab (gboolean whether)
2470{
2471 g_settings_set_boolean (settings_general,
2472 KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB"compositing-fast-alt-tab",
2473 whether);
2474}
2475
2476void
2477meta_prefs_set_center_new_windows (gboolean whether)
2478{
2479 g_settings_set_boolean (settings_general,
2480 KEY_GENERAL_CENTER_NEW_WINDOWS"center-new-windows",
2481 whether);
2482}
2483
2484void
2485meta_prefs_set_force_fullscreen (gboolean whether)
2486{
2487 force_fullscreen = whether;
2488}
2489
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e9815c.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e9815c.html new file mode 100644 index 00000000..82bf4db0 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-e9815c.html @@ -0,0 +1,3755 @@ + + + +core/screen.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/screen.c
Warning:line 1781, column 36
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name screen.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/screen.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco X screen handler */
4
5/*
6 * Copyright (C) 2001, 2002 Havoc Pennington
7 * Copyright (C) 2002, 2003 Red Hat Inc.
8 * Some ICCCM manager selection code derived from fvwm2,
9 * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
10 * Copyright (C) 2003 Rob Adams
11 * Copyright (C) 2004-2006 Elijah Newren
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301, USA.
27 */
28
29#include <config.h>
30#include <glib/gi18n-lib.h>
31
32#include "screen-private.h"
33#include "util.h"
34#include "errors.h"
35#include "window-private.h"
36#include "frame-private.h"
37#include "prefs.h"
38#include "workspace.h"
39#include "keybindings.h"
40#include "prefs.h"
41#include "stack.h"
42#include "xprops.h"
43#include "compositor.h"
44
45#ifdef HAVE_SOLARIS_XINERAMA
46#include <X11/extensions/xinerama.h>
47#endif
48#ifdef HAVE_XFREE_XINERAMA
49#include <X11/extensions/Xinerama.h>
50#endif
51
52#include <X11/Xatom.h>
53#include <cairo/cairo-xlib.h>
54#include <locale.h>
55#include <string.h>
56#include <stdio.h>
57
58static char* get_screen_name (MetaDisplay *display,
59 int number);
60
61static void update_num_workspaces (MetaScreen *screen,
62 guint32 timestamp);
63static void update_focus_mode (MetaScreen *screen);
64static void set_workspace_names (MetaScreen *screen);
65static void prefs_changed_callback (MetaPreference pref,
66 gpointer data);
67
68static void set_desktop_geometry_hint (MetaScreen *screen);
69static void set_desktop_viewport_hint (MetaScreen *screen);
70
71#ifdef HAVE_STARTUP_NOTIFICATION
72static void meta_screen_sn_event (SnMonitorEvent *event,
73 void *user_data);
74#endif
75
76static int
77set_wm_check_hint (MetaScreen *screen)
78{
79 unsigned long data[1];
80
81 g_return_val_if_fail (screen->display->leader_window != None, 0)do { if ((screen->display->leader_window != 0L)) { } else
{ g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "screen->display->leader_window != None"); return (
0); } } while (0)
;
82
83 data[0] = screen->display->leader_window;
84
85 XChangeProperty (screen->display->xdisplay, screen->xroot,
86 screen->display->atom__NET_SUPPORTING_WM_CHECK,
87 XA_WINDOW((Atom) 33),
88 32, PropModeReplace0, (guchar*) data, 1);
89
90 return Success0;
91}
92
93static void
94unset_wm_check_hint (MetaScreen *screen)
95{
96 XDeleteProperty (screen->display->xdisplay, screen->xroot,
97 screen->display->atom__NET_SUPPORTING_WM_CHECK);
98}
99
100static int
101set_supported_hint (MetaScreen *screen)
102{
103 Atom atoms[] = {
104#define EWMH_ATOMS_ONLY
105#define item(x) screen->display->atom_##x,
106#include "atomnames.h"
107#undef item
108#undef EWMH_ATOMS_ONLY
109 screen->display->atom__GTK_FRAME_EXTENTS,
110 screen->display->atom__GTK_SHOW_WINDOW_MENU,
111 screen->display->atom__GTK_WORKAREAS
112 };
113
114 XChangeProperty (screen->display->xdisplay, screen->xroot,
115 screen->display->atom__NET_SUPPORTED,
116 XA_ATOM((Atom) 4),
117 32, PropModeReplace0,
118 (guchar*) atoms, G_N_ELEMENTS(atoms)(sizeof (atoms) / sizeof ((atoms)[0])));
119
120 return Success0;
121}
122
123static int
124set_wm_icon_size_hint (MetaScreen *screen)
125{
126 int icon_size = meta_prefs_get_icon_size();
127#define N_VALS 6
128 gulong vals[N_VALS];
129
130 /* min width, min height, max w, max h, width inc, height inc */
131 vals[0] = icon_size; /* width */
132 vals[1] = icon_size; /* height */
133 vals[2] = icon_size; /* width */
134 vals[3] = icon_size; /* height */
135 vals[4] = 0;
136 vals[5] = 0;
137
138 XChangeProperty (screen->display->xdisplay, screen->xroot,
139 screen->display->atom_WM_ICON_SIZE,
140 XA_CARDINAL((Atom) 6),
141 32, PropModeReplace0, (guchar*) vals, N_VALS);
142
143 return Success0;
144#undef N_VALS
145}
146
147static void
148reload_xinerama_infos (MetaScreen *screen)
149{
150 MetaDisplay *display;
151
152 {
153 GList *tmp;
154
155 tmp = screen->workspaces;
156 while (tmp != NULL((void*)0))
157 {
158 MetaWorkspace *space = tmp->data;
159
160 meta_workspace_invalidate_work_area (space);
161
162 tmp = tmp->next;
163 }
164 }
165
166 display = screen->display;
167
168 if (screen->xinerama_infos)
169 g_free (screen->xinerama_infos);
170
171 screen->xinerama_infos = NULL((void*)0);
172 screen->n_xinerama_infos = 0;
173 screen->last_xinerama_index = 0;
174
175 screen->display->xinerama_cache_invalidated = TRUE(!(0));
176
177#ifdef HAVE_XFREE_XINERAMA
178 if (XineramaIsActive (display->xdisplay))
179 {
180 XineramaScreenInfo *infos;
181 int n_infos;
182 int i;
183
184 n_infos = 0;
185 infos = XineramaQueryScreens (display->xdisplay, &n_infos);
186
187 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
188 "Found %d Xinerama screens on display %s\n",
189 n_infos, display->name);
190
191 if (n_infos > 0)
192 {
193 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos)((MetaXineramaScreenInfo *) g_malloc_n ((n_infos), sizeof (MetaXineramaScreenInfo
)))
;
194 screen->n_xinerama_infos = n_infos;
195
196 i = 0;
197 while (i < n_infos)
198 {
199 screen->xinerama_infos[i].number = infos[i].screen_number;
200 screen->xinerama_infos[i].rect.x = infos[i].x_org;
201 screen->xinerama_infos[i].rect.y = infos[i].y_org;
202 screen->xinerama_infos[i].rect.width = infos[i].width;
203 screen->xinerama_infos[i].rect.height = infos[i].height;
204
205 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
206 "Xinerama %d is %d,%d %d x %d\n",
207 screen->xinerama_infos[i].number,
208 screen->xinerama_infos[i].rect.x,
209 screen->xinerama_infos[i].rect.y,
210 screen->xinerama_infos[i].rect.width,
211 screen->xinerama_infos[i].rect.height);
212
213 ++i;
214 }
215 }
216
217 meta_XFree (infos)do { if ((infos)) XFree ((infos)); } while (0);
218 }
219 else
220 {
221 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
222 "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
223 display->name);
224 }
225#else
226 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
227 "Marco compiled without XFree86 Xinerama support\n");
228#endif /* HAVE_XFREE_XINERAMA */
229
230#ifdef HAVE_SOLARIS_XINERAMA
231 /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
232 if (screen->n_xinerama_infos == 0 &&
233 XineramaGetState (screen->display->xdisplay,
234 screen->number))
235 {
236 XRectangle monitors[MAXFRAMEBUFFERS];
237 unsigned char hints[16];
238 int result;
239 int n_monitors;
240 int i;
241
242 n_monitors = 0;
243 result = XineramaGetInfo (screen->display->xdisplay,
244 screen->number,
245 monitors, hints,
246 &n_monitors);
247 /* Yes I know it should be Success but the current implementation
248 * returns the num of monitor
249 */
250 if (result > 0)
251 {
252 g_assert (n_monitors > 0)do { if (n_monitors > 0) ; else g_assertion_message_expr (
"marco", "core/screen.c", 252, ((const char*) (__func__)), "n_monitors > 0"
); } while (0)
;
253
254 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors)((MetaXineramaScreenInfo *) g_malloc_n ((n_monitors), sizeof (
MetaXineramaScreenInfo)))
;
255 screen->n_xinerama_infos = n_monitors;
256
257 i = 0;
258 while (i < n_monitors)
259 {
260 screen->xinerama_infos[i].number = i;
261 screen->xinerama_infos[i].rect.x = monitors[i].x;
262 screen->xinerama_infos[i].rect.y = monitors[i].y;
263 screen->xinerama_infos[i].rect.width = monitors[i].width;
264 screen->xinerama_infos[i].rect.height = monitors[i].height;
265
266 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
267 "Xinerama %d is %d,%d %d x %d\n",
268 screen->xinerama_infos[i].number,
269 screen->xinerama_infos[i].rect.x,
270 screen->xinerama_infos[i].rect.y,
271 screen->xinerama_infos[i].rect.width,
272 screen->xinerama_infos[i].rect.height);
273
274 ++i;
275 }
276 }
277 }
278 else if (screen->n_xinerama_infos == 0)
279 {
280 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
281 "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
282 display->name);
283 }
284#else
285 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
286 "Marco compiled without Solaris Xinerama support\n");
287#endif /* HAVE_SOLARIS_XINERAMA */
288
289 /* If no Xinerama, fill in the single screen info so
290 * we can use the field unconditionally
291 */
292 if (screen->n_xinerama_infos == 0)
293 {
294 if (g_getenv ("MARCO_DEBUG_XINERAMA"))
295 {
296 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
297 "Pretending a single monitor has two Xinerama screens\n");
298
299 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2)((MetaXineramaScreenInfo *) g_malloc_n ((2), sizeof (MetaXineramaScreenInfo
)))
;
300 screen->n_xinerama_infos = 2;
301
302 screen->xinerama_infos[0].number = 0;
303 screen->xinerama_infos[0].rect = screen->rect;
304 screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
305
306 screen->xinerama_infos[1].number = 1;
307 screen->xinerama_infos[1].rect = screen->rect;
308 screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
309 screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
310 }
311 else
312 {
313 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
314 "No Xinerama screens, using default screen info\n");
315
316 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1)((MetaXineramaScreenInfo *) g_malloc_n ((1), sizeof (MetaXineramaScreenInfo
)))
;
317 screen->n_xinerama_infos = 1;
318
319 screen->xinerama_infos[0].number = 0;
320 screen->xinerama_infos[0].rect = screen->rect;
321 }
322 }
323
324 g_assert (screen->n_xinerama_infos > 0)do { if (screen->n_xinerama_infos > 0) ; else g_assertion_message_expr
("marco", "core/screen.c", 324, ((const char*) (__func__)), "screen->n_xinerama_infos > 0"
); } while (0)
;
325 g_assert (screen->xinerama_infos != NULL)do { if (screen->xinerama_infos != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 325, ((const char*) (__func__)), "screen->xinerama_infos != NULL"
); } while (0)
;
326}
327
328MetaScreen*
329meta_screen_new (MetaDisplay *display,
330 int number,
331 guint32 timestamp)
332{
333 MetaScreen *screen;
334 Window xroot;
335 Display *xdisplay;
336 XWindowAttributes attr;
337 Window new_wm_sn_owner;
338 Window current_wm_sn_owner;
339 gboolean replace_current_wm;
340 Atom wm_sn_atom;
341 char buf[128];
342 guint32 manager_timestamp;
343 gulong current_workspace;
344
345 replace_current_wm = meta_get_replace_current_wm ();
346
347 /* Only display->name, display->xdisplay, and display->error_traps
348 * can really be used in this function, since normally screens are
349 * created from the MetaDisplay constructor
350 */
351
352 xdisplay = display->xdisplay;
353
354 meta_verbosemeta_verbose_real ("Trying screen %d on display '%s'\n",
355 number, display->name);
356
357 xroot = RootWindow (xdisplay, number)((&((_XPrivDisplay)(xdisplay))->screens[number])->root
)
;
358
359 /* FVWM checks for None here, I don't know if this
360 * ever actually happens
361 */
362 if (xroot == None0L)
363 {
364 meta_warning (_("Screen %d on display '%s' is invalid\n")((char *) g_dgettext ("marco", "Screen %d on display '%s' is invalid\n"
))
,
365 number, display->name);
366 return NULL((void*)0);
367 }
368
369 sprintf (buf, "WM_S%d", number);
370 wm_sn_atom = XInternAtom (xdisplay, buf, False0);
371
372 current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
373
374 if (current_wm_sn_owner != None0L)
375 {
376 XSetWindowAttributes attrs;
377
378 if (!replace_current_wm)
379 {
380 meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n")((char *) g_dgettext ("marco", "Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"
))
,
381 number, display->name);
382
383 return NULL((void*)0);
384 }
385
386 /* We want to find out when the current selection owner dies */
387 meta_error_trap_push (display);
388 attrs.event_mask = StructureNotifyMask(1L<<17);
389 XChangeWindowAttributes (xdisplay,
390 current_wm_sn_owner, CWEventMask(1L<<11), &attrs);
391 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
392 current_wm_sn_owner = None0L; /* don't wait for it to die later on */
393 }
394
395 /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
396 * but those cannot be masked, so we only need NoEventMask.
397 */
398 new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask0L);
399
400 manager_timestamp = timestamp;
401
402 XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
403 manager_timestamp);
404
405 if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
406 {
407 meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n")((char *) g_dgettext ("marco", "Could not acquire window manager selection on screen %d display \"%s\"\n"
))
,
408 number, display->name);
409
410 XDestroyWindow (xdisplay, new_wm_sn_owner);
411
412 return NULL((void*)0);
413 }
414
415 {
416 /* Send client message indicating that we are now the WM */
417 XClientMessageEvent ev;
418
419 ev.type = ClientMessage33;
420 ev.window = xroot;
421 ev.message_type = display->atom_MANAGER;
422 ev.format = 32;
423 ev.data.l[0] = manager_timestamp;
424 ev.data.l[1] = wm_sn_atom;
425
426 XSendEvent (xdisplay, xroot, False0, StructureNotifyMask(1L<<17), (XEvent*)&ev);
427 }
428
429 /* Wait for old window manager to go away */
430 if (current_wm_sn_owner != None0L)
431 {
432 XEvent event;
433
434 /* We sort of block infinitely here which is probably lame. */
435
436 meta_verbosemeta_verbose_real ("Waiting for old window manager to exit\n");
437 do
438 {
439 XWindowEvent (xdisplay, current_wm_sn_owner,
440 StructureNotifyMask(1L<<17), &event);
441 }
442 while (event.type != DestroyNotify17);
443 }
444
445 /* select our root window events */
446 meta_error_trap_push (display);
447
448 /* We need to or with the existing event mask since
449 * gtk+ may be interested in other events.
450 */
451 XGetWindowAttributes (xdisplay, xroot, &attr);
452 XSelectInput (xdisplay,
453 xroot,
454 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19) |
455 ColormapChangeMask(1L<<23) | PropertyChangeMask(1L<<22) |
456 LeaveWindowMask(1L<<5) | EnterWindowMask(1L<<4) |
457 KeyPressMask(1L<<0) | KeyReleaseMask(1L<<1) |
458 FocusChangeMask(1L<<21) | StructureNotifyMask(1L<<17) |
459#ifdef HAVE_COMPOSITE_EXTENSIONS1
460 ExposureMask(1L<<15) |
461#endif
462 attr.your_event_mask);
463 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
464 {
465 meta_warning (_("Screen %d on display \"%s\" already has a window manager\n")((char *) g_dgettext ("marco", "Screen %d on display \"%s\" already has a window manager\n"
))
,
466 number, display->name);
467
468 XDestroyWindow (xdisplay, new_wm_sn_owner);
469
470 return NULL((void*)0);
471 }
472
473 screen = g_new (MetaScreen, 1)((MetaScreen *) g_malloc_n ((1), sizeof (MetaScreen)));
474 screen->closing = 0;
475
476 screen->display = display;
477 screen->number = number;
478 screen->screen_name = get_screen_name (display, number);
479 screen->xscreen = ScreenOfDisplay (xdisplay, number)(&((_XPrivDisplay)(xdisplay))->screens[number]);
480 screen->xroot = xroot;
481 screen->rect.x = screen->rect.y = 0;
482 screen->rect.width = WidthOfScreen (screen->xscreen)((screen->xscreen)->width);
483 screen->rect.height = HeightOfScreen (screen->xscreen)((screen->xscreen)->height);
484 screen->current_cursor = -1; /* invalid/unset */
485 screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen)((screen->xscreen)->root_visual);
486 screen->default_depth = DefaultDepthOfScreen (screen->xscreen)((screen->xscreen)->root_depth);
487 screen->flash_window = None0L;
488
489 screen->wm_sn_selection_window = new_wm_sn_owner;
490 screen->wm_sn_atom = wm_sn_atom;
491 screen->wm_sn_timestamp = manager_timestamp;
492
493#ifdef HAVE_COMPOSITE_EXTENSIONS1
494 g_snprintf (buf, sizeof(buf), "_NET_WM_CM_S%d", screen->number);
495 screen->wm_cm_atom = XInternAtom (screen->display->xdisplay, buf, FALSE(0));
496 screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
497 xroot,
498 NoEventMask0L);
499#endif
500 screen->work_area_idle = 0;
501
502 screen->active_workspace = NULL((void*)0);
503 screen->workspaces = NULL((void*)0);
504 screen->rows_of_workspaces = 1;
505 screen->columns_of_workspaces = -1;
506 screen->vertical_workspaces = FALSE(0);
507 screen->starting_corner = META_SCREEN_TOPLEFT;
508 screen->compositor_data = NULL((void*)0);
509
510 {
511 XFontStruct *font_info;
512 XGCValues gc_values;
513 gulong value_mask = 0;
514
515 gc_values.subwindow_mode = IncludeInferiors1;
516 value_mask |= GCSubwindowMode(1L<<15);
517 gc_values.function = GXinvert0xa;
518 value_mask |= GCFunction(1L<<0);
519 gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH2;
520 value_mask |= GCLineWidth(1L<<4);
521
522 font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
523
524 if (font_info != NULL((void*)0))
525 {
526 gc_values.font = font_info->fid;
527 value_mask |= GCFont(1L<<14);
528 XFreeFontInfo (NULL((void*)0), font_info, 1);
529 }
530 else
531 meta_warning ("xserver doesn't have 'fixed' font.\n");
532
533 screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
534 screen->xroot,
535 value_mask,
536 &gc_values);
537 }
538
539 screen->xinerama_infos = NULL((void*)0);
540 screen->n_xinerama_infos = 0;
541 screen->last_xinerama_index = 0;
542
543 reload_xinerama_infos (screen);
544
545 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
546
547 /* Handle creating a no_focus_window for this screen */
548 screen->no_focus_window =
549 meta_create_offscreen_window (display->xdisplay,
550 screen->xroot,
551 FocusChangeMask(1L<<21)|KeyPressMask(1L<<0)|KeyReleaseMask(1L<<1));
552 XMapWindow (display->xdisplay, screen->no_focus_window);
553 /* Done with no_focus_window stuff */
554
555 set_wm_icon_size_hint (screen);
556
557 set_supported_hint (screen);
558
559 set_wm_check_hint (screen);
560
561 set_desktop_viewport_hint (screen);
562
563 set_desktop_geometry_hint (screen);
564
565 meta_screen_update_workspace_layout (screen);
566
567 /* Get current workspace */
568 current_workspace = 0;
569 if (meta_prop_get_cardinal (screen->display,
570 screen->xroot,
571 screen->display->atom__NET_CURRENT_DESKTOP,
572 &current_workspace))
573 meta_verbosemeta_verbose_real ("Read existing _NET_CURRENT_DESKTOP = %d\n",
574 (int) current_workspace);
575 else
576 meta_verbosemeta_verbose_real ("No _NET_CURRENT_DESKTOP present\n");
577
578 /* Screens must have at least one workspace at all times,
579 * so create that required workspace.
580 */
581 meta_workspace_activate (meta_workspace_new (screen), timestamp);
582 update_num_workspaces (screen, timestamp);
583
584 set_workspace_names (screen);
585
586 screen->all_keys_grabbed = FALSE(0);
587 screen->keys_grabbed = FALSE(0);
588 meta_screen_grab_keys (screen);
589
590 screen->ui = meta_ui_new (screen->display->xdisplay,
591 screen->xscreen);
592
593 screen->tab_popup = NULL((void*)0);
594 screen->tile_preview = NULL((void*)0);
595
596 screen->tile_preview_timeout_id = 0;
597
598 screen->stack = meta_stack_new (screen);
599
600 meta_prefs_add_listener (prefs_changed_callback, screen);
601
602#ifdef HAVE_STARTUP_NOTIFICATION
603 screen->sn_context =
604 sn_monitor_context_new (screen->display->sn_display,
605 screen->number,
606 meta_screen_sn_event,
607 screen,
608 NULL((void*)0));
609 screen->startup_sequences = NULL((void*)0);
610 screen->startup_sequence_timeout = 0;
611#endif
612
613 /* Switch to the _NET_CURRENT_DESKTOP workspace */
614 {
615 MetaWorkspace *space;
616
617 space = meta_screen_get_workspace_by_index (screen,
618 current_workspace);
619
620 if (space != NULL((void*)0))
621 meta_workspace_activate (space, timestamp);
622 }
623
624 meta_verbosemeta_verbose_real ("Added screen %d ('%s') root 0x%lx\n",
625 screen->number, screen->screen_name, screen->xroot);
626
627 return screen;
628}
629
630void
631meta_screen_free (MetaScreen *screen,
632 guint32 timestamp)
633{
634 MetaDisplay *display;
635 XGCValues gc_values = { 0 };
636
637 display = screen->display;
638
639 screen->closing += 1;
640
641 meta_display_grab (display);
642
643 if (screen->display->compositor)
644 {
645 meta_compositor_unmanage_screen (screen->display->compositor,
646 screen);
647 }
648
649 meta_display_unmanage_windows_for_screen (display, screen, timestamp);
650
651 meta_prefs_remove_listener (prefs_changed_callback, screen);
652
653 meta_screen_ungrab_keys (screen);
654
655#ifdef HAVE_STARTUP_NOTIFICATION
656 g_slist_free_full (screen->startup_sequences,
657 (GDestroyNotify) sn_startup_sequence_unref);
658 screen->startup_sequences = NULL((void*)0);
659
660 if (screen->startup_sequence_timeout != 0)
661 {
662 g_source_remove (screen->startup_sequence_timeout);
663 screen->startup_sequence_timeout = 0;
664 }
665 if (screen->sn_context)
666 {
667 sn_monitor_context_unref (screen->sn_context);
668 screen->sn_context = NULL((void*)0);
669 }
670#endif
671
672 meta_ui_free (screen->ui);
673
674 meta_stack_free (screen->stack);
675
676 meta_error_trap_push (screen->display);
677 XSelectInput (screen->display->xdisplay, screen->xroot, 0);
678 if (meta_error_trap_pop_with_return (screen->display, FALSE(0)) != Success0)
679 meta_warning (_("Could not release screen %d on display \"%s\"\n")((char *) g_dgettext ("marco", "Could not release screen %d on display \"%s\"\n"
))
,
680 screen->number, screen->display->name);
681
682 unset_wm_check_hint (screen);
683
684 XDestroyWindow (screen->display->xdisplay,
685 screen->wm_sn_selection_window);
686
687 if (screen->work_area_idle != 0)
688 g_source_remove (screen->work_area_idle);
689
690 if (XGetGCValues (screen->display->xdisplay,
691 screen->root_xor_gc,
692 GCFont(1L<<14),
693 &gc_values))
694 {
695 XUnloadFont (screen->display->xdisplay,
696 gc_values.font);
697 }
698
699 XFreeGC (screen->display->xdisplay,
700 screen->root_xor_gc);
701
702 if (screen->xinerama_infos)
703 g_free (screen->xinerama_infos);
704
705 if (screen->tile_preview_timeout_id)
706 g_source_remove (screen->tile_preview_timeout_id);
707
708 if (screen->tile_preview)
709 meta_tile_preview_free (screen->tile_preview);
710
711 g_free (screen->screen_name);
712 g_free (screen);
713
714 XFlush (display->xdisplay);
715 meta_display_ungrab (display);
716}
717
718typedef struct
719{
720 Window xwindow;
721 XWindowAttributes attrs;
722} WindowInfo;
723
724static GList *
725list_windows (MetaScreen *screen)
726{
727 Window ignored1, ignored2;
728 Window *children;
729 guint n_children, i;
730 GList *result;
731
732 XQueryTree (screen->display->xdisplay,
733 screen->xroot,
734 &ignored1, &ignored2, &children, &n_children);
735
736 result = NULL((void*)0);
737 for (i = 0; i < n_children; ++i)
738 {
739 WindowInfo *info = g_new0 (WindowInfo, 1)((WindowInfo *) g_malloc0_n ((1), sizeof (WindowInfo)));
740
741 meta_error_trap_push (screen->display);
742
743 XGetWindowAttributes (screen->display->xdisplay,
744 children[i], &info->attrs);
745
746 if (meta_error_trap_pop_with_return (screen->display, TRUE(!(0))))
747 {
748 meta_verbosemeta_verbose_real ("Failed to get attributes for window 0x%lx\n",
749 children[i]);
750 g_free (info);
751 }
752 else
753 {
754 info->xwindow = children[i];
755 result = g_list_prepend (result, info);
756 }
757 }
758
759 if (children)
760 XFree (children);
761
762 return g_list_reverse (result);
763}
764
765void
766meta_screen_manage_all_windows (MetaScreen *screen)
767{
768 GList *windows;
769 GList *list;
770
771 meta_display_grab (screen->display);
772
773 windows = list_windows (screen);
774
775 meta_stack_freeze (screen->stack);
776 for (list = windows; list != NULL((void*)0); list = list->next)
777 {
778 WindowInfo *info = list->data;
779 MetaWindow *window;
780 gboolean test_window_owner;
781
782 window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE(!(0)),
783 &info->attrs);
784 test_window_owner = info->xwindow == screen->no_focus_window ||
785 info->xwindow == screen->flash_window ||
786 info->xwindow == screen->wm_sn_selection_window;
787
788#ifdef HAVE_COMPOSITE_EXTENSIONS1
789 test_window_owner = test_window_owner || info->xwindow == screen->wm_cm_selection_window;
790#endif
791 if (test_window_owner)
792 {
793 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
794 continue;
795 }
796
797 if (screen->display->compositor)
798 meta_compositor_add_window (screen->display->compositor, window,
799 info->xwindow, &info->attrs);
800 }
801 meta_stack_thaw (screen->stack);
802
803 g_list_free_full (windows, g_free);
804
805 meta_display_ungrab (screen->display);
806}
807
808void
809meta_screen_composite_all_windows (MetaScreen *screen)
810{
811#ifdef HAVE_COMPOSITE_EXTENSIONS1
812 MetaDisplay *display;
813 GList *windows, *list;
814
815 display = screen->display;
816 if (!display->compositor)
817 return;
818
819 windows = list_windows (screen);
820
821 meta_stack_freeze (screen->stack);
822
823 for (list = windows; list != NULL((void*)0); list = list->next)
824 {
825 WindowInfo *info = list->data;
826
827 if (info->xwindow == screen->no_focus_window ||
828 info->xwindow == screen->flash_window ||
829 info->xwindow == screen->wm_sn_selection_window ||
830 info->xwindow == screen->wm_cm_selection_window) {
831 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
832 continue;
833 }
834
835 meta_compositor_add_window (display->compositor,
836 meta_display_lookup_x_window (display,
837 info->xwindow),
838 info->xwindow, &info->attrs);
839 }
840
841 meta_stack_thaw (screen->stack);
842
843 g_list_free_full (windows, g_free);
844#endif
845}
846
847MetaScreen*
848meta_screen_for_x_screen (Screen *xscreen)
849{
850 MetaDisplay *display;
851
852 display = meta_display_for_x_display (DisplayOfScreen (xscreen)((xscreen)->display));
853
854 if (display == NULL((void*)0))
855 return NULL((void*)0);
856
857 return meta_display_screen_for_x_screen (display, xscreen);
858}
859
860static void
861prefs_changed_callback (MetaPreference pref,
862 gpointer data)
863{
864 MetaScreen *screen = data;
865
866 if (pref == META_PREF_NUM_WORKSPACES)
867 {
868 /* GSettings doesn't provide timestamps, but luckily update_num_workspaces
869 * often doesn't need it...
870 */
871 guint32 timestamp =
872 meta_display_get_current_time_roundtrip (screen->display);
873 update_num_workspaces (screen, timestamp);
874 }
875 else if (pref == META_PREF_FOCUS_MODE)
876 {
877 update_focus_mode (screen);
878 }
879 else if (pref == META_PREF_WORKSPACE_NAMES)
880 {
881 set_workspace_names (screen);
882 }
883}
884
885static char*
886get_screen_name (MetaDisplay *display,
887 int number)
888{
889 char *p;
890 char *dname;
891 char *scr;
892
893 /* DisplayString gives us a sort of canonical display,
894 * vs. the user-entered name from XDisplayName()
895 */
896 dname = g_strdup (DisplayString (display->xdisplay))g_strdup_inline ((((_XPrivDisplay)(display->xdisplay))->
display_name))
;
897
898 /* Change display name to specify this screen.
899 */
900 p = strrchr (dname, ':');
901 if (p)
902 {
903 p = strchr (p, '.');
904 if (p)
905 *p = '\0';
906 }
907
908 scr = g_strdup_printf ("%s.%d", dname, number);
909
910 g_free (dname);
911
912 return scr;
913}
914
915static gint
916ptrcmp (gconstpointer a, gconstpointer b)
917{
918 if (a < b)
919 return -1;
920 else if (a > b)
921 return 1;
922 else
923 return 0;
924}
925
926static void
927listify_func (gpointer key, gpointer value, gpointer data)
928{
929 GSList **listp;
930
931 listp = data;
932
933 *listp = g_slist_prepend (*listp, value);
934}
935
936void
937meta_screen_foreach_window (MetaScreen *screen,
938 MetaScreenWindowFunc func,
939 gpointer data)
940{
941 GSList *winlist;
942 GSList *tmp;
943
944 /* If we end up doing this often, just keeping a list
945 * of windows might be sensible.
946 */
947
948 winlist = NULL((void*)0);
949 g_hash_table_foreach (screen->display->window_ids,
950 listify_func,
951 &winlist);
952
953 winlist = g_slist_sort (winlist, ptrcmp);
954
955 tmp = winlist;
956 while (tmp != NULL((void*)0))
957 {
958 /* If the next node doesn't contain this window
959 * a second time, delete the window.
960 */
961 if (tmp->next == NULL((void*)0) ||
962 (tmp->next && tmp->next->data != tmp->data))
963 {
964 MetaWindow *window = tmp->data;
965
966 if (window->screen == screen)
967 (* func) (screen, window, data);
968 }
969
970 tmp = tmp->next;
971 }
972 g_slist_free (winlist);
973}
974
975static void
976queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
977{
978 if (window->frame)
979 meta_frame_queue_draw (window->frame);
980}
981
982void
983meta_screen_queue_frame_redraws (MetaScreen *screen)
984{
985 meta_screen_foreach_window (screen, queue_draw, NULL((void*)0));
986}
987
988static void
989queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
990{
991 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
992}
993
994void
995meta_screen_queue_window_resizes (MetaScreen *screen)
996{
997 meta_screen_foreach_window (screen, queue_resize, NULL((void*)0));
998}
999
1000int
1001meta_screen_get_n_workspaces (MetaScreen *screen)
1002{
1003 return g_list_length (screen->workspaces);
1004}
1005
1006MetaWorkspace*
1007meta_screen_get_workspace_by_index (MetaScreen *screen,
1008 int idx)
1009{
1010 GList *tmp;
1011 int i;
1012
1013 /* should be robust, idx is maybe from an app */
1014 if (idx < 0)
1015 return NULL((void*)0);
1016
1017 i = 0;
1018 tmp = screen->workspaces;
1019 while (tmp != NULL((void*)0))
1020 {
1021 MetaWorkspace *w = tmp->data;
1022
1023 if (i == idx)
1024 return w;
1025
1026 ++i;
1027 tmp = tmp->next;
1028 }
1029
1030 return NULL((void*)0);
1031}
1032
1033static void
1034set_number_of_spaces_hint (MetaScreen *screen,
1035 int n_spaces)
1036{
1037 unsigned long data[1];
1038
1039 if (screen->closing > 0)
1040 return;
1041
1042 data[0] = n_spaces;
1043
1044 meta_verbosemeta_verbose_real ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
1045
1046 meta_error_trap_push (screen->display);
1047 XChangeProperty (screen->display->xdisplay, screen->xroot,
1048 screen->display->atom__NET_NUMBER_OF_DESKTOPS,
1049 XA_CARDINAL((Atom) 6),
1050 32, PropModeReplace0, (guchar*) data, 1);
1051 meta_error_trap_pop (screen->display, FALSE(0));
1052}
1053
1054static void
1055set_desktop_geometry_hint (MetaScreen *screen)
1056{
1057 unsigned long data[2];
1058
1059 if (screen->closing > 0)
1060 return;
1061
1062 data[0] = screen->rect.width;
1063 data[1] = screen->rect.height;
1064
1065 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
1066
1067 meta_error_trap_push (screen->display);
1068 XChangeProperty (screen->display->xdisplay, screen->xroot,
1069 screen->display->atom__NET_DESKTOP_GEOMETRY,
1070 XA_CARDINAL((Atom) 6),
1071 32, PropModeReplace0, (guchar*) data, 2);
1072 meta_error_trap_pop (screen->display, FALSE(0));
1073}
1074
1075static void
1076set_desktop_viewport_hint (MetaScreen *screen)
1077{
1078 unsigned long data[2];
1079
1080 if (screen->closing > 0)
1081 return;
1082
1083 /*
1084 * Marco does not implement viewports, so this is a fixed 0,0
1085 */
1086 data[0] = 0;
1087 data[1] = 0;
1088
1089 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
1090
1091 meta_error_trap_push (screen->display);
1092 XChangeProperty (screen->display->xdisplay, screen->xroot,
1093 screen->display->atom__NET_DESKTOP_VIEWPORT,
1094 XA_CARDINAL((Atom) 6),
1095 32, PropModeReplace0, (guchar*) data, 2);
1096 meta_error_trap_pop (screen->display, FALSE(0));
1097}
1098
1099static void
1100update_num_workspaces (MetaScreen *screen,
1101 guint32 timestamp)
1102{
1103 int new_num;
1104 GList *tmp;
1105 int i;
1106 GList *extras;
1107 MetaWorkspace *last_remaining;
1108 gboolean need_change_space;
1109
1110 new_num = meta_prefs_get_num_workspaces ();
1111
1112 g_assert (new_num > 0)do { if (new_num > 0) ; else g_assertion_message_expr ("marco"
, "core/screen.c", 1112, ((const char*) (__func__)), "new_num > 0"
); } while (0)
;
1113
1114 last_remaining = NULL((void*)0);
1115 extras = NULL((void*)0);
1116 i = 0;
1117 tmp = screen->workspaces;
1118 while (tmp != NULL((void*)0))
1119 {
1120 MetaWorkspace *w = tmp->data;
1121
1122 if (i >= new_num)
1123 extras = g_list_prepend (extras, w);
1124 else
1125 last_remaining = w;
1126
1127 ++i;
1128 tmp = tmp->next;
1129 }
1130
1131 g_assert (last_remaining)do { if (last_remaining) ; else g_assertion_message_expr ("marco"
, "core/screen.c", 1131, ((const char*) (__func__)), "last_remaining"
); } while (0)
;
1132
1133 /* Get rid of the extra workspaces by moving all their windows
1134 * to last_remaining, then activating last_remaining if
1135 * one of the removed workspaces was active. This will be a bit
1136 * wacky if the config tool for changing number of workspaces
1137 * is on a removed workspace ;-)
1138 */
1139 need_change_space = FALSE(0);
1140 tmp = extras;
1141 while (tmp != NULL((void*)0))
1142 {
1143 MetaWorkspace *w = tmp->data;
1144
1145 meta_workspace_relocate_windows (w, last_remaining);
1146
1147 if (w == screen->active_workspace)
1148 need_change_space = TRUE(!(0));
1149
1150 tmp = tmp->next;
1151 }
1152
1153 if (need_change_space)
1154 meta_workspace_activate (last_remaining, timestamp);
1155
1156 /* Should now be safe to free the workspaces */
1157 tmp = extras;
1158 while (tmp != NULL((void*)0))
1159 {
1160 MetaWorkspace *w = tmp->data;
1161
1162 g_assert (w->windows == NULL)do { if (w->windows == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 1162, ((const char*) (__func__)),
"w->windows == NULL"); } while (0)
;
1163 meta_workspace_free (w);
1164
1165 tmp = tmp->next;
1166 }
1167
1168 g_list_free (extras);
1169
1170 while (i < new_num)
1171 {
1172 meta_workspace_new (screen);
1173 ++i;
1174 }
1175
1176 set_number_of_spaces_hint (screen, new_num);
1177
1178 meta_screen_queue_workarea_recalc (screen);
1179}
1180
1181static void
1182update_focus_mode (MetaScreen *screen)
1183{
1184 /* nothing to do anymore */ ;
1185}
1186
1187void
1188meta_screen_set_cursor (MetaScreen *screen,
1189 MetaCursor cursor)
1190{
1191 Cursor xcursor;
1192
1193 if (cursor == screen->current_cursor)
1194 return;
1195
1196 screen->current_cursor = cursor;
1197
1198 xcursor = meta_display_create_x_cursor (screen->display, cursor);
1199 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1200 XFlush (screen->display->xdisplay);
1201 XFreeCursor (screen->display->xdisplay, xcursor);
1202}
1203
1204void
1205meta_screen_update_cursor (MetaScreen *screen)
1206{
1207 Cursor xcursor;
1208
1209 xcursor = meta_display_create_x_cursor (screen->display,
1210 screen->current_cursor);
1211 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1212 XFlush (screen->display->xdisplay);
1213 XFreeCursor (screen->display->xdisplay, xcursor);
1214}
1215
1216#define MAX_PREVIEW_SCREEN_FRACTION0.33 0.33
1217#define MAX_PREVIEW_SIZE300.0 300.0
1218
1219static cairo_surface_t *
1220get_window_surface (MetaWindow *window)
1221{
1222 cairo_surface_t *surface, *scaled;
1223 cairo_t *cr;
1224 const MetaXineramaScreenInfo *current;
1225 int width, height, max_columns;
1226 double max_size;
1227 double ratio;
1228
1229 surface = meta_compositor_get_window_surface (window->display->compositor, window);
1230
1231 if (surface == NULL((void*)0))
1232 return NULL((void*)0);
1233
1234 width = cairo_xlib_surface_get_width (surface);
1235 height = cairo_xlib_surface_get_height (surface);
1236
1237 current = meta_screen_get_current_xinerama (window->screen);
1238 max_columns = meta_prefs_get_alt_tab_max_columns ();
1239
1240 /* Scale surface to fit current screen */
1241 if (width > height)
1242 {
1243 max_size = MIN (MAX_PREVIEW_SIZE, MAX_PREVIEW_SCREEN_FRACTION * ((double) current->rect.width) / ((double) max_columns))(((300.0) < (0.33 * ((double) current->rect.width) / ((
double) max_columns))) ? (300.0) : (0.33 * ((double) current->
rect.width) / ((double) max_columns)))
;
1244 ratio = ((double) width) / max_size;
1245 width = (int) max_size;
1246 height = (int) (((double) height) / ratio);
1247 }
1248 else
1249 {
1250 max_size = MIN (MAX_PREVIEW_SIZE, MAX_PREVIEW_SCREEN_FRACTION * ((double) current->rect.height) / ((double) max_columns))(((300.0) < (0.33 * ((double) current->rect.height) / (
(double) max_columns))) ? (300.0) : (0.33 * ((double) current
->rect.height) / ((double) max_columns)))
;
1251 ratio = ((double) height) / max_size;
1252 height = (int) max_size;
1253 width = (int) (((double) width) / ratio);
1254 }
1255
1256 meta_error_trap_push (window->display);
1257 scaled = cairo_surface_create_similar (surface,
1258 cairo_surface_get_content (surface),
1259 width, height);
1260 if (meta_error_trap_pop_with_return (window->display, FALSE(0)) != Success0)
1261 return NULL((void*)0);
1262
1263 cr = cairo_create (scaled);
1264 cairo_scale (cr, 1/ratio, 1/ratio);
1265 cairo_set_source_surface (cr, surface, 0, 0);
1266 cairo_paint (cr);
1267
1268 cairo_destroy (cr);
1269 cairo_surface_destroy (surface);
1270
1271 return scaled;
1272}
1273
1274void
1275meta_screen_ensure_tab_popup (MetaScreen *screen,
1276 MetaTabList list_type,
1277 MetaTabShowType show_type)
1278{
1279 MetaTabEntry *entries;
1280 GList *tab_list;
1281 GList *tmp;
1282 int len;
1283 int i;
1284 gint border;
1285 int scale;
1286
1287 if (screen->tab_popup)
1288 return;
1289
1290 tab_list = meta_display_get_tab_list (screen->display,
1291 list_type,
1292 screen,
1293 screen->active_workspace);
1294
1295 len = g_list_length (tab_list);
1296 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
1297
1298 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1299 entries[len].key = NULL((void*)0);
1300 entries[len].title = NULL((void*)0);
1301 entries[len].icon = NULL((void*)0);
1302 entries[len].win_surface = NULL((void*)0);
1303
1304 border = meta_prefs_show_tab_border() ? BORDER_OUTLINE_TAB |
1305 BORDER_OUTLINE_WINDOW : BORDER_OUTLINE_TAB;
1306 i = 0;
1307 tmp = tab_list;
1308 while (i < len)
1309 {
1310 MetaWindow *window;
1311 MetaRectangle r;
1312
1313 window = tmp->data;
1314
1315 entries[i].key = (MetaTabEntryKey) window->xwindow;
1316 entries[i].title = window->title;
1317 entries[i].win_surface = NULL((void*)0);
1318
1319 entries[i].icon = g_object_ref (window->icon)((__typeof__ (window->icon)) (g_object_ref) (window->icon
))
;
1320
1321 /* Only get the window thumbnail surface if the user has a compositor
1322 * enabled and does NOT have compositing-fast-alt-tab-set to true in
1323 * GSettings. There is an obvious lag when the surface is retrieved. */
1324 if (meta_prefs_get_compositing_manager() && !meta_prefs_get_compositing_fast_alt_tab())
1325 {
1326 cairo_surface_t *win_surface;
1327
1328 /* Get window thumbnail */
1329 win_surface = get_window_surface (window);
1330
1331 if (win_surface != NULL((void*)0))
1332 {
1333 cairo_surface_t *surface, *icon;
1334 cairo_t *cr;
1335 int width, height, icon_width, icon_height;
1336
1337#define ICON_OFFSET6 6
1338
1339 width = cairo_xlib_surface_get_width (win_surface);
1340 height = cairo_xlib_surface_get_height (win_surface);
1341
1342 /* Create a new surface to overlap the window icon into */
1343 surface = cairo_surface_create_similar (win_surface,
1344 cairo_surface_get_content (win_surface),
1345 width, height);
1346
1347 cr = cairo_create (surface);
1348 cairo_set_source_surface (cr, win_surface, 0, 0);
1349 cairo_paint (cr);
1350
1351 /* Get the window icon as a surface */
1352 icon = gdk_cairo_surface_create_from_pixbuf (window->icon, scale, NULL((void*)0));
1353
1354 icon_width = cairo_image_surface_get_width (icon) / scale;
1355 icon_height = cairo_image_surface_get_height (icon) / scale;
1356
1357 /* Overlap the window icon surface over the window thumbnail */
1358 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
1359 cairo_set_source_surface (cr, icon,
1360 width - icon_width - ICON_OFFSET6,
1361 height - icon_height - ICON_OFFSET6);
1362 cairo_paint (cr);
1363
1364 entries[i].win_surface = surface;
1365
1366 cairo_destroy (cr);
1367 cairo_surface_destroy (icon);
1368 cairo_surface_destroy (win_surface);
1369 }
1370 }
1371
1372 entries[i].blank = FALSE(0);
1373 entries[i].hidden = !meta_window_showing_on_its_workspace (window);
1374 entries[i].demands_attention = window->wm_state_demands_attention;
1375
1376 if (show_type == META_TAB_SHOW_INSTANTLY ||
1377 !entries[i].hidden ||
1378 !meta_window_get_icon_geometry (window, &r))
1379 meta_window_get_outer_rect (window, &r);
1380
1381 entries[i].rect = r;
1382
1383 /* Find inside of highlight rectangle to be used when window is
1384 * outlined for tabbing. This should be the size of the
1385 * east/west frame, and the size of the south frame, on those
1386 * sides. On the top it should be the size of the south frame
1387 * edge.
1388 */
1389 if (border & BORDER_OUTLINE_WINDOW)
1390 {
1391#define OUTLINE_WIDTH5 5
1392 /* Top side */
1393 entries[i].inner_rect.y = OUTLINE_WIDTH5;
1394
1395 /* Bottom side */
1396 entries[i].inner_rect.height = r.height - entries[i].inner_rect.y - OUTLINE_WIDTH5;
1397
1398 /* Left side */
1399 entries[i].inner_rect.x = OUTLINE_WIDTH5;
1400
1401 /* Right side */
1402 entries[i].inner_rect.width = r.width - entries[i].inner_rect.x - OUTLINE_WIDTH5;
1403 }
1404
1405 ++i;
1406 tmp = tmp->next;
1407 }
1408
1409 screen->tab_popup = meta_ui_tab_popup_new (entries,
1410 screen,
1411 len,
1412 meta_prefs_get_alt_tab_max_columns(),
1413 meta_prefs_get_alt_tab_expand_to_fit_title(),
1414 border);
1415
1416 for (i = 0; i < len; i++)
1417 {
1418 g_object_unref (entries[i].icon);
1419 if (entries[i].win_surface)
1420 cairo_surface_destroy (entries[i].win_surface);
1421 }
1422
1423 g_free (entries);
1424
1425 g_list_free (tab_list);
1426
1427 /* don't show tab popup, since proper window isn't selected yet */
1428}
1429
1430void
1431meta_screen_ensure_workspace_popup (MetaScreen *screen)
1432{
1433 MetaTabEntry *entries;
1434 int len;
1435 int i;
1436 MetaWorkspaceLayout layout;
1437 int n_workspaces;
1438 int current_workspace;
1439
1440 if (screen->tab_popup)
1441 return;
1442
1443 current_workspace = meta_workspace_index (screen->active_workspace);
1444 n_workspaces = meta_screen_get_n_workspaces (screen);
1445
1446 meta_screen_calc_workspace_layout (screen, n_workspaces,
1447 current_workspace, &layout);
1448
1449 len = layout.grid_area;
1450
1451 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1452 entries[len].key = NULL((void*)0);
1453 entries[len].title = NULL((void*)0);
1454 entries[len].icon = NULL((void*)0);
1455 entries[len].win_surface = NULL((void*)0);
1456
1457 i = 0;
1458 while (i < len)
1459 {
1460 if (layout.grid[i] >= 0)
1461 {
1462 MetaWorkspace *workspace;
1463
1464 workspace = meta_screen_get_workspace_by_index (screen,
1465 layout.grid[i]);
1466
1467 entries[i].key = (MetaTabEntryKey) workspace;
1468 entries[i].title = meta_workspace_get_name (workspace);
1469 entries[i].icon = NULL((void*)0);
1470 entries[i].win_surface = NULL((void*)0);
1471 entries[i].blank = FALSE(0);
1472
1473 g_assert (entries[i].title != NULL)do { if (entries[i].title != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 1473, ((const char*) (__func__)),
"entries[i].title != NULL"); } while (0)
;
1474 }
1475 else
1476 {
1477 entries[i].key = NULL((void*)0);
1478 entries[i].title = NULL((void*)0);
1479 entries[i].icon = NULL((void*)0);
1480 entries[i].win_surface = NULL((void*)0);
1481 entries[i].blank = TRUE(!(0));
1482 }
1483 entries[i].hidden = FALSE(0);
1484 entries[i].demands_attention = FALSE(0);
1485
1486 ++i;
1487 }
1488
1489 screen->tab_popup = meta_ui_tab_popup_new (entries,
1490 screen,
1491 len,
1492 layout.cols,
1493 FALSE(0), /* expand_for_titles */
1494 BORDER_OUTLINE_WORKSPACE);
1495
1496 g_free (entries);
1497 meta_screen_free_workspace_layout (&layout);
1498
1499 /* don't show tab popup, since proper space isn't selected yet */
1500}
1501
1502static gboolean
1503meta_screen_tile_preview_update_timeout (gpointer data)
1504{
1505 MetaScreen *screen = data;
1506 MetaWindow *window = screen->display->grab_window;
1507 gboolean needs_preview = FALSE(0);
1508
1509 screen->tile_preview_timeout_id = 0;
1510
1511 if (!screen->tile_preview)
1512 screen->tile_preview = meta_tile_preview_new ();
1513
1514 if (window)
1515 {
1516 switch (window->tile_mode)
1517 {
1518 case META_TILE_MAXIMIZED:
1519 if (!META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
)
1520 needs_preview = TRUE(!(0));
1521 break;
1522
1523 case META_TILE_NONE:
1524 needs_preview = FALSE(0);
1525 break;
1526
1527 default:
1528 if (!META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
)
1529 needs_preview = TRUE(!(0));
1530 break;
1531
1532 }
1533 }
1534
1535 if (needs_preview)
1536 {
1537 MetaRectangle tile_rect;
1538
1539 meta_window_get_current_tile_area (window, &tile_rect);
1540 meta_tile_preview_show (screen->tile_preview, &tile_rect, screen);
1541 }
1542 else
1543 meta_tile_preview_hide (screen->tile_preview);
1544
1545 return FALSE(0);
1546}
1547
1548#define TILE_PREVIEW_TIMEOUT_MS200 200
1549
1550void
1551meta_screen_tile_preview_update (MetaScreen *screen,
1552 gboolean delay)
1553{
1554 if (delay)
1555 {
1556 if (screen->tile_preview_timeout_id > 0)
1557 return;
1558
1559 screen->tile_preview_timeout_id =
1560 g_timeout_add (TILE_PREVIEW_TIMEOUT_MS200,
1561 meta_screen_tile_preview_update_timeout,
1562 screen);
1563 }
1564 else
1565 {
1566 if (screen->tile_preview_timeout_id > 0)
1567 g_source_remove (screen->tile_preview_timeout_id);
1568
1569 meta_screen_tile_preview_update_timeout ((gpointer)screen);
1570 }
1571}
1572
1573void
1574meta_screen_tile_preview_hide (MetaScreen *screen)
1575{
1576 if (screen->tile_preview_timeout_id > 0)
1577 g_source_remove (screen->tile_preview_timeout_id);
1578
1579 if (screen->tile_preview)
1580 meta_tile_preview_hide (screen->tile_preview);
1581}
1582
1583MetaWindow*
1584meta_screen_get_mouse_window (MetaScreen *screen,
1585 MetaWindow *not_this_one)
1586{
1587 MetaWindow *window;
1588 Window root_return, child_return;
1589 int root_x_return, root_y_return;
1590 int win_x_return, win_y_return;
1591 unsigned int mask_return;
1592
1593 if (not_this_one)
1594 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1595 "Focusing mouse window excluding %s\n", not_this_one->desc);
1596
1597 meta_error_trap_push (screen->display);
1598 XQueryPointer (screen->display->xdisplay,
1599 screen->xroot,
1600 &root_return,
1601 &child_return,
1602 &root_x_return,
1603 &root_y_return,
1604 &win_x_return,
1605 &win_y_return,
1606 &mask_return);
1607 meta_error_trap_pop (screen->display, TRUE(!(0)));
1608
1609 window = meta_stack_get_default_focus_window_at_point (screen->stack,
1610 screen->active_workspace,
1611 not_this_one,
1612 root_x_return,
1613 root_y_return);
1614
1615 return window;
1616}
1617
1618const MetaXineramaScreenInfo*
1619meta_screen_get_xinerama_for_rect (MetaScreen *screen,
1620 MetaRectangle *rect)
1621{
1622 int i;
1623 int best_xinerama, xinerama_score;
1624
1625 if (screen->n_xinerama_infos == 1)
1626 return &screen->xinerama_infos[0];
1627
1628 best_xinerama = 0;
1629 xinerama_score = 0;
1630
1631 for (i = 0; i < screen->n_xinerama_infos; i++)
1632 {
1633 MetaRectangle dest;
1634 if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
1635 rect,
1636 &dest))
1637 {
1638 int cur = meta_rectangle_area (&dest);
1639 if (cur > xinerama_score)
1640 {
1641 xinerama_score = cur;
1642 best_xinerama = i;
1643 }
1644 }
1645 }
1646
1647 return &screen->xinerama_infos[best_xinerama];
1648}
1649
1650const MetaXineramaScreenInfo*
1651meta_screen_get_xinerama_for_window (MetaScreen *screen,
1652 MetaWindow *window)
1653{
1654 MetaRectangle window_rect;
1655
1656 meta_window_get_outer_rect (window, &window_rect);
1657
1658 return meta_screen_get_xinerama_for_rect (screen, &window_rect);
1659}
1660
1661const MetaXineramaScreenInfo*
1662meta_screen_get_xinerama_neighbor (MetaScreen *screen,
1663 int which_xinerama,
1664 MetaScreenDirection direction)
1665{
1666 MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
1667 MetaXineramaScreenInfo* current;
1668 int i;
1669
1670 for (i = 0; i < screen->n_xinerama_infos; i++)
1671 {
1672 current = screen->xinerama_infos + i;
1673
1674 if ((direction == META_SCREEN_RIGHT &&
1675 current->rect.x == input->rect.x + input->rect.width &&
1676 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1677 (direction == META_SCREEN_LEFT &&
1678 input->rect.x == current->rect.x + current->rect.width &&
1679 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1680 (direction == META_SCREEN_UP &&
1681 input->rect.y == current->rect.y + current->rect.height &&
1682 meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
1683 (direction == META_SCREEN_DOWN &&
1684 current->rect.y == input->rect.y + input->rect.height &&
1685 meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
1686 {
1687 return current;
1688 }
1689 }
1690
1691 return NULL((void*)0);
1692}
1693
1694void
1695meta_screen_get_natural_xinerama_list (MetaScreen *screen,
1696 int** xineramas_list,
1697 int* n_xineramas)
1698{
1699 const MetaXineramaScreenInfo* current;
1700 const MetaXineramaScreenInfo* tmp;
1701 GQueue* xinerama_queue;
1702 int* visited;
1703 int cur = 0;
1704 int i;
1705
1706 *n_xineramas = screen->n_xinerama_infos;
1707 *xineramas_list = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1708
1709 /* we calculate a natural ordering by which to choose xineramas for
1710 * window placement. We start at the current xinerama, and perform
1711 * a breadth-first search of the xineramas starting from that
1712 * xinerama. We choose preferentially left, then right, then down,
1713 * then up. The visitation order produced by this traversal is the
1714 * natural xinerama ordering.
1715 */
1716
1717 visited = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1718 for (i = 0; i < screen->n_xinerama_infos; i++)
1
Assuming 'i' is < field 'n_xinerama_infos'
2
Loop condition is true. Entering loop body
3
Assuming 'i' is < field 'n_xinerama_infos'
4
Loop condition is true. Entering loop body
5
Assuming 'i' is < field 'n_xinerama_infos'
6
Loop condition is true. Entering loop body
7
Assuming 'i' is >= field 'n_xinerama_infos'
8
Loop condition is false. Execution continues on line 1723
1719 {
1720 visited[i] = FALSE(0);
1721 }
1722
1723 current = meta_screen_get_current_xinerama (screen);
1724 xinerama_queue = g_queue_new ();
1725 g_queue_push_tail (xinerama_queue, (gpointer) current);
1726 visited[current->number] = TRUE(!(0));
1727
1728 while (!g_queue_is_empty (xinerama_queue))
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
15
Assuming the condition is false
16
Loop condition is false. Execution continues on line 1777
1729 {
1730 current = (const MetaXineramaScreenInfo*)
1731 g_queue_pop_head (xinerama_queue);
1732
1733 (*xineramas_list)[cur++] = current->number;
1734
1735 /* enqueue each of the directions */
1736 tmp = meta_screen_get_xinerama_neighbor (screen,
1737 current->number,
1738 META_SCREEN_LEFT);
1739 if (tmp && !visited[tmp->number])
11
Assuming 'tmp' is null
1740 {
1741 g_queue_push_tail (xinerama_queue,
1742 (MetaXineramaScreenInfo*) tmp);
1743 visited[tmp->number] = TRUE(!(0));
1744 }
1745 tmp = meta_screen_get_xinerama_neighbor (screen,
1746 current->number,
1747 META_SCREEN_RIGHT);
1748 if (tmp && !visited[tmp->number])
12
Assuming 'tmp' is null
1749 {
1750 g_queue_push_tail (xinerama_queue,
1751 (MetaXineramaScreenInfo*) tmp);
1752 visited[tmp->number] = TRUE(!(0));
1753 }
1754 tmp = meta_screen_get_xinerama_neighbor (screen,
1755 current->number,
1756 META_SCREEN_UP);
1757 if (tmp && !visited[tmp->number])
13
Assuming 'tmp' is null
1758 {
1759 g_queue_push_tail (xinerama_queue,
1760 (MetaXineramaScreenInfo*) tmp);
1761 visited[tmp->number] = TRUE(!(0));
1762 }
1763 tmp = meta_screen_get_xinerama_neighbor (screen,
1764 current->number,
1765 META_SCREEN_DOWN);
1766 if (tmp && !visited[tmp->number])
14
Assuming 'tmp' is null
1767 {
1768 g_queue_push_tail (xinerama_queue,
1769 (MetaXineramaScreenInfo*) tmp);
1770 visited[tmp->number] = TRUE(!(0));
1771 }
1772 }
1773
1774 /* in case we somehow missed some set of xineramas, go through the
1775 * visited list and add in any xineramas that were missed
1776 */
1777 for (i = 0; i < screen->n_xinerama_infos; i++)
17
Assuming 'i' is < field 'n_xinerama_infos'
18
Loop condition is true. Entering loop body
21
Assuming 'i' is < field 'n_xinerama_infos'
22
Loop condition is true. Entering loop body
25
Assuming 'i' is < field 'n_xinerama_infos'
26
Loop condition is true. Entering loop body
1778 {
1779 if (visited[i] == FALSE(0))
19
Assuming the condition is true
20
Taking true branch
23
Assuming the condition is true
24
Taking true branch
27
Assuming the condition is true
28
Taking true branch
1780 {
1781 (*xineramas_list)[cur++] = i;
29
Out of bound memory access (access exceeds upper limit of memory block)
1782 }
1783 }
1784
1785 g_free (visited);
1786 g_queue_free (xinerama_queue);
1787}
1788
1789const MetaXineramaScreenInfo*
1790meta_screen_get_current_xinerama (MetaScreen *screen)
1791{
1792 if (screen->n_xinerama_infos == 1)
1793 return &screen->xinerama_infos[0];
1794
1795 /* Sadly, we have to do it this way. Yuck.
1796 */
1797
1798 if (screen->display->xinerama_cache_invalidated)
1799 {
1800 Window root_return, child_return;
1801 int win_x_return, win_y_return;
1802 unsigned int mask_return;
1803 int i;
1804 MetaRectangle pointer_position;
1805
1806 screen->display->xinerama_cache_invalidated = FALSE(0);
1807
1808 pointer_position.width = pointer_position.height = 1;
1809 XQueryPointer (screen->display->xdisplay,
1810 screen->xroot,
1811 &root_return,
1812 &child_return,
1813 &pointer_position.x,
1814 &pointer_position.y,
1815 &win_x_return,
1816 &win_y_return,
1817 &mask_return);
1818
1819 screen->last_xinerama_index = 0;
1820 for (i = 0; i < screen->n_xinerama_infos; i++)
1821 {
1822 if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
1823 &pointer_position))
1824 {
1825 screen->last_xinerama_index = i;
1826 break;
1827 }
1828 }
1829
1830 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
1831 "Rechecked current Xinerama, now %d\n",
1832 screen->last_xinerama_index);
1833 }
1834
1835 return &screen->xinerama_infos[screen->last_xinerama_index];
1836}
1837
1838#define _NET_WM_ORIENTATION_HORZ0 0
1839#define _NET_WM_ORIENTATION_VERT1 1
1840
1841#define _NET_WM_TOPLEFT0 0
1842#define _NET_WM_TOPRIGHT1 1
1843#define _NET_WM_BOTTOMRIGHT2 2
1844#define _NET_WM_BOTTOMLEFT3 3
1845
1846void
1847meta_screen_update_workspace_layout (MetaScreen *screen)
1848{
1849 gulong *list;
1850 int n_items;
1851
1852 list = NULL((void*)0);
1853 n_items = 0;
1854
1855 if (meta_prop_get_cardinal_list (screen->display,
1856 screen->xroot,
1857 screen->display->atom__NET_DESKTOP_LAYOUT,
1858 &list, &n_items))
1859 {
1860 if (n_items == 3 || n_items == 4)
1861 {
1862 int cols, rows;
1863
1864 switch (list[0])
1865 {
1866 case _NET_WM_ORIENTATION_HORZ0:
1867 screen->vertical_workspaces = FALSE(0);
1868 break;
1869 case _NET_WM_ORIENTATION_VERT1:
1870 screen->vertical_workspaces = TRUE(!(0));
1871 break;
1872 default:
1873 meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
1874 break;
1875 }
1876
1877 cols = list[1];
1878 rows = list[2];
1879
1880 if (rows <= 0 && cols <= 0)
1881 {
1882 meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
1883 }
1884 else
1885 {
1886 if (rows > 0)
1887 screen->rows_of_workspaces = rows;
1888 else
1889 screen->rows_of_workspaces = -1;
1890
1891 if (cols > 0)
1892 screen->columns_of_workspaces = cols;
1893 else
1894 screen->columns_of_workspaces = -1;
1895 }
1896
1897 if (n_items == 4)
1898 {
1899 switch (list[3])
1900 {
1901 case _NET_WM_TOPLEFT0:
1902 screen->starting_corner = META_SCREEN_TOPLEFT;
1903 break;
1904 case _NET_WM_TOPRIGHT1:
1905 screen->starting_corner = META_SCREEN_TOPRIGHT;
1906 break;
1907 case _NET_WM_BOTTOMRIGHT2:
1908 screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
1909 break;
1910 case _NET_WM_BOTTOMLEFT3:
1911 screen->starting_corner = META_SCREEN_BOTTOMLEFT;
1912 break;
1913 default:
1914 meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
1915 break;
1916 }
1917 }
1918 else
1919 screen->starting_corner = META_SCREEN_TOPLEFT;
1920 }
1921 else
1922 {
1923 meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
1924 "(3 is accepted for backwards compat)\n", n_items);
1925 }
1926
1927 meta_XFree (list)do { if ((list)) XFree ((list)); } while (0);
1928 }
1929
1930 meta_verbosemeta_verbose_real ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
1931 screen->rows_of_workspaces,
1932 screen->columns_of_workspaces,
1933 screen->vertical_workspaces,
1934 screen->starting_corner);
1935}
1936
1937static void
1938set_workspace_names (MetaScreen *screen)
1939{
1940 /* This updates names on root window when the pref changes,
1941 * note we only get prefs change notify if things have
1942 * really changed.
1943 */
1944 GString *flattened;
1945 int i;
1946 int n_spaces;
1947
1948 /* flatten to nul-separated list */
1949 n_spaces = meta_screen_get_n_workspaces (screen);
1950 flattened = g_string_new ("");
1951 i = 0;
1952 while (i < n_spaces)
1953 {
1954 const char *name;
1955
1956 name = meta_prefs_get_workspace_name (i);
1957
1958 if (name)
1959 g_string_append_len (flattened, name,g_string_append_len_inline (flattened, name, strlen (name) + 1
)
1960 strlen (name) + 1)g_string_append_len_inline (flattened, name, strlen (name) + 1
)
;
1961 else
1962 g_string_append_len (flattened, "", 1)g_string_append_len_inline (flattened, "", 1);
1963
1964 ++i;
1965 }
1966
1967 meta_error_trap_push (screen->display);
1968 XChangeProperty (screen->display->xdisplay,
1969 screen->xroot,
1970 screen->display->atom__NET_DESKTOP_NAMES,
1971 screen->display->atom_UTF8_STRING,
1972 8, PropModeReplace0,
1973 (unsigned char *)flattened->str, flattened->len);
1974 meta_error_trap_pop (screen->display, FALSE(0));
1975
1976 g_string_free (flattened, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(flattened), ((!(0)))) : g_string_free_and_steal (flattened))
: (g_string_free) ((flattened), ((!(0)))))
;
1977}
1978
1979void
1980meta_screen_update_workspace_names (MetaScreen *screen)
1981{
1982 char **names;
1983 int n_names;
1984 int i;
1985
1986 /* this updates names in prefs when the root window property changes,
1987 * iff the new property contents don't match what's already in prefs
1988 */
1989
1990 names = NULL((void*)0);
1991 n_names = 0;
1992 if (!meta_prop_get_utf8_list (screen->display,
1993 screen->xroot,
1994 screen->display->atom__NET_DESKTOP_NAMES,
1995 &names, &n_names))
1996 {
1997 meta_verbosemeta_verbose_real ("Failed to get workspace names from root window %d\n",
1998 screen->number);
1999 return;
2000 }
2001
2002 i = 0;
2003 while (i < n_names)
2004 {
2005 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2006 "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
2007 i, names[i] ? names[i] : "null");
2008 meta_prefs_change_workspace_name (i, names[i]);
2009
2010 ++i;
2011 }
2012
2013 g_strfreev (names);
2014}
2015
2016Window
2017meta_create_offscreen_window (Display *xdisplay,
2018 Window parent,
2019 long valuemask)
2020{
2021 XSetWindowAttributes attrs;
2022
2023 /* we want to be override redirect because sometimes we
2024 * create a window on a screen we aren't managing.
2025 * (but on a display we are managing at least one screen for)
2026 */
2027 attrs.override_redirect = True1;
2028 attrs.event_mask = valuemask;
2029
2030 return XCreateWindow (xdisplay,
2031 parent,
2032 -100, -100, 1, 1,
2033 0,
2034 CopyFromParent0L,
2035 CopyFromParent0L,
2036 (Visual *)CopyFromParent0L,
2037 CWOverrideRedirect(1L<<9) | CWEventMask(1L<<11),
2038 &attrs);
2039}
2040
2041static void
2042set_workspace_work_area_hint (MetaWorkspace *workspace,
2043 MetaScreen *screen)
2044{
2045 unsigned long *data;
2046 unsigned long *tmp;
2047 int i;
2048 gchar *workarea_name;
2049 Atom workarea_atom;
2050
2051 data = g_new (unsigned long, screen->n_xinerama_infos * 4)((unsigned long *) g_malloc_n ((screen->n_xinerama_infos *
4), sizeof (unsigned long)))
;
2052 tmp = data;
2053
2054 for (i = 0; i < screen->n_xinerama_infos; i++)
2055 {
2056 MetaRectangle area;
2057
2058 meta_workspace_get_work_area_for_xinerama (workspace, i, &area);
2059
2060 tmp[0] = area.x;
2061 tmp[1] = area.y;
2062 tmp[2] = area.width;
2063 tmp[3] = area.height;
2064
2065 tmp += 4;
2066 }
2067
2068 workarea_name = g_strdup_printf ("_GTK_WORKAREAS_D%d",
2069 meta_workspace_index (workspace));
2070
2071 workarea_atom = XInternAtom (screen->display->xdisplay, workarea_name, False0);
2072 g_free (workarea_name);
2073
2074 meta_error_trap_push (screen->display);
2075 XChangeProperty (screen->display->xdisplay, screen->xroot, workarea_atom,
2076 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2077 (guchar*) data, screen->n_xinerama_infos * 4);
2078 meta_error_trap_pop (screen->display, TRUE(!(0)));
2079
2080 g_free (data);
2081}
2082
2083static void
2084set_work_area_hint (MetaScreen *screen)
2085{
2086 int num_workspaces;
2087 GList *tmp_list;
2088 unsigned long *data, *tmp;
2089 MetaRectangle area;
2090
2091 num_workspaces = meta_screen_get_n_workspaces (screen);
2092 data = g_new (unsigned long, num_workspaces * 4)((unsigned long *) g_malloc_n ((num_workspaces * 4), sizeof (
unsigned long)))
;
2093 tmp_list = screen->workspaces;
2094 tmp = data;
2095
2096 while (tmp_list != NULL((void*)0))
2097 {
2098 MetaWorkspace *workspace = tmp_list->data;
2099
2100 if (workspace->screen == screen)
2101 {
2102 meta_workspace_get_work_area_all_xineramas (workspace, &area);
2103 set_workspace_work_area_hint (workspace, screen);
2104 tmp[0] = area.x;
2105 tmp[1] = area.y;
2106 tmp[2] = area.width;
2107 tmp[3] = area.height;
2108
2109 tmp += 4;
2110 }
2111
2112 tmp_list = tmp_list->next;
2113 }
2114
2115 meta_error_trap_push (screen->display);
2116 XChangeProperty (screen->display->xdisplay, screen->xroot,
2117 screen->display->atom__NET_WORKAREA,
2118 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2119 (guchar*) data, num_workspaces*4);
2120 g_free (data);
2121 meta_error_trap_pop (screen->display, FALSE(0));
2122}
2123
2124static gboolean
2125set_work_area_idle_func (MetaScreen *screen)
2126{
2127 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2128 "Running work area idle function\n");
2129
2130 screen->work_area_idle = 0;
2131
2132 set_work_area_hint (screen);
2133
2134 return FALSE(0);
2135}
2136
2137void
2138meta_screen_queue_workarea_recalc (MetaScreen *screen)
2139{
2140 /* Recompute work area in an idle */
2141 if (screen->work_area_idle == 0)
2142 {
2143 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2144 "Adding work area hint idle function\n");
2145 screen->work_area_idle =
2146 g_idle_add_full (META_PRIORITY_WORK_AREA_HINT(200 + 15),
2147 (GSourceFunc) set_work_area_idle_func,
2148 screen,
2149 NULL((void*)0));
2150 }
2151}
2152
2153#ifdef WITH_VERBOSE_MODE1
2154static char *
2155meta_screen_corner_to_string (MetaScreenCorner corner)
2156{
2157 switch (corner)
2158 {
2159 case META_SCREEN_TOPLEFT:
2160 return "TopLeft";
2161 case META_SCREEN_TOPRIGHT:
2162 return "TopRight";
2163 case META_SCREEN_BOTTOMLEFT:
2164 return "BottomLeft";
2165 case META_SCREEN_BOTTOMRIGHT:
2166 return "BottomRight";
2167 }
2168
2169 return "Unknown";
2170}
2171#endif /* WITH_VERBOSE_MODE */
2172
2173void
2174meta_screen_calc_workspace_layout (MetaScreen *screen,
2175 int num_workspaces,
2176 int current_space,
2177 MetaWorkspaceLayout *layout)
2178{
2179 int rows, cols;
2180 int grid_area;
2181 int *grid;
2182 int i, r, c;
2183 int current_row, current_col;
2184
2185 rows = screen->rows_of_workspaces;
2186 cols = screen->columns_of_workspaces;
2187 if (rows <= 0 && cols <= 0)
2188 cols = num_workspaces;
2189
2190 if (rows <= 0)
2191 rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
2192 if (cols <= 0)
2193 cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
2194
2195 /* paranoia */
2196 if (rows < 1)
2197 rows = 1;
2198 if (cols < 1)
2199 cols = 1;
2200
2201 g_assert (rows != 0 && cols != 0)do { if (rows != 0 && cols != 0) ; else g_assertion_message_expr
("marco", "core/screen.c", 2201, ((const char*) (__func__)),
"rows != 0 && cols != 0"); } while (0)
;
2202
2203 grid_area = rows * cols;
2204
2205 meta_verbosemeta_verbose_real ("Getting layout rows = %d cols = %d current = %d "
2206 "num_spaces = %d vertical = %s corner = %s\n",
2207 rows, cols, current_space, num_workspaces,
2208 screen->vertical_workspaces ? "(true)" : "(false)",
2209 meta_screen_corner_to_string (screen->starting_corner));
2210
2211 /* ok, we want to setup the distances in the workspace array to go
2212 * in each direction. Remember, there are many ways that a workspace
2213 * array can be setup.
2214 * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
2215 * and look at the _NET_DESKTOP_LAYOUT section for details.
2216 * For instance:
2217 */
2218 /* starting_corner = META_SCREEN_TOPLEFT
2219 * vertical_workspaces = 0 vertical_workspaces=1
2220 * 1234 1357
2221 * 5678 2468
2222 *
2223 * starting_corner = META_SCREEN_TOPRIGHT
2224 * vertical_workspaces = 0 vertical_workspaces=1
2225 * 4321 7531
2226 * 8765 8642
2227 *
2228 * starting_corner = META_SCREEN_BOTTOMLEFT
2229 * vertical_workspaces = 0 vertical_workspaces=1
2230 * 5678 2468
2231 * 1234 1357
2232 *
2233 * starting_corner = META_SCREEN_BOTTOMRIGHT
2234 * vertical_workspaces = 0 vertical_workspaces=1
2235 * 8765 8642
2236 * 4321 7531
2237 *
2238 */
2239 /* keep in mind that we could have a ragged layout, e.g. the "8"
2240 * in the above grids could be missing
2241 */
2242
2243 grid = g_new (int, grid_area)((int *) g_malloc_n ((grid_area), sizeof (int)));
2244
2245 i = 0;
2246 switch (screen->starting_corner)
2247 {
2248 case META_SCREEN_TOPLEFT:
2249 if (screen->vertical_workspaces)
2250 {
2251 c = 0;
2252 while (c < cols)
2253 {
2254 r = 0;
2255 while (r < rows)
2256 {
2257 grid[r*cols+c] = i;
2258 ++i;
2259 ++r;
2260 }
2261 ++c;
2262 }
2263 }
2264 else
2265 {
2266 r = 0;
2267 while (r < rows)
2268 {
2269 c = 0;
2270 while (c < cols)
2271 {
2272 grid[r*cols+c] = i;
2273 ++i;
2274 ++c;
2275 }
2276 ++r;
2277 }
2278 }
2279 break;
2280 case META_SCREEN_TOPRIGHT:
2281 if (screen->vertical_workspaces)
2282 {
2283 c = cols - 1;
2284 while (c >= 0)
2285 {
2286 r = 0;
2287 while (r < rows)
2288 {
2289 grid[r*cols+c] = i;
2290 ++i;
2291 ++r;
2292 }
2293 --c;
2294 }
2295 }
2296 else
2297 {
2298 r = 0;
2299 while (r < rows)
2300 {
2301 c = cols - 1;
2302 while (c >= 0)
2303 {
2304 grid[r*cols+c] = i;
2305 ++i;
2306 --c;
2307 }
2308 ++r;
2309 }
2310 }
2311 break;
2312 case META_SCREEN_BOTTOMLEFT:
2313 if (screen->vertical_workspaces)
2314 {
2315 c = 0;
2316 while (c < cols)
2317 {
2318 r = rows - 1;
2319 while (r >= 0)
2320 {
2321 grid[r*cols+c] = i;
2322 ++i;
2323 --r;
2324 }
2325 ++c;
2326 }
2327 }
2328 else
2329 {
2330 r = rows - 1;
2331 while (r >= 0)
2332 {
2333 c = 0;
2334 while (c < cols)
2335 {
2336 grid[r*cols+c] = i;
2337 ++i;
2338 ++c;
2339 }
2340 --r;
2341 }
2342 }
2343 break;
2344 case META_SCREEN_BOTTOMRIGHT:
2345 if (screen->vertical_workspaces)
2346 {
2347 c = cols - 1;
2348 while (c >= 0)
2349 {
2350 r = rows - 1;
2351 while (r >= 0)
2352 {
2353 grid[r*cols+c] = i;
2354 ++i;
2355 --r;
2356 }
2357 --c;
2358 }
2359 }
2360 else
2361 {
2362 r = rows - 1;
2363 while (r >= 0)
2364 {
2365 c = cols - 1;
2366 while (c >= 0)
2367 {
2368 grid[r*cols+c] = i;
2369 ++i;
2370 --c;
2371 }
2372 --r;
2373 }
2374 }
2375 break;
2376 }
2377
2378 if (i != grid_area)
2379 meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
2380 G_STRFUNC((const char*) (__func__)), i);
2381
2382 current_row = 0;
2383 current_col = 0;
2384 r = 0;
2385 while (r < rows)
2386 {
2387 c = 0;
2388 while (c < cols)
2389 {
2390 if (grid[r*cols+c] == current_space)
2391 {
2392 current_row = r;
2393 current_col = c;
2394 }
2395 else if (grid[r*cols+c] >= num_workspaces)
2396 {
2397 /* flag nonexistent spaces with -1 */
2398 grid[r*cols+c] = -1;
2399 }
2400 ++c;
2401 }
2402 ++r;
2403 }
2404
2405 layout->rows = rows;
2406 layout->cols = cols;
2407 layout->grid = grid;
2408 layout->grid_area = grid_area;
2409 layout->current_row = current_row;
2410 layout->current_col = current_col;
2411
2412#ifdef WITH_VERBOSE_MODE1
2413 if (meta_is_verbose ())
2414 {
2415 r = 0;
2416 while (r < layout->rows)
2417 {
2418 meta_verbosemeta_verbose_real (" ");
2419 meta_push_no_msg_prefix ();
2420 c = 0;
2421 while (c < layout->cols)
2422 {
2423 if (r == layout->current_row &&
2424 c == layout->current_col)
2425 meta_verbosemeta_verbose_real ("*%2d ", layout->grid[r*layout->cols+c]);
2426 else
2427 meta_verbosemeta_verbose_real ("%3d ", layout->grid[r*layout->cols+c]);
2428 ++c;
2429 }
2430 meta_verbosemeta_verbose_real ("\n");
2431 meta_pop_no_msg_prefix ();
2432 ++r;
2433 }
2434 }
2435#endif /* WITH_VERBOSE_MODE */
2436}
2437
2438void
2439meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
2440{
2441 g_free (layout->grid);
2442}
2443
2444static void
2445meta_screen_resize_func (MetaScreen *screen,
2446 MetaWindow *window,
2447 void *user_data)
2448{
2449 if (window->struts)
2450 {
2451 meta_window_update_struts (window);
2452 }
2453 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2454
2455 meta_window_recalc_features (window);
2456}
2457
2458void
2459meta_screen_resize (MetaScreen *screen,
2460 int width,
2461 int height)
2462{
2463 screen->rect.width = width;
2464 screen->rect.height = height;
2465
2466 reload_xinerama_infos (screen);
2467 set_desktop_geometry_hint (screen);
2468
2469 /* Queue a resize on all the windows */
2470 meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
2471}
2472
2473void
2474meta_screen_update_showing_desktop_hint (MetaScreen *screen)
2475{
2476 unsigned long data[1];
2477
2478 data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
2479
2480 meta_error_trap_push (screen->display);
2481 XChangeProperty (screen->display->xdisplay, screen->xroot,
2482 screen->display->atom__NET_SHOWING_DESKTOP,
2483 XA_CARDINAL((Atom) 6),
2484 32, PropModeReplace0, (guchar*) data, 1);
2485 meta_error_trap_pop (screen->display, FALSE(0));
2486}
2487
2488static void
2489queue_windows_showing (MetaScreen *screen)
2490{
2491 GSList *windows;
2492 GSList *tmp;
2493
2494 /* Must operate on all windows on display instead of just on the
2495 * active_workspace's window list, because the active_workspace's
2496 * window list may not contain the on_all_workspace windows.
2497 */
2498 windows = meta_display_list_windows (screen->display);
2499
2500 tmp = windows;
2501 while (tmp != NULL((void*)0))
2502 {
2503 MetaWindow *w = tmp->data;
2504
2505 if (w->screen == screen && !meta_prefs_is_in_skip_list (w->res_class))
2506 meta_window_queue (w, META_QUEUE_CALC_SHOWING);
2507
2508 tmp = tmp->next;
2509 }
2510
2511 g_slist_free (windows);
2512}
2513
2514void
2515meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
2516 MetaWindow *keep)
2517{
2518 GList *windows;
2519 GList *tmp;
2520
2521 windows = screen->active_workspace->windows;
2522
2523 tmp = windows;
2524 while (tmp != NULL((void*)0))
2525 {
2526 MetaWindow *w = tmp->data;
2527
2528 if (w->screen == screen &&
2529 w->has_minimize_func &&
2530 w != keep)
2531 meta_window_minimize (w);
2532
2533 tmp = tmp->next;
2534 }
2535}
2536
2537void
2538meta_screen_show_desktop (MetaScreen *screen,
2539 guint32 timestamp)
2540{
2541 GList *windows;
2542
2543 if (screen->active_workspace->showing_desktop)
2544 return;
2545
2546 screen->active_workspace->showing_desktop = TRUE(!(0));
2547
2548 queue_windows_showing (screen);
2549
2550 /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
2551 * see bug 159257.
2552 */
2553 windows = screen->active_workspace->mru_list;
2554 while (windows != NULL((void*)0))
2555 {
2556 MetaWindow *w = windows->data;
2557
2558 if (w->screen == screen &&
2559 w->type == META_WINDOW_DESKTOP &&
2560 !meta_prefs_is_in_skip_list (w->res_class))
2561 {
2562 meta_window_focus (w, timestamp);
2563 break;
2564 }
2565
2566 windows = windows->next;
2567 }
2568
2569 meta_screen_update_showing_desktop_hint (screen);
2570}
2571
2572void
2573meta_screen_unshow_desktop (MetaScreen *screen)
2574{
2575 if (!screen->active_workspace->showing_desktop)
2576 return;
2577
2578 screen->active_workspace->showing_desktop = FALSE(0);
2579
2580 queue_windows_showing (screen);
2581
2582 meta_screen_update_showing_desktop_hint (screen);
2583}
2584
2585#ifdef HAVE_STARTUP_NOTIFICATION
2586static gboolean startup_sequence_timeout (void *data);
2587
2588static void
2589update_startup_feedback (MetaScreen *screen)
2590{
2591 if (screen->startup_sequences != NULL((void*)0))
2592 {
2593 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2594 "Setting busy cursor\n");
2595 meta_screen_set_cursor (screen, META_CURSOR_BUSY);
2596 }
2597 else
2598 {
2599 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2600 "Setting default cursor\n");
2601 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
2602 }
2603}
2604
2605static void
2606add_sequence (MetaScreen *screen,
2607 SnStartupSequence *sequence)
2608{
2609 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2610 "Adding sequence %s\n",
2611 sn_startup_sequence_get_id (sequence));
2612 sn_startup_sequence_ref (sequence);
2613 screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
2614 sequence);
2615
2616 /* our timeout just polls every second, instead of bothering
2617 * to compute exactly when we may next time out
2618 */
2619 if (screen->startup_sequence_timeout == 0)
2620 screen->startup_sequence_timeout = g_timeout_add (1000,
2621 startup_sequence_timeout,
2622 screen);
2623
2624 update_startup_feedback (screen);
2625}
2626
2627static void
2628remove_sequence (MetaScreen *screen,
2629 SnStartupSequence *sequence)
2630{
2631 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2632 "Removing sequence %s\n",
2633 sn_startup_sequence_get_id (sequence));
2634
2635 screen->startup_sequences = g_slist_remove (screen->startup_sequences,
2636 sequence);
2637 sn_startup_sequence_unref (sequence);
2638
2639 if (screen->startup_sequences == NULL((void*)0) &&
2640 screen->startup_sequence_timeout != 0)
2641 {
2642 g_source_remove (screen->startup_sequence_timeout);
2643 screen->startup_sequence_timeout = 0;
2644 }
2645
2646 update_startup_feedback (screen);
2647}
2648
2649typedef struct
2650{
2651 GSList *list;
2652 gint64 now;
2653} CollectTimedOutData;
2654
2655/* This should be fairly long, as it should never be required unless
2656 * apps or .desktop files are buggy, and it's confusing if
2657 * OpenOffice or whatever seems to stop launching - people
2658 * might decide they need to launch it again.
2659 */
2660#define STARTUP_TIMEOUT15000 15000
2661
2662static void
2663collect_timed_out_foreach (void *element,
2664 void *data)
2665{
2666 CollectTimedOutData *ctod = data;
2667 SnStartupSequence *sequence = element;
2668 double elapsed;
2669
2670 time_t tv_sec;
2671 suseconds_t tv_usec;
2672 gint64 tv;
2673
2674 sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
2675 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
2676 elapsed = (ctod->now - tv) / 1000.0;
2677
2678 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2679 "Sequence used %g seconds vs. %g max: %s\n",
2680 elapsed, (double) STARTUP_TIMEOUT15000,
2681 sn_startup_sequence_get_id (sequence));
2682
2683 if (elapsed > STARTUP_TIMEOUT15000)
2684 ctod->list = g_slist_prepend (ctod->list, sequence);
2685}
2686
2687static gboolean
2688startup_sequence_timeout (void *data)
2689{
2690 MetaScreen *screen = data;
2691 CollectTimedOutData ctod;
2692 GSList *tmp;
2693
2694 ctod.list = NULL((void*)0);
2695
2696 ctod.now = g_get_real_time ();
2697 g_slist_foreach (screen->startup_sequences,
2698 collect_timed_out_foreach,
2699 &ctod);
2700
2701 tmp = ctod.list;
2702 while (tmp != NULL((void*)0))
2703 {
2704 SnStartupSequence *sequence = tmp->data;
2705
2706 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2707 "Timed out sequence %s\n",
2708 sn_startup_sequence_get_id (sequence));
2709
2710 sn_startup_sequence_complete (sequence);
2711
2712 tmp = tmp->next;
2713 }
2714
2715 g_slist_free (ctod.list);
2716
2717 if (screen->startup_sequences != NULL((void*)0))
2718 {
2719 return TRUE(!(0));
2720 }
2721 else
2722 {
2723 /* remove */
2724 screen->startup_sequence_timeout = 0;
2725 return FALSE(0);
2726 }
2727}
2728
2729static void
2730meta_screen_sn_event (SnMonitorEvent *event,
2731 void *user_data)
2732{
2733 MetaScreen *screen;
2734 SnStartupSequence *sequence;
2735
2736 screen = user_data;
2737
2738 sequence = sn_monitor_event_get_startup_sequence (event);
2739
2740 switch (sn_monitor_event_get_type (event))
2741 {
2742 case SN_MONITOR_EVENT_INITIATED:
2743 {
2744 const char *wmclass;
2745
2746 wmclass = sn_startup_sequence_get_wmclass (sequence);
2747
2748 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2749 "Received startup initiated for %s wmclass %s\n",
2750 sn_startup_sequence_get_id (sequence),
2751 wmclass ? wmclass : "(unset)");
2752 add_sequence (screen, sequence);
2753 }
2754 break;
2755
2756 case SN_MONITOR_EVENT_COMPLETED:
2757 {
2758 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2759 "Received startup completed for %s\n",
2760 sn_startup_sequence_get_id (sequence));
2761 remove_sequence (screen,
2762 sn_monitor_event_get_startup_sequence (event));
2763 }
2764 break;
2765
2766 case SN_MONITOR_EVENT_CHANGED:
2767 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2768 "Received startup changed for %s\n",
2769 sn_startup_sequence_get_id (sequence));
2770 break;
2771
2772 case SN_MONITOR_EVENT_CANCELED:
2773 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2774 "Received startup canceled for %s\n",
2775 sn_startup_sequence_get_id (sequence));
2776 break;
2777 }
2778}
2779#endif
2780
2781/* Sets the initial_timestamp and initial_workspace properties
2782 * of a window according to information given us by the
2783 * startup-notification library.
2784 *
2785 * Returns TRUE if startup properties have been applied, and
2786 * FALSE if they have not (for example, if they had already
2787 * been applied.)
2788 */
2789gboolean
2790meta_screen_apply_startup_properties (MetaScreen *screen,
2791 MetaWindow *window)
2792{
2793#ifdef HAVE_STARTUP_NOTIFICATION
2794 const char *startup_id;
2795 GSList *tmp;
2796 SnStartupSequence *sequence;
2797
2798 /* Does the window have a startup ID stored? */
2799 startup_id = meta_window_get_startup_id (window);
2800
2801 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2802 "Applying startup props to %s id \"%s\"\n",
2803 window->desc,
2804 startup_id ? startup_id : "(none)");
2805
2806 sequence = NULL((void*)0);
2807 if (startup_id == NULL((void*)0))
2808 {
2809 /* No startup ID stored for the window. Let's ask the
2810 * startup-notification library whether there's anything
2811 * stored for the resource name or resource class hints.
2812 */
2813 tmp = screen->startup_sequences;
2814 while (tmp != NULL((void*)0))
2815 {
2816 const char *wmclass;
2817
2818 wmclass = sn_startup_sequence_get_wmclass (tmp->data);
2819
2820 if (wmclass != NULL((void*)0) &&
2821 ((window->res_class &&
2822 strcmp (wmclass, window->res_class) == 0) ||
2823 (window->res_name &&
2824 strcmp (wmclass, window->res_name) == 0)))
2825 {
2826 sequence = tmp->data;
2827
2828 g_assert (window->startup_id == NULL)do { if (window->startup_id == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 2828, ((const char*) (__func__)),
"window->startup_id == NULL"); } while (0)
;
2829 window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence))g_strdup_inline (sn_startup_sequence_get_id (sequence));
2830 startup_id = window->startup_id;
2831
2832 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2833 "Ending legacy sequence %s due to window %s\n",
2834 sn_startup_sequence_get_id (sequence),
2835 window->desc);
2836
2837 sn_startup_sequence_complete (sequence);
2838 break;
2839 }
2840
2841 tmp = tmp->next;
2842 }
2843 }
2844
2845 /* Still no startup ID? Bail. */
2846 if (startup_id == NULL((void*)0))
2847 return FALSE(0);
2848
2849 /* We might get this far and not know the sequence ID (if the window
2850 * already had a startup ID stored), so let's look for one if we don't
2851 * already know it.
2852 */
2853 if (sequence == NULL((void*)0))
2854 {
2855 tmp = screen->startup_sequences;
2856 while (tmp != NULL((void*)0))
2857 {
2858 const char *id;
2859
2860 id = sn_startup_sequence_get_id (tmp->data);
2861
2862 if (strcmp (id, startup_id) == 0)
2863 {
2864 sequence = tmp->data;
2865 break;
2866 }
2867
2868 tmp = tmp->next;
2869 }
2870 }
2871
2872 if (sequence != NULL((void*)0))
2873 {
2874 gboolean changed_something = FALSE(0);
2875
2876 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2877 "Found startup sequence for window %s ID \"%s\"\n",
2878 window->desc, startup_id);
2879
2880 if (!window->initial_workspace_set)
2881 {
2882 int space = sn_startup_sequence_get_workspace (sequence);
2883 if (space >= 0)
2884 {
2885 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2886 "Setting initial window workspace to %d based on startup info\n",
2887 space);
2888
2889 window->initial_workspace_set = TRUE(!(0));
2890 window->initial_workspace = space;
2891 changed_something = TRUE(!(0));
2892 }
2893 }
2894
2895 if (!window->initial_timestamp_set)
2896 {
2897 guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
2898 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2899 "Setting initial window timestamp to %u based on startup info\n",
2900 timestamp);
2901
2902 window->initial_timestamp_set = TRUE(!(0));
2903 window->initial_timestamp = timestamp;
2904 changed_something = TRUE(!(0));
2905 }
2906
2907 return changed_something;
2908 }
2909 else
2910 {
2911 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2912 "Did not find startup sequence for window %s ID \"%s\"\n",
2913 window->desc, startup_id);
2914 }
2915
2916#endif /* HAVE_STARTUP_NOTIFICATION */
2917
2918 return FALSE(0);
2919}
2920
2921int
2922meta_screen_get_screen_number (MetaScreen *screen)
2923{
2924 return screen->number;
2925}
2926
2927MetaDisplay *
2928meta_screen_get_display (MetaScreen *screen)
2929{
2930 return screen->display;
2931}
2932
2933Window
2934meta_screen_get_xroot (MetaScreen *screen)
2935{
2936 return screen->xroot;
2937}
2938
2939void
2940meta_screen_get_size (MetaScreen *screen,
2941 int *width,
2942 int *height)
2943{
2944 *width = screen->rect.width;
2945 *height = screen->rect.height;
2946}
2947
2948gpointer
2949meta_screen_get_compositor_data (MetaScreen *screen)
2950{
2951 return screen->compositor_data;
2952}
2953
2954void
2955meta_screen_set_compositor_data (MetaScreen *screen,
2956 gpointer compositor)
2957{
2958 screen->compositor_data = compositor;
2959}
2960
2961#ifdef HAVE_COMPOSITE_EXTENSIONS1
2962void
2963meta_screen_set_cm_selection (MetaScreen *screen)
2964{
2965 screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip (
2966 screen->display);
2967
2968 meta_verbosemeta_verbose_real ("Setting selection for screen: %d\n", screen->number);
2969 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2970 screen->wm_cm_selection_window, screen->wm_cm_timestamp);
2971}
2972
2973void
2974meta_screen_unset_cm_selection (MetaScreen *screen)
2975{
2976 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2977 None0L, screen->wm_cm_timestamp);
2978}
2979
2980gboolean
2981meta_screen_is_cm_selected (MetaScreen *screen)
2982{
2983 Window owner = XGetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom);
2984 return owner != None0L;
2985}
2986#endif /* HAVE_COMPOSITE_EXTENSIONS */
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ec6e93.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ec6e93.html new file mode 100644 index 00000000..a794fc24 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ec6e93.html @@ -0,0 +1,1117 @@ + + + +core/bell.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/bell.c
Warning:line 409, column 10
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bell.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/bell.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco visual bell */
4
5/*
6 * Copyright (C) 2002 Sun Microsystems Inc.
7 * Copyright (C) 2005, 2006 Elijah Newren
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25/**
26 * \file bell.c Ring the bell or flash the screen
27 *
28 * Sometimes, X programs "ring the bell", whatever that means. Marco lets
29 * the user configure the bell to be audible or visible (aka visual), and
30 * if it's visual it can be configured to be frame-flash or fullscreen-flash.
31 * We never get told about audible bells; X handles them just fine by itself.
32 *
33 * Visual bells come in at meta_bell_notify(), which checks we are actually
34 * in visual mode and calls through to bell_visual_notify(). That
35 * function then checks what kind of visual flash you like, and calls either
36 * bell_flash_fullscreen()-- which calls bell_flash_screen() to do
37 * its work-- or bell_flash_frame(), which flashes the focussed window
38 * using bell_flash_window_frame(), unless there is no such window, in
39 * which case it flashes the screen instead. bell_flash_window_frame()
40 * flashes the frame and calls bell_unflash_frame() as a timeout to
41 * remove the flash.
42 *
43 * The visual bell was the result of a discussion in Bugzilla here:
44 * <http://bugzilla.gnome.org/show_bug.cgi?id=99886>.
45 *
46 * Several of the functions in this file are ifdeffed out entirely if we are
47 * found not to have the XKB extension, which is required to do these clever
48 * things with bells; some others are entirely no-ops in that case.
49 */
50
51#include <config.h>
52#include <glib/gi18n-lib.h>
53
54#include "bell.h"
55#include "screen-private.h"
56#include "prefs.h"
57#include <canberra-gtk.h>
58
59#ifdef HAVE_XKB
60/**
61 * Flashes one entire screen. This is done by making a window the size of the
62 * whole screen (or reusing the old one, if it's still around), mapping it,
63 * painting it white and then black, and then unmapping it. We set saveunder so
64 * that all the windows behind it come back immediately.
65 *
66 * Unlike frame flashes, we don't do fullscreen flashes with a timeout; rather,
67 * we do them in one go, because we don't have to rely on the theme code
68 * redrawing the frame for us in order to do the flash.
69 *
70 * \param display The display which owns the screen (rather redundant)
71 * \param screen The screen to flash
72 *
73 * \bug The way I read it, this appears not to do the flash
74 * the first time we flash a particular display. Am I wrong?
75 *
76 * \bug This appears to destroy our current XSync status.
77 */
78static void
79bell_flash_screen (MetaDisplay *display,
80 MetaScreen *screen)
81{
82 Window root = screen->xroot;
83 int width = screen->rect.width;
84 int height = screen->rect.height;
85
86 if (screen->flash_window == None0L)
87 {
88 Visual *visual = (Visual *)CopyFromParent0L;
89 XSetWindowAttributes xswa;
90 int depth = CopyFromParent0L;
91 xswa.save_under = True1;
92 xswa.override_redirect = True1;
93 /*
94 * TODO: use XGetVisualInfo and determine which is an
95 * overlay, if one is present, and use the Overlay visual
96 * for this window (for performance reasons).
97 * Not sure how to tell this yet...
98 */
99 screen->flash_window = XCreateWindow (display->xdisplay, root,
100 0, 0, width, height,
101 0, depth,
102 InputOutput1,
103 visual,
104 /* note: XSun doesn't like SaveUnder here */
105 CWSaveUnder(1L<<10) | CWOverrideRedirect(1L<<9),
106 &xswa);
107 XSelectInput (display->xdisplay, screen->flash_window, ExposureMask(1L<<15));
108 XMapWindow (display->xdisplay, screen->flash_window);
109 XSync (display->xdisplay, False0);
110 XFlush (display->xdisplay);
111 XUnmapWindow (display->xdisplay, screen->flash_window);
112 }
113 else
114 {
115 /* just draw something in the window */
116 GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL((void*)0));
117 XMapWindow (display->xdisplay, screen->flash_window);
118 XSetForeground (display->xdisplay, gc,
119 WhitePixel (display->xdisplay,((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->white_pixel)
120 XScreenNumberOfScreen (screen->xscreen))((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->white_pixel)
);
121 XFillRectangle (display->xdisplay, screen->flash_window, gc,
122 0, 0, width, height);
123 XSetForeground (display->xdisplay, gc,
124 BlackPixel (display->xdisplay,((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->black_pixel)
125 XScreenNumberOfScreen (screen->xscreen))((&((_XPrivDisplay)(display->xdisplay))->screens[XScreenNumberOfScreen
(screen->xscreen)])->black_pixel)
);
126 XFillRectangle (display->xdisplay, screen->flash_window, gc,
127 0, 0, width, height);
128 XFlush (display->xdisplay);
129 XSync (display->xdisplay, False0);
130 XUnmapWindow (display->xdisplay, screen->flash_window);
131 XFreeGC (display->xdisplay, gc);
132 }
133
134 if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK &&
135 !display->mouse_mode)
136 meta_display_increment_focus_sentinel (display);
137 XFlush (display->xdisplay);
138}
139#endif /* HAVE_XKB */
140
141/**
142 * Flashes one screen, or all screens, in response to a bell event.
143 * If the event is on a particular window, flash the screen that
144 * window is on. Otherwise, flash every screen on this display.
145 *
146 * If the configure script found we had no XKB, this does not exist.
147 *
148 * \param display The display the event came in on
149 * \param xkb_ev The bell event
150 */
151#ifdef HAVE_XKB
152static void
153bell_flash_fullscreen (MetaDisplay *display,
154 XkbAnyEvent *xkb_ev)
155{
156 XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
157 MetaScreen *screen;
158
159 g_assert (xkb_ev->xkb_type == XkbBellNotify)do { if (xkb_ev->xkb_type == 8) ; else g_assertion_message_expr
("marco", "core/bell.c", 159, ((const char*) (__func__)), "xkb_ev->xkb_type == XkbBellNotify"
); } while (0)
;
160 if (xkb_bell_ev->window != None0L)
161 {
162 screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
163 if (screen)
164 bell_flash_screen (display, screen);
165 }
166 else
167 {
168 GSList *screen_list = display->screens;
169 while (screen_list)
170 {
171 screen = (MetaScreen *) screen_list->data;
172 bell_flash_screen (display, screen);
173 screen_list = screen_list->next;
174 }
175 }
176}
177
178/**
179 * Makes a frame be not flashed; this is the timeout half of
180 * bell_flash_window_frame(). This is done simply by clearing the
181 * flash flag and queuing a redraw of the frame.
182 *
183 * If the configure script found we had no XKB, this does not exist.
184 *
185 * \param data The frame to unflash, cast to a gpointer so it can go into
186 * a callback function.
187 * \return Always FALSE, so we don't get called again.
188 *
189 * \bug This is the parallel to bell_flash_window_frame(), so it should
190 * really be called meta_bell_unflash_window_frame().
191 */
192static gboolean
193bell_unflash_frame (gpointer data)
194{
195 MetaFrame *frame = (MetaFrame *) data;
196 frame->is_flashing = 0;
197 meta_frame_queue_draw (frame);
198 return FALSE(0);
199}
200
201/**
202 * Makes a frame flash and then return to normal shortly afterwards.
203 * This is done by setting a flag so that the theme
204 * code will temporarily draw the frame as focussed if it's unfocussed and
205 * vice versa, and then queueing a redraw. Lastly, we create a timeout so
206 * that the flag can be unset and the frame re-redrawn.
207 *
208 * If the configure script found we had no XKB, this does not exist.
209 *
210 * \param window The window to flash
211 */
212static void
213bell_flash_window_frame (MetaWindow *window)
214{
215 g_assert (window->frame != NULL)do { if (window->frame != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/bell.c", 215, ((const char*) (__func__)), "window->frame != NULL"
); } while (0)
;
216 window->frame->is_flashing = 1;
217 meta_frame_queue_draw (window->frame);
218 g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE200, 100,
219 bell_unflash_frame, window->frame, NULL((void*)0));
220}
221
222/**
223 * Flashes the frame of the focussed window. If there is no focussed window,
224 * flashes the screen.
225 *
226 * \param display The display the bell event came in on
227 * \param xkb_ev The bell event we just received
228 */
229static void
230bell_flash_frame (MetaDisplay *display,
231 XkbAnyEvent *xkb_ev)
232{
233 XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
234 MetaWindow *window;
235
236 g_assert (xkb_ev->xkb_type == XkbBellNotify)do { if (xkb_ev->xkb_type == 8) ; else g_assertion_message_expr
("marco", "core/bell.c", 236, ((const char*) (__func__)), "xkb_ev->xkb_type == XkbBellNotify"
); } while (0)
;
237 window = meta_display_lookup_x_window (display, xkb_bell_event->window);
238 if (!window && (display->focus_window))
239 {
240 window = display->focus_window;
241 }
242 if (window && window->frame)
243 {
244 bell_flash_window_frame (window);
245 }
246 else /* revert to fullscreen flash if there's no focussed window */
247 {
248 bell_flash_fullscreen (display, xkb_ev);
249 }
250}
251
252/**
253 * Gives the user some kind of visual bell substitute, in response to a
254 * bell event. What this is depends on the "visual bell type" pref.
255 *
256 * If the configure script found we had no XKB, this does not exist.
257 *
258 * \param display The display the bell event came in on
259 * \param xkb_ev The bell event we just received
260 *
261 * \bug This should be merged with meta_bell_notify().
262 */
263static void
264bell_visual_notify (MetaDisplay *display,
265 XkbAnyEvent *xkb_ev)
266{
267 switch (meta_prefs_get_visual_bell_type ())
268 {
269 case META_VISUAL_BELL_FULLSCREEN_FLASH:
270 bell_flash_fullscreen (display, xkb_ev);
271 break;
272 case META_VISUAL_BELL_FRAME_FLASH:
273 bell_flash_frame (display, xkb_ev); /* does nothing yet */
274 break;
275 case META_VISUAL_BELL_INVALID:
276 /* do nothing */
277 break;
278 }
279}
280
281void
282meta_bell_notify (MetaDisplay *display,
283 XkbAnyEvent *xkb_ev)
284{
285 /* flash something */
286 if (meta_prefs_get_visual_bell ())
287 bell_visual_notify (display, xkb_ev);
288
289 if (meta_prefs_bell_is_audible ())
290 {
291 ca_proplist *p;
292 XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
293 MetaWindow *window;
294 int res;
295
296 ca_proplist_create (&p);
297 ca_proplist_sets (p, CA_PROP_EVENT_ID"event.id", "bell-window-system");
298 ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION"event.description", _("Bell event")((char *) g_dgettext ("marco", "Bell event")));
299 ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL"canberra.cache-control", "permanent");
300
301 window = meta_display_lookup_x_window (display, xkb_bell_event->window);
302 if (!window && (display->focus_window) && (display->focus_window->frame))
303 window = display->focus_window;
304
305 if (window)
306 {
307 int x=-1, y=-1, width=-1, height=-1, screen_width=-1, screen_height=-1;
308 MetaScreen *screen;
309
310 screen = meta_window_get_screen (window);
311
312 ca_proplist_sets (p, CA_PROP_WINDOW_NAME"window.name", window->title);
313 ca_proplist_setf (p, CA_PROP_WINDOW_X11_XID"window.x11.xid", "%lu", (unsigned long)window->xwindow);
314 ca_proplist_setf (p, CA_PROP_WINDOW_X11_SCREEN"window.x11.screen", "%i", meta_screen_get_screen_number(screen));
315 ca_proplist_sets (p, CA_PROP_APPLICATION_NAME"application.name", window->res_name);
316 ca_proplist_setf (p, CA_PROP_APPLICATION_PROCESS_ID"application.process.id", "%d", window->net_wm_pid);
317
318 /* properties for positional sound based on window placement */
319 meta_window_get_geometry (window, &x, &y, &width, &height);
320 ca_proplist_setf (p, CA_PROP_WINDOW_X"window.x", "%i", x);
321 ca_proplist_setf (p, CA_PROP_WINDOW_Y"window.y", "%i", y);
322 ca_proplist_setf (p, CA_PROP_WINDOW_WIDTH"window.width", "%i", width);
323 ca_proplist_setf (p, CA_PROP_WINDOW_HEIGHT"window.height", "%i", height);
324
325 meta_screen_get_size (screen, &screen_width, &screen_height);
326 if (screen_width > 1)
327 {
328 x += width/2;
329 x = CLAMP(x, 0, screen_width-1)(((x) > (screen_width-1)) ? (screen_width-1) : (((x) < (
0)) ? (0) : (x)))
;
330
331 /* From libcanberra-gtk.
332 * We use these strange format strings here to avoid that libc
333 * applies locale information on the formatting of floating
334 * numbers. */
335
336 ca_proplist_setf (p, CA_PROP_WINDOW_HPOS"window.hpos", "%i.%03i",
337 (int) (x/(screen_width-1)), (int) (1000.0*x/(screen_width-1)) % 1000);
338 }
339 if (screen_height > 1)
340 {
341 y += height/2;
342 y = CLAMP(y, 0, screen_height-1)(((y) > (screen_height-1)) ? (screen_height-1) : (((y) <
(0)) ? (0) : (y)))
;
343
344 ca_proplist_setf (p, CA_PROP_WINDOW_VPOS"window.vpos", "%i.%03i",
345 (int) (y/(screen_height-1)), (int) (1000.0*y/(screen_height-1)) % 1000);
346 }
347 }
348
349 /* First, we try to play a real sound ... */
350 res = ca_context_play_full (ca_gtk_context_get (), 1, p, NULL((void*)0), NULL((void*)0));
351
352 ca_proplist_destroy (p);
353
354 if (res != CA_SUCCESS && res != CA_ERROR_DISABLED)
355 {
356 /* ...and in case that failed we use the classic X11 bell. */
357 XkbForceDeviceBell (display->xdisplay,
358 xkb_bell_event->device,
359 xkb_bell_event->bell_class,
360 xkb_bell_event->bell_id,
361 xkb_bell_event->percent);
362 }
363 }
364}
365#endif /* HAVE_XKB */
366
367void
368meta_bell_set_audible (MetaDisplay *display, gboolean audible)
369{
370}
371
372gboolean
373meta_bell_init (MetaDisplay *display)
374{
375#ifdef HAVE_XKB
376 int xkb_base_error_type, xkb_opcode;
377
378 if (!XkbQueryExtension (display->xdisplay, &xkb_opcode,
379 &display->xkb_base_event_type,
380 &xkb_base_error_type,
381 NULL((void*)0), NULL((void*)0)))
382 {
383 display->xkb_base_event_type = -1;
384 g_message ("could not find XKB extension.");
385 return FALSE(0);
386 }
387 else
388 {
389 unsigned int mask = XkbBellNotifyMask(1L << 8);
390 gboolean visual_bell_auto_reset = FALSE(0);
391 /* TRUE if and when non-broken version is available */
392 XkbSelectEvents (display->xdisplay,
393 XkbUseCoreKbd0x0100,
394 XkbBellNotifyMask(1L << 8),
395 XkbBellNotifyMask(1L << 8));
396 XkbChangeEnabledControls (display->xdisplay,
397 XkbUseCoreKbd0x0100,
398 XkbAudibleBellMask(1L << 9),
399 0);
400 if (visual_bell_auto_reset) {
401 XkbSetAutoResetControls (display->xdisplay,
402 XkbAudibleBellMask(1L << 9),
403 &mask,
404 &mask);
405 }
406 return TRUE(!(0));
407 }
408#endif
409 return FALSE(0);
This statement is never executed
410}
411
412void
413meta_bell_shutdown (MetaDisplay *display)
414{
415#ifdef HAVE_XKB
416 /* TODO: persist initial bell state in display, reset here */
417 XkbChangeEnabledControls (display->xdisplay,
418 XkbUseCoreKbd0x0100,
419 XkbAudibleBellMask(1L << 9),
420 XkbAudibleBellMask(1L << 9));
421#endif
422}
423
424/**
425 * Deals with a frame being destroyed. This is important because if we're
426 * using a visual bell, we might be flashing the edges of the frame, and
427 * so we'd have a timeout function waiting ready to un-flash them. If the
428 * frame's going away, we can tell the timeout not to bother.
429 *
430 * \param frame The frame which is being destroyed
431 */
432void
433meta_bell_notify_frame_destroy (MetaFrame *frame)
434{
435 if (frame->is_flashing)
436 g_source_remove_by_funcs_user_data (&g_timeout_funcs, frame);
437}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ed0075.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ed0075.html new file mode 100644 index 00000000..5c820a1e --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ed0075.html @@ -0,0 +1,3708 @@ + + + +core/screen.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:core/screen.c
Warning:line 1733, column 32
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name screen.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c core/screen.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco X screen handler */
4
5/*
6 * Copyright (C) 2001, 2002 Havoc Pennington
7 * Copyright (C) 2002, 2003 Red Hat Inc.
8 * Some ICCCM manager selection code derived from fvwm2,
9 * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
10 * Copyright (C) 2003 Rob Adams
11 * Copyright (C) 2004-2006 Elijah Newren
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301, USA.
27 */
28
29#include <config.h>
30#include <glib/gi18n-lib.h>
31
32#include "screen-private.h"
33#include "util.h"
34#include "errors.h"
35#include "window-private.h"
36#include "frame-private.h"
37#include "prefs.h"
38#include "workspace.h"
39#include "keybindings.h"
40#include "prefs.h"
41#include "stack.h"
42#include "xprops.h"
43#include "compositor.h"
44
45#ifdef HAVE_SOLARIS_XINERAMA
46#include <X11/extensions/xinerama.h>
47#endif
48#ifdef HAVE_XFREE_XINERAMA
49#include <X11/extensions/Xinerama.h>
50#endif
51
52#include <X11/Xatom.h>
53#include <cairo/cairo-xlib.h>
54#include <locale.h>
55#include <string.h>
56#include <stdio.h>
57
58static char* get_screen_name (MetaDisplay *display,
59 int number);
60
61static void update_num_workspaces (MetaScreen *screen,
62 guint32 timestamp);
63static void update_focus_mode (MetaScreen *screen);
64static void set_workspace_names (MetaScreen *screen);
65static void prefs_changed_callback (MetaPreference pref,
66 gpointer data);
67
68static void set_desktop_geometry_hint (MetaScreen *screen);
69static void set_desktop_viewport_hint (MetaScreen *screen);
70
71#ifdef HAVE_STARTUP_NOTIFICATION
72static void meta_screen_sn_event (SnMonitorEvent *event,
73 void *user_data);
74#endif
75
76static int
77set_wm_check_hint (MetaScreen *screen)
78{
79 unsigned long data[1];
80
81 g_return_val_if_fail (screen->display->leader_window != None, 0)do { if ((screen->display->leader_window != 0L)) { } else
{ g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "screen->display->leader_window != None"); return (
0); } } while (0)
;
82
83 data[0] = screen->display->leader_window;
84
85 XChangeProperty (screen->display->xdisplay, screen->xroot,
86 screen->display->atom__NET_SUPPORTING_WM_CHECK,
87 XA_WINDOW((Atom) 33),
88 32, PropModeReplace0, (guchar*) data, 1);
89
90 return Success0;
91}
92
93static void
94unset_wm_check_hint (MetaScreen *screen)
95{
96 XDeleteProperty (screen->display->xdisplay, screen->xroot,
97 screen->display->atom__NET_SUPPORTING_WM_CHECK);
98}
99
100static int
101set_supported_hint (MetaScreen *screen)
102{
103 Atom atoms[] = {
104#define EWMH_ATOMS_ONLY
105#define item(x) screen->display->atom_##x,
106#include "atomnames.h"
107#undef item
108#undef EWMH_ATOMS_ONLY
109 screen->display->atom__GTK_FRAME_EXTENTS,
110 screen->display->atom__GTK_SHOW_WINDOW_MENU,
111 screen->display->atom__GTK_WORKAREAS
112 };
113
114 XChangeProperty (screen->display->xdisplay, screen->xroot,
115 screen->display->atom__NET_SUPPORTED,
116 XA_ATOM((Atom) 4),
117 32, PropModeReplace0,
118 (guchar*) atoms, G_N_ELEMENTS(atoms)(sizeof (atoms) / sizeof ((atoms)[0])));
119
120 return Success0;
121}
122
123static int
124set_wm_icon_size_hint (MetaScreen *screen)
125{
126 int icon_size = meta_prefs_get_icon_size();
127#define N_VALS 6
128 gulong vals[N_VALS];
129
130 /* min width, min height, max w, max h, width inc, height inc */
131 vals[0] = icon_size; /* width */
132 vals[1] = icon_size; /* height */
133 vals[2] = icon_size; /* width */
134 vals[3] = icon_size; /* height */
135 vals[4] = 0;
136 vals[5] = 0;
137
138 XChangeProperty (screen->display->xdisplay, screen->xroot,
139 screen->display->atom_WM_ICON_SIZE,
140 XA_CARDINAL((Atom) 6),
141 32, PropModeReplace0, (guchar*) vals, N_VALS);
142
143 return Success0;
144#undef N_VALS
145}
146
147static void
148reload_xinerama_infos (MetaScreen *screen)
149{
150 MetaDisplay *display;
151
152 {
153 GList *tmp;
154
155 tmp = screen->workspaces;
156 while (tmp != NULL((void*)0))
157 {
158 MetaWorkspace *space = tmp->data;
159
160 meta_workspace_invalidate_work_area (space);
161
162 tmp = tmp->next;
163 }
164 }
165
166 display = screen->display;
167
168 if (screen->xinerama_infos)
169 g_free (screen->xinerama_infos);
170
171 screen->xinerama_infos = NULL((void*)0);
172 screen->n_xinerama_infos = 0;
173 screen->last_xinerama_index = 0;
174
175 screen->display->xinerama_cache_invalidated = TRUE(!(0));
176
177#ifdef HAVE_XFREE_XINERAMA
178 if (XineramaIsActive (display->xdisplay))
179 {
180 XineramaScreenInfo *infos;
181 int n_infos;
182 int i;
183
184 n_infos = 0;
185 infos = XineramaQueryScreens (display->xdisplay, &n_infos);
186
187 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
188 "Found %d Xinerama screens on display %s\n",
189 n_infos, display->name);
190
191 if (n_infos > 0)
192 {
193 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos)((MetaXineramaScreenInfo *) g_malloc_n ((n_infos), sizeof (MetaXineramaScreenInfo
)))
;
194 screen->n_xinerama_infos = n_infos;
195
196 i = 0;
197 while (i < n_infos)
198 {
199 screen->xinerama_infos[i].number = infos[i].screen_number;
200 screen->xinerama_infos[i].rect.x = infos[i].x_org;
201 screen->xinerama_infos[i].rect.y = infos[i].y_org;
202 screen->xinerama_infos[i].rect.width = infos[i].width;
203 screen->xinerama_infos[i].rect.height = infos[i].height;
204
205 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
206 "Xinerama %d is %d,%d %d x %d\n",
207 screen->xinerama_infos[i].number,
208 screen->xinerama_infos[i].rect.x,
209 screen->xinerama_infos[i].rect.y,
210 screen->xinerama_infos[i].rect.width,
211 screen->xinerama_infos[i].rect.height);
212
213 ++i;
214 }
215 }
216
217 meta_XFree (infos)do { if ((infos)) XFree ((infos)); } while (0);
218 }
219 else
220 {
221 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
222 "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
223 display->name);
224 }
225#else
226 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
227 "Marco compiled without XFree86 Xinerama support\n");
228#endif /* HAVE_XFREE_XINERAMA */
229
230#ifdef HAVE_SOLARIS_XINERAMA
231 /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
232 if (screen->n_xinerama_infos == 0 &&
233 XineramaGetState (screen->display->xdisplay,
234 screen->number))
235 {
236 XRectangle monitors[MAXFRAMEBUFFERS];
237 unsigned char hints[16];
238 int result;
239 int n_monitors;
240 int i;
241
242 n_monitors = 0;
243 result = XineramaGetInfo (screen->display->xdisplay,
244 screen->number,
245 monitors, hints,
246 &n_monitors);
247 /* Yes I know it should be Success but the current implementation
248 * returns the num of monitor
249 */
250 if (result > 0)
251 {
252 g_assert (n_monitors > 0)do { if (n_monitors > 0) ; else g_assertion_message_expr (
"marco", "core/screen.c", 252, ((const char*) (__func__)), "n_monitors > 0"
); } while (0)
;
253
254 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors)((MetaXineramaScreenInfo *) g_malloc_n ((n_monitors), sizeof (
MetaXineramaScreenInfo)))
;
255 screen->n_xinerama_infos = n_monitors;
256
257 i = 0;
258 while (i < n_monitors)
259 {
260 screen->xinerama_infos[i].number = i;
261 screen->xinerama_infos[i].rect.x = monitors[i].x;
262 screen->xinerama_infos[i].rect.y = monitors[i].y;
263 screen->xinerama_infos[i].rect.width = monitors[i].width;
264 screen->xinerama_infos[i].rect.height = monitors[i].height;
265
266 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
267 "Xinerama %d is %d,%d %d x %d\n",
268 screen->xinerama_infos[i].number,
269 screen->xinerama_infos[i].rect.x,
270 screen->xinerama_infos[i].rect.y,
271 screen->xinerama_infos[i].rect.width,
272 screen->xinerama_infos[i].rect.height);
273
274 ++i;
275 }
276 }
277 }
278 else if (screen->n_xinerama_infos == 0)
279 {
280 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
281 "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
282 display->name);
283 }
284#else
285 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
286 "Marco compiled without Solaris Xinerama support\n");
287#endif /* HAVE_SOLARIS_XINERAMA */
288
289 /* If no Xinerama, fill in the single screen info so
290 * we can use the field unconditionally
291 */
292 if (screen->n_xinerama_infos == 0)
293 {
294 if (g_getenv ("MARCO_DEBUG_XINERAMA"))
295 {
296 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
297 "Pretending a single monitor has two Xinerama screens\n");
298
299 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2)((MetaXineramaScreenInfo *) g_malloc_n ((2), sizeof (MetaXineramaScreenInfo
)))
;
300 screen->n_xinerama_infos = 2;
301
302 screen->xinerama_infos[0].number = 0;
303 screen->xinerama_infos[0].rect = screen->rect;
304 screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
305
306 screen->xinerama_infos[1].number = 1;
307 screen->xinerama_infos[1].rect = screen->rect;
308 screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
309 screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
310 }
311 else
312 {
313 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
314 "No Xinerama screens, using default screen info\n");
315
316 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1)((MetaXineramaScreenInfo *) g_malloc_n ((1), sizeof (MetaXineramaScreenInfo
)))
;
317 screen->n_xinerama_infos = 1;
318
319 screen->xinerama_infos[0].number = 0;
320 screen->xinerama_infos[0].rect = screen->rect;
321 }
322 }
323
324 g_assert (screen->n_xinerama_infos > 0)do { if (screen->n_xinerama_infos > 0) ; else g_assertion_message_expr
("marco", "core/screen.c", 324, ((const char*) (__func__)), "screen->n_xinerama_infos > 0"
); } while (0)
;
325 g_assert (screen->xinerama_infos != NULL)do { if (screen->xinerama_infos != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 325, ((const char*) (__func__)), "screen->xinerama_infos != NULL"
); } while (0)
;
326}
327
328MetaScreen*
329meta_screen_new (MetaDisplay *display,
330 int number,
331 guint32 timestamp)
332{
333 MetaScreen *screen;
334 Window xroot;
335 Display *xdisplay;
336 XWindowAttributes attr;
337 Window new_wm_sn_owner;
338 Window current_wm_sn_owner;
339 gboolean replace_current_wm;
340 Atom wm_sn_atom;
341 char buf[128];
342 guint32 manager_timestamp;
343 gulong current_workspace;
344
345 replace_current_wm = meta_get_replace_current_wm ();
346
347 /* Only display->name, display->xdisplay, and display->error_traps
348 * can really be used in this function, since normally screens are
349 * created from the MetaDisplay constructor
350 */
351
352 xdisplay = display->xdisplay;
353
354 meta_verbosemeta_verbose_real ("Trying screen %d on display '%s'\n",
355 number, display->name);
356
357 xroot = RootWindow (xdisplay, number)((&((_XPrivDisplay)(xdisplay))->screens[number])->root
)
;
358
359 /* FVWM checks for None here, I don't know if this
360 * ever actually happens
361 */
362 if (xroot == None0L)
363 {
364 meta_warning (_("Screen %d on display '%s' is invalid\n")((char *) g_dgettext ("marco", "Screen %d on display '%s' is invalid\n"
))
,
365 number, display->name);
366 return NULL((void*)0);
367 }
368
369 sprintf (buf, "WM_S%d", number);
370 wm_sn_atom = XInternAtom (xdisplay, buf, False0);
371
372 current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
373
374 if (current_wm_sn_owner != None0L)
375 {
376 XSetWindowAttributes attrs;
377
378 if (!replace_current_wm)
379 {
380 meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n")((char *) g_dgettext ("marco", "Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"
))
,
381 number, display->name);
382
383 return NULL((void*)0);
384 }
385
386 /* We want to find out when the current selection owner dies */
387 meta_error_trap_push (display);
388 attrs.event_mask = StructureNotifyMask(1L<<17);
389 XChangeWindowAttributes (xdisplay,
390 current_wm_sn_owner, CWEventMask(1L<<11), &attrs);
391 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
392 current_wm_sn_owner = None0L; /* don't wait for it to die later on */
393 }
394
395 /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
396 * but those cannot be masked, so we only need NoEventMask.
397 */
398 new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask0L);
399
400 manager_timestamp = timestamp;
401
402 XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
403 manager_timestamp);
404
405 if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
406 {
407 meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n")((char *) g_dgettext ("marco", "Could not acquire window manager selection on screen %d display \"%s\"\n"
))
,
408 number, display->name);
409
410 XDestroyWindow (xdisplay, new_wm_sn_owner);
411
412 return NULL((void*)0);
413 }
414
415 {
416 /* Send client message indicating that we are now the WM */
417 XClientMessageEvent ev;
418
419 ev.type = ClientMessage33;
420 ev.window = xroot;
421 ev.message_type = display->atom_MANAGER;
422 ev.format = 32;
423 ev.data.l[0] = manager_timestamp;
424 ev.data.l[1] = wm_sn_atom;
425
426 XSendEvent (xdisplay, xroot, False0, StructureNotifyMask(1L<<17), (XEvent*)&ev);
427 }
428
429 /* Wait for old window manager to go away */
430 if (current_wm_sn_owner != None0L)
431 {
432 XEvent event;
433
434 /* We sort of block infinitely here which is probably lame. */
435
436 meta_verbosemeta_verbose_real ("Waiting for old window manager to exit\n");
437 do
438 {
439 XWindowEvent (xdisplay, current_wm_sn_owner,
440 StructureNotifyMask(1L<<17), &event);
441 }
442 while (event.type != DestroyNotify17);
443 }
444
445 /* select our root window events */
446 meta_error_trap_push (display);
447
448 /* We need to or with the existing event mask since
449 * gtk+ may be interested in other events.
450 */
451 XGetWindowAttributes (xdisplay, xroot, &attr);
452 XSelectInput (xdisplay,
453 xroot,
454 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19) |
455 ColormapChangeMask(1L<<23) | PropertyChangeMask(1L<<22) |
456 LeaveWindowMask(1L<<5) | EnterWindowMask(1L<<4) |
457 KeyPressMask(1L<<0) | KeyReleaseMask(1L<<1) |
458 FocusChangeMask(1L<<21) | StructureNotifyMask(1L<<17) |
459#ifdef HAVE_COMPOSITE_EXTENSIONS1
460 ExposureMask(1L<<15) |
461#endif
462 attr.your_event_mask);
463 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
464 {
465 meta_warning (_("Screen %d on display \"%s\" already has a window manager\n")((char *) g_dgettext ("marco", "Screen %d on display \"%s\" already has a window manager\n"
))
,
466 number, display->name);
467
468 XDestroyWindow (xdisplay, new_wm_sn_owner);
469
470 return NULL((void*)0);
471 }
472
473 screen = g_new (MetaScreen, 1)((MetaScreen *) g_malloc_n ((1), sizeof (MetaScreen)));
474 screen->closing = 0;
475
476 screen->display = display;
477 screen->number = number;
478 screen->screen_name = get_screen_name (display, number);
479 screen->xscreen = ScreenOfDisplay (xdisplay, number)(&((_XPrivDisplay)(xdisplay))->screens[number]);
480 screen->xroot = xroot;
481 screen->rect.x = screen->rect.y = 0;
482 screen->rect.width = WidthOfScreen (screen->xscreen)((screen->xscreen)->width);
483 screen->rect.height = HeightOfScreen (screen->xscreen)((screen->xscreen)->height);
484 screen->current_cursor = -1; /* invalid/unset */
485 screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen)((screen->xscreen)->root_visual);
486 screen->default_depth = DefaultDepthOfScreen (screen->xscreen)((screen->xscreen)->root_depth);
487 screen->flash_window = None0L;
488
489 screen->wm_sn_selection_window = new_wm_sn_owner;
490 screen->wm_sn_atom = wm_sn_atom;
491 screen->wm_sn_timestamp = manager_timestamp;
492
493#ifdef HAVE_COMPOSITE_EXTENSIONS1
494 g_snprintf (buf, sizeof(buf), "_NET_WM_CM_S%d", screen->number);
495 screen->wm_cm_atom = XInternAtom (screen->display->xdisplay, buf, FALSE(0));
496 screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
497 xroot,
498 NoEventMask0L);
499#endif
500 screen->work_area_idle = 0;
501
502 screen->active_workspace = NULL((void*)0);
503 screen->workspaces = NULL((void*)0);
504 screen->rows_of_workspaces = 1;
505 screen->columns_of_workspaces = -1;
506 screen->vertical_workspaces = FALSE(0);
507 screen->starting_corner = META_SCREEN_TOPLEFT;
508 screen->compositor_data = NULL((void*)0);
509
510 {
511 XFontStruct *font_info;
512 XGCValues gc_values;
513 gulong value_mask = 0;
514
515 gc_values.subwindow_mode = IncludeInferiors1;
516 value_mask |= GCSubwindowMode(1L<<15);
517 gc_values.function = GXinvert0xa;
518 value_mask |= GCFunction(1L<<0);
519 gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH2;
520 value_mask |= GCLineWidth(1L<<4);
521
522 font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
523
524 if (font_info != NULL((void*)0))
525 {
526 gc_values.font = font_info->fid;
527 value_mask |= GCFont(1L<<14);
528 XFreeFontInfo (NULL((void*)0), font_info, 1);
529 }
530 else
531 meta_warning ("xserver doesn't have 'fixed' font.\n");
532
533 screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
534 screen->xroot,
535 value_mask,
536 &gc_values);
537 }
538
539 screen->xinerama_infos = NULL((void*)0);
540 screen->n_xinerama_infos = 0;
541 screen->last_xinerama_index = 0;
542
543 reload_xinerama_infos (screen);
544
545 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
546
547 /* Handle creating a no_focus_window for this screen */
548 screen->no_focus_window =
549 meta_create_offscreen_window (display->xdisplay,
550 screen->xroot,
551 FocusChangeMask(1L<<21)|KeyPressMask(1L<<0)|KeyReleaseMask(1L<<1));
552 XMapWindow (display->xdisplay, screen->no_focus_window);
553 /* Done with no_focus_window stuff */
554
555 set_wm_icon_size_hint (screen);
556
557 set_supported_hint (screen);
558
559 set_wm_check_hint (screen);
560
561 set_desktop_viewport_hint (screen);
562
563 set_desktop_geometry_hint (screen);
564
565 meta_screen_update_workspace_layout (screen);
566
567 /* Get current workspace */
568 current_workspace = 0;
569 if (meta_prop_get_cardinal (screen->display,
570 screen->xroot,
571 screen->display->atom__NET_CURRENT_DESKTOP,
572 &current_workspace))
573 meta_verbosemeta_verbose_real ("Read existing _NET_CURRENT_DESKTOP = %d\n",
574 (int) current_workspace);
575 else
576 meta_verbosemeta_verbose_real ("No _NET_CURRENT_DESKTOP present\n");
577
578 /* Screens must have at least one workspace at all times,
579 * so create that required workspace.
580 */
581 meta_workspace_activate (meta_workspace_new (screen), timestamp);
582 update_num_workspaces (screen, timestamp);
583
584 set_workspace_names (screen);
585
586 screen->all_keys_grabbed = FALSE(0);
587 screen->keys_grabbed = FALSE(0);
588 meta_screen_grab_keys (screen);
589
590 screen->ui = meta_ui_new (screen->display->xdisplay,
591 screen->xscreen);
592
593 screen->tab_popup = NULL((void*)0);
594 screen->tile_preview = NULL((void*)0);
595
596 screen->tile_preview_timeout_id = 0;
597
598 screen->stack = meta_stack_new (screen);
599
600 meta_prefs_add_listener (prefs_changed_callback, screen);
601
602#ifdef HAVE_STARTUP_NOTIFICATION
603 screen->sn_context =
604 sn_monitor_context_new (screen->display->sn_display,
605 screen->number,
606 meta_screen_sn_event,
607 screen,
608 NULL((void*)0));
609 screen->startup_sequences = NULL((void*)0);
610 screen->startup_sequence_timeout = 0;
611#endif
612
613 /* Switch to the _NET_CURRENT_DESKTOP workspace */
614 {
615 MetaWorkspace *space;
616
617 space = meta_screen_get_workspace_by_index (screen,
618 current_workspace);
619
620 if (space != NULL((void*)0))
621 meta_workspace_activate (space, timestamp);
622 }
623
624 meta_verbosemeta_verbose_real ("Added screen %d ('%s') root 0x%lx\n",
625 screen->number, screen->screen_name, screen->xroot);
626
627 return screen;
628}
629
630void
631meta_screen_free (MetaScreen *screen,
632 guint32 timestamp)
633{
634 MetaDisplay *display;
635 XGCValues gc_values = { 0 };
636
637 display = screen->display;
638
639 screen->closing += 1;
640
641 meta_display_grab (display);
642
643 if (screen->display->compositor)
644 {
645 meta_compositor_unmanage_screen (screen->display->compositor,
646 screen);
647 }
648
649 meta_display_unmanage_windows_for_screen (display, screen, timestamp);
650
651 meta_prefs_remove_listener (prefs_changed_callback, screen);
652
653 meta_screen_ungrab_keys (screen);
654
655#ifdef HAVE_STARTUP_NOTIFICATION
656 g_slist_free_full (screen->startup_sequences,
657 (GDestroyNotify) sn_startup_sequence_unref);
658 screen->startup_sequences = NULL((void*)0);
659
660 if (screen->startup_sequence_timeout != 0)
661 {
662 g_source_remove (screen->startup_sequence_timeout);
663 screen->startup_sequence_timeout = 0;
664 }
665 if (screen->sn_context)
666 {
667 sn_monitor_context_unref (screen->sn_context);
668 screen->sn_context = NULL((void*)0);
669 }
670#endif
671
672 meta_ui_free (screen->ui);
673
674 meta_stack_free (screen->stack);
675
676 meta_error_trap_push (screen->display);
677 XSelectInput (screen->display->xdisplay, screen->xroot, 0);
678 if (meta_error_trap_pop_with_return (screen->display, FALSE(0)) != Success0)
679 meta_warning (_("Could not release screen %d on display \"%s\"\n")((char *) g_dgettext ("marco", "Could not release screen %d on display \"%s\"\n"
))
,
680 screen->number, screen->display->name);
681
682 unset_wm_check_hint (screen);
683
684 XDestroyWindow (screen->display->xdisplay,
685 screen->wm_sn_selection_window);
686
687 if (screen->work_area_idle != 0)
688 g_source_remove (screen->work_area_idle);
689
690 if (XGetGCValues (screen->display->xdisplay,
691 screen->root_xor_gc,
692 GCFont(1L<<14),
693 &gc_values))
694 {
695 XUnloadFont (screen->display->xdisplay,
696 gc_values.font);
697 }
698
699 XFreeGC (screen->display->xdisplay,
700 screen->root_xor_gc);
701
702 if (screen->xinerama_infos)
703 g_free (screen->xinerama_infos);
704
705 if (screen->tile_preview_timeout_id)
706 g_source_remove (screen->tile_preview_timeout_id);
707
708 if (screen->tile_preview)
709 meta_tile_preview_free (screen->tile_preview);
710
711 g_free (screen->screen_name);
712 g_free (screen);
713
714 XFlush (display->xdisplay);
715 meta_display_ungrab (display);
716}
717
718typedef struct
719{
720 Window xwindow;
721 XWindowAttributes attrs;
722} WindowInfo;
723
724static GList *
725list_windows (MetaScreen *screen)
726{
727 Window ignored1, ignored2;
728 Window *children;
729 guint n_children, i;
730 GList *result;
731
732 XQueryTree (screen->display->xdisplay,
733 screen->xroot,
734 &ignored1, &ignored2, &children, &n_children);
735
736 result = NULL((void*)0);
737 for (i = 0; i < n_children; ++i)
738 {
739 WindowInfo *info = g_new0 (WindowInfo, 1)((WindowInfo *) g_malloc0_n ((1), sizeof (WindowInfo)));
740
741 meta_error_trap_push (screen->display);
742
743 XGetWindowAttributes (screen->display->xdisplay,
744 children[i], &info->attrs);
745
746 if (meta_error_trap_pop_with_return (screen->display, TRUE(!(0))))
747 {
748 meta_verbosemeta_verbose_real ("Failed to get attributes for window 0x%lx\n",
749 children[i]);
750 g_free (info);
751 }
752 else
753 {
754 info->xwindow = children[i];
755 result = g_list_prepend (result, info);
756 }
757 }
758
759 if (children)
760 XFree (children);
761
762 return g_list_reverse (result);
763}
764
765void
766meta_screen_manage_all_windows (MetaScreen *screen)
767{
768 GList *windows;
769 GList *list;
770
771 meta_display_grab (screen->display);
772
773 windows = list_windows (screen);
774
775 meta_stack_freeze (screen->stack);
776 for (list = windows; list != NULL((void*)0); list = list->next)
777 {
778 WindowInfo *info = list->data;
779 MetaWindow *window;
780 gboolean test_window_owner;
781
782 window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE(!(0)),
783 &info->attrs);
784 test_window_owner = info->xwindow == screen->no_focus_window ||
785 info->xwindow == screen->flash_window ||
786 info->xwindow == screen->wm_sn_selection_window;
787
788#ifdef HAVE_COMPOSITE_EXTENSIONS1
789 test_window_owner = test_window_owner || info->xwindow == screen->wm_cm_selection_window;
790#endif
791 if (test_window_owner)
792 {
793 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
794 continue;
795 }
796
797 if (screen->display->compositor)
798 meta_compositor_add_window (screen->display->compositor, window,
799 info->xwindow, &info->attrs);
800 }
801 meta_stack_thaw (screen->stack);
802
803 g_list_free_full (windows, g_free);
804
805 meta_display_ungrab (screen->display);
806}
807
808void
809meta_screen_composite_all_windows (MetaScreen *screen)
810{
811#ifdef HAVE_COMPOSITE_EXTENSIONS1
812 MetaDisplay *display;
813 GList *windows, *list;
814
815 display = screen->display;
816 if (!display->compositor)
817 return;
818
819 windows = list_windows (screen);
820
821 meta_stack_freeze (screen->stack);
822
823 for (list = windows; list != NULL((void*)0); list = list->next)
824 {
825 WindowInfo *info = list->data;
826
827 if (info->xwindow == screen->no_focus_window ||
828 info->xwindow == screen->flash_window ||
829 info->xwindow == screen->wm_sn_selection_window ||
830 info->xwindow == screen->wm_cm_selection_window) {
831 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
832 continue;
833 }
834
835 meta_compositor_add_window (display->compositor,
836 meta_display_lookup_x_window (display,
837 info->xwindow),
838 info->xwindow, &info->attrs);
839 }
840
841 meta_stack_thaw (screen->stack);
842
843 g_list_free_full (windows, g_free);
844#endif
845}
846
847MetaScreen*
848meta_screen_for_x_screen (Screen *xscreen)
849{
850 MetaDisplay *display;
851
852 display = meta_display_for_x_display (DisplayOfScreen (xscreen)((xscreen)->display));
853
854 if (display == NULL((void*)0))
855 return NULL((void*)0);
856
857 return meta_display_screen_for_x_screen (display, xscreen);
858}
859
860static void
861prefs_changed_callback (MetaPreference pref,
862 gpointer data)
863{
864 MetaScreen *screen = data;
865
866 if (pref == META_PREF_NUM_WORKSPACES)
867 {
868 /* GSettings doesn't provide timestamps, but luckily update_num_workspaces
869 * often doesn't need it...
870 */
871 guint32 timestamp =
872 meta_display_get_current_time_roundtrip (screen->display);
873 update_num_workspaces (screen, timestamp);
874 }
875 else if (pref == META_PREF_FOCUS_MODE)
876 {
877 update_focus_mode (screen);
878 }
879 else if (pref == META_PREF_WORKSPACE_NAMES)
880 {
881 set_workspace_names (screen);
882 }
883}
884
885static char*
886get_screen_name (MetaDisplay *display,
887 int number)
888{
889 char *p;
890 char *dname;
891 char *scr;
892
893 /* DisplayString gives us a sort of canonical display,
894 * vs. the user-entered name from XDisplayName()
895 */
896 dname = g_strdup (DisplayString (display->xdisplay))g_strdup_inline ((((_XPrivDisplay)(display->xdisplay))->
display_name))
;
897
898 /* Change display name to specify this screen.
899 */
900 p = strrchr (dname, ':');
901 if (p)
902 {
903 p = strchr (p, '.');
904 if (p)
905 *p = '\0';
906 }
907
908 scr = g_strdup_printf ("%s.%d", dname, number);
909
910 g_free (dname);
911
912 return scr;
913}
914
915static gint
916ptrcmp (gconstpointer a, gconstpointer b)
917{
918 if (a < b)
919 return -1;
920 else if (a > b)
921 return 1;
922 else
923 return 0;
924}
925
926static void
927listify_func (gpointer key, gpointer value, gpointer data)
928{
929 GSList **listp;
930
931 listp = data;
932
933 *listp = g_slist_prepend (*listp, value);
934}
935
936void
937meta_screen_foreach_window (MetaScreen *screen,
938 MetaScreenWindowFunc func,
939 gpointer data)
940{
941 GSList *winlist;
942 GSList *tmp;
943
944 /* If we end up doing this often, just keeping a list
945 * of windows might be sensible.
946 */
947
948 winlist = NULL((void*)0);
949 g_hash_table_foreach (screen->display->window_ids,
950 listify_func,
951 &winlist);
952
953 winlist = g_slist_sort (winlist, ptrcmp);
954
955 tmp = winlist;
956 while (tmp != NULL((void*)0))
957 {
958 /* If the next node doesn't contain this window
959 * a second time, delete the window.
960 */
961 if (tmp->next == NULL((void*)0) ||
962 (tmp->next && tmp->next->data != tmp->data))
963 {
964 MetaWindow *window = tmp->data;
965
966 if (window->screen == screen)
967 (* func) (screen, window, data);
968 }
969
970 tmp = tmp->next;
971 }
972 g_slist_free (winlist);
973}
974
975static void
976queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
977{
978 if (window->frame)
979 meta_frame_queue_draw (window->frame);
980}
981
982void
983meta_screen_queue_frame_redraws (MetaScreen *screen)
984{
985 meta_screen_foreach_window (screen, queue_draw, NULL((void*)0));
986}
987
988static void
989queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
990{
991 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
992}
993
994void
995meta_screen_queue_window_resizes (MetaScreen *screen)
996{
997 meta_screen_foreach_window (screen, queue_resize, NULL((void*)0));
998}
999
1000int
1001meta_screen_get_n_workspaces (MetaScreen *screen)
1002{
1003 return g_list_length (screen->workspaces);
1004}
1005
1006MetaWorkspace*
1007meta_screen_get_workspace_by_index (MetaScreen *screen,
1008 int idx)
1009{
1010 GList *tmp;
1011 int i;
1012
1013 /* should be robust, idx is maybe from an app */
1014 if (idx < 0)
1015 return NULL((void*)0);
1016
1017 i = 0;
1018 tmp = screen->workspaces;
1019 while (tmp != NULL((void*)0))
1020 {
1021 MetaWorkspace *w = tmp->data;
1022
1023 if (i == idx)
1024 return w;
1025
1026 ++i;
1027 tmp = tmp->next;
1028 }
1029
1030 return NULL((void*)0);
1031}
1032
1033static void
1034set_number_of_spaces_hint (MetaScreen *screen,
1035 int n_spaces)
1036{
1037 unsigned long data[1];
1038
1039 if (screen->closing > 0)
1040 return;
1041
1042 data[0] = n_spaces;
1043
1044 meta_verbosemeta_verbose_real ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
1045
1046 meta_error_trap_push (screen->display);
1047 XChangeProperty (screen->display->xdisplay, screen->xroot,
1048 screen->display->atom__NET_NUMBER_OF_DESKTOPS,
1049 XA_CARDINAL((Atom) 6),
1050 32, PropModeReplace0, (guchar*) data, 1);
1051 meta_error_trap_pop (screen->display, FALSE(0));
1052}
1053
1054static void
1055set_desktop_geometry_hint (MetaScreen *screen)
1056{
1057 unsigned long data[2];
1058
1059 if (screen->closing > 0)
1060 return;
1061
1062 data[0] = screen->rect.width;
1063 data[1] = screen->rect.height;
1064
1065 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
1066
1067 meta_error_trap_push (screen->display);
1068 XChangeProperty (screen->display->xdisplay, screen->xroot,
1069 screen->display->atom__NET_DESKTOP_GEOMETRY,
1070 XA_CARDINAL((Atom) 6),
1071 32, PropModeReplace0, (guchar*) data, 2);
1072 meta_error_trap_pop (screen->display, FALSE(0));
1073}
1074
1075static void
1076set_desktop_viewport_hint (MetaScreen *screen)
1077{
1078 unsigned long data[2];
1079
1080 if (screen->closing > 0)
1081 return;
1082
1083 /*
1084 * Marco does not implement viewports, so this is a fixed 0,0
1085 */
1086 data[0] = 0;
1087 data[1] = 0;
1088
1089 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
1090
1091 meta_error_trap_push (screen->display);
1092 XChangeProperty (screen->display->xdisplay, screen->xroot,
1093 screen->display->atom__NET_DESKTOP_VIEWPORT,
1094 XA_CARDINAL((Atom) 6),
1095 32, PropModeReplace0, (guchar*) data, 2);
1096 meta_error_trap_pop (screen->display, FALSE(0));
1097}
1098
1099static void
1100update_num_workspaces (MetaScreen *screen,
1101 guint32 timestamp)
1102{
1103 int new_num;
1104 GList *tmp;
1105 int i;
1106 GList *extras;
1107 MetaWorkspace *last_remaining;
1108 gboolean need_change_space;
1109
1110 new_num = meta_prefs_get_num_workspaces ();
1111
1112 g_assert (new_num > 0)do { if (new_num > 0) ; else g_assertion_message_expr ("marco"
, "core/screen.c", 1112, ((const char*) (__func__)), "new_num > 0"
); } while (0)
;
1113
1114 last_remaining = NULL((void*)0);
1115 extras = NULL((void*)0);
1116 i = 0;
1117 tmp = screen->workspaces;
1118 while (tmp != NULL((void*)0))
1119 {
1120 MetaWorkspace *w = tmp->data;
1121
1122 if (i >= new_num)
1123 extras = g_list_prepend (extras, w);
1124 else
1125 last_remaining = w;
1126
1127 ++i;
1128 tmp = tmp->next;
1129 }
1130
1131 g_assert (last_remaining)do { if (last_remaining) ; else g_assertion_message_expr ("marco"
, "core/screen.c", 1131, ((const char*) (__func__)), "last_remaining"
); } while (0)
;
1132
1133 /* Get rid of the extra workspaces by moving all their windows
1134 * to last_remaining, then activating last_remaining if
1135 * one of the removed workspaces was active. This will be a bit
1136 * wacky if the config tool for changing number of workspaces
1137 * is on a removed workspace ;-)
1138 */
1139 need_change_space = FALSE(0);
1140 tmp = extras;
1141 while (tmp != NULL((void*)0))
1142 {
1143 MetaWorkspace *w = tmp->data;
1144
1145 meta_workspace_relocate_windows (w, last_remaining);
1146
1147 if (w == screen->active_workspace)
1148 need_change_space = TRUE(!(0));
1149
1150 tmp = tmp->next;
1151 }
1152
1153 if (need_change_space)
1154 meta_workspace_activate (last_remaining, timestamp);
1155
1156 /* Should now be safe to free the workspaces */
1157 tmp = extras;
1158 while (tmp != NULL((void*)0))
1159 {
1160 MetaWorkspace *w = tmp->data;
1161
1162 g_assert (w->windows == NULL)do { if (w->windows == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 1162, ((const char*) (__func__)),
"w->windows == NULL"); } while (0)
;
1163 meta_workspace_free (w);
1164
1165 tmp = tmp->next;
1166 }
1167
1168 g_list_free (extras);
1169
1170 while (i < new_num)
1171 {
1172 meta_workspace_new (screen);
1173 ++i;
1174 }
1175
1176 set_number_of_spaces_hint (screen, new_num);
1177
1178 meta_screen_queue_workarea_recalc (screen);
1179}
1180
1181static void
1182update_focus_mode (MetaScreen *screen)
1183{
1184 /* nothing to do anymore */ ;
1185}
1186
1187void
1188meta_screen_set_cursor (MetaScreen *screen,
1189 MetaCursor cursor)
1190{
1191 Cursor xcursor;
1192
1193 if (cursor == screen->current_cursor)
1194 return;
1195
1196 screen->current_cursor = cursor;
1197
1198 xcursor = meta_display_create_x_cursor (screen->display, cursor);
1199 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1200 XFlush (screen->display->xdisplay);
1201 XFreeCursor (screen->display->xdisplay, xcursor);
1202}
1203
1204void
1205meta_screen_update_cursor (MetaScreen *screen)
1206{
1207 Cursor xcursor;
1208
1209 xcursor = meta_display_create_x_cursor (screen->display,
1210 screen->current_cursor);
1211 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1212 XFlush (screen->display->xdisplay);
1213 XFreeCursor (screen->display->xdisplay, xcursor);
1214}
1215
1216#define MAX_PREVIEW_SCREEN_FRACTION0.33 0.33
1217#define MAX_PREVIEW_SIZE300.0 300.0
1218
1219static cairo_surface_t *
1220get_window_surface (MetaWindow *window)
1221{
1222 cairo_surface_t *surface, *scaled;
1223 cairo_t *cr;
1224 const MetaXineramaScreenInfo *current;
1225 int width, height, max_columns;
1226 double max_size;
1227 double ratio;
1228
1229 surface = meta_compositor_get_window_surface (window->display->compositor, window);
1230
1231 if (surface == NULL((void*)0))
1232 return NULL((void*)0);
1233
1234 width = cairo_xlib_surface_get_width (surface);
1235 height = cairo_xlib_surface_get_height (surface);
1236
1237 current = meta_screen_get_current_xinerama (window->screen);
1238 max_columns = meta_prefs_get_alt_tab_max_columns ();
1239
1240 /* Scale surface to fit current screen */
1241 if (width > height)
1242 {
1243 max_size = MIN (MAX_PREVIEW_SIZE, MAX_PREVIEW_SCREEN_FRACTION * ((double) current->rect.width) / ((double) max_columns))(((300.0) < (0.33 * ((double) current->rect.width) / ((
double) max_columns))) ? (300.0) : (0.33 * ((double) current->
rect.width) / ((double) max_columns)))
;
1244 ratio = ((double) width) / max_size;
1245 width = (int) max_size;
1246 height = (int) (((double) height) / ratio);
1247 }
1248 else
1249 {
1250 max_size = MIN (MAX_PREVIEW_SIZE, MAX_PREVIEW_SCREEN_FRACTION * ((double) current->rect.height) / ((double) max_columns))(((300.0) < (0.33 * ((double) current->rect.height) / (
(double) max_columns))) ? (300.0) : (0.33 * ((double) current
->rect.height) / ((double) max_columns)))
;
1251 ratio = ((double) height) / max_size;
1252 height = (int) max_size;
1253 width = (int) (((double) width) / ratio);
1254 }
1255
1256 meta_error_trap_push (window->display);
1257 scaled = cairo_surface_create_similar (surface,
1258 cairo_surface_get_content (surface),
1259 width, height);
1260 if (meta_error_trap_pop_with_return (window->display, FALSE(0)) != Success0)
1261 return NULL((void*)0);
1262
1263 cr = cairo_create (scaled);
1264 cairo_scale (cr, 1/ratio, 1/ratio);
1265 cairo_set_source_surface (cr, surface, 0, 0);
1266 cairo_paint (cr);
1267
1268 cairo_destroy (cr);
1269 cairo_surface_destroy (surface);
1270
1271 return scaled;
1272}
1273
1274void
1275meta_screen_ensure_tab_popup (MetaScreen *screen,
1276 MetaTabList list_type,
1277 MetaTabShowType show_type)
1278{
1279 MetaTabEntry *entries;
1280 GList *tab_list;
1281 GList *tmp;
1282 int len;
1283 int i;
1284 gint border;
1285 int scale;
1286
1287 if (screen->tab_popup)
1288 return;
1289
1290 tab_list = meta_display_get_tab_list (screen->display,
1291 list_type,
1292 screen,
1293 screen->active_workspace);
1294
1295 len = g_list_length (tab_list);
1296 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
1297
1298 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1299 entries[len].key = NULL((void*)0);
1300 entries[len].title = NULL((void*)0);
1301 entries[len].icon = NULL((void*)0);
1302 entries[len].win_surface = NULL((void*)0);
1303
1304 border = meta_prefs_show_tab_border() ? BORDER_OUTLINE_TAB |
1305 BORDER_OUTLINE_WINDOW : BORDER_OUTLINE_TAB;
1306 i = 0;
1307 tmp = tab_list;
1308 while (i < len)
1309 {
1310 MetaWindow *window;
1311 MetaRectangle r;
1312
1313 window = tmp->data;
1314
1315 entries[i].key = (MetaTabEntryKey) window->xwindow;
1316 entries[i].title = window->title;
1317 entries[i].win_surface = NULL((void*)0);
1318
1319 entries[i].icon = g_object_ref (window->icon)((__typeof__ (window->icon)) (g_object_ref) (window->icon
))
;
1320
1321 /* Only get the window thumbnail surface if the user has a compositor
1322 * enabled and does NOT have compositing-fast-alt-tab-set to true in
1323 * GSettings. There is an obvious lag when the surface is retrieved. */
1324 if (meta_prefs_get_compositing_manager() && !meta_prefs_get_compositing_fast_alt_tab())
1325 {
1326 cairo_surface_t *win_surface;
1327
1328 /* Get window thumbnail */
1329 win_surface = get_window_surface (window);
1330
1331 if (win_surface != NULL((void*)0))
1332 {
1333 cairo_surface_t *surface, *icon;
1334 cairo_t *cr;
1335 int width, height, icon_width, icon_height;
1336
1337#define ICON_OFFSET6 6
1338
1339 width = cairo_xlib_surface_get_width (win_surface);
1340 height = cairo_xlib_surface_get_height (win_surface);
1341
1342 /* Create a new surface to overlap the window icon into */
1343 surface = cairo_surface_create_similar (win_surface,
1344 cairo_surface_get_content (win_surface),
1345 width, height);
1346
1347 cr = cairo_create (surface);
1348 cairo_set_source_surface (cr, win_surface, 0, 0);
1349 cairo_paint (cr);
1350
1351 /* Get the window icon as a surface */
1352 icon = gdk_cairo_surface_create_from_pixbuf (window->icon, scale, NULL((void*)0));
1353
1354 icon_width = cairo_image_surface_get_width (icon) / scale;
1355 icon_height = cairo_image_surface_get_height (icon) / scale;
1356
1357 /* Overlap the window icon surface over the window thumbnail */
1358 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
1359 cairo_set_source_surface (cr, icon,
1360 width - icon_width - ICON_OFFSET6,
1361 height - icon_height - ICON_OFFSET6);
1362 cairo_paint (cr);
1363
1364 entries[i].win_surface = surface;
1365
1366 cairo_destroy (cr);
1367 cairo_surface_destroy (icon);
1368 cairo_surface_destroy (win_surface);
1369 }
1370 }
1371
1372 entries[i].blank = FALSE(0);
1373 entries[i].hidden = !meta_window_showing_on_its_workspace (window);
1374 entries[i].demands_attention = window->wm_state_demands_attention;
1375
1376 if (show_type == META_TAB_SHOW_INSTANTLY ||
1377 !entries[i].hidden ||
1378 !meta_window_get_icon_geometry (window, &r))
1379 meta_window_get_outer_rect (window, &r);
1380
1381 entries[i].rect = r;
1382
1383 /* Find inside of highlight rectangle to be used when window is
1384 * outlined for tabbing. This should be the size of the
1385 * east/west frame, and the size of the south frame, on those
1386 * sides. On the top it should be the size of the south frame
1387 * edge.
1388 */
1389 if (border & BORDER_OUTLINE_WINDOW)
1390 {
1391#define OUTLINE_WIDTH5 5
1392 /* Top side */
1393 entries[i].inner_rect.y = OUTLINE_WIDTH5;
1394
1395 /* Bottom side */
1396 entries[i].inner_rect.height = r.height - entries[i].inner_rect.y - OUTLINE_WIDTH5;
1397
1398 /* Left side */
1399 entries[i].inner_rect.x = OUTLINE_WIDTH5;
1400
1401 /* Right side */
1402 entries[i].inner_rect.width = r.width - entries[i].inner_rect.x - OUTLINE_WIDTH5;
1403 }
1404
1405 ++i;
1406 tmp = tmp->next;
1407 }
1408
1409 screen->tab_popup = meta_ui_tab_popup_new (entries,
1410 screen,
1411 len,
1412 meta_prefs_get_alt_tab_max_columns(),
1413 meta_prefs_get_alt_tab_expand_to_fit_title(),
1414 border);
1415
1416 for (i = 0; i < len; i++)
1417 {
1418 g_object_unref (entries[i].icon);
1419 if (entries[i].win_surface)
1420 cairo_surface_destroy (entries[i].win_surface);
1421 }
1422
1423 g_free (entries);
1424
1425 g_list_free (tab_list);
1426
1427 /* don't show tab popup, since proper window isn't selected yet */
1428}
1429
1430void
1431meta_screen_ensure_workspace_popup (MetaScreen *screen)
1432{
1433 MetaTabEntry *entries;
1434 int len;
1435 int i;
1436 MetaWorkspaceLayout layout;
1437 int n_workspaces;
1438 int current_workspace;
1439
1440 if (screen->tab_popup)
1441 return;
1442
1443 current_workspace = meta_workspace_index (screen->active_workspace);
1444 n_workspaces = meta_screen_get_n_workspaces (screen);
1445
1446 meta_screen_calc_workspace_layout (screen, n_workspaces,
1447 current_workspace, &layout);
1448
1449 len = layout.grid_area;
1450
1451 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1452 entries[len].key = NULL((void*)0);
1453 entries[len].title = NULL((void*)0);
1454 entries[len].icon = NULL((void*)0);
1455 entries[len].win_surface = NULL((void*)0);
1456
1457 i = 0;
1458 while (i < len)
1459 {
1460 if (layout.grid[i] >= 0)
1461 {
1462 MetaWorkspace *workspace;
1463
1464 workspace = meta_screen_get_workspace_by_index (screen,
1465 layout.grid[i]);
1466
1467 entries[i].key = (MetaTabEntryKey) workspace;
1468 entries[i].title = meta_workspace_get_name (workspace);
1469 entries[i].icon = NULL((void*)0);
1470 entries[i].win_surface = NULL((void*)0);
1471 entries[i].blank = FALSE(0);
1472
1473 g_assert (entries[i].title != NULL)do { if (entries[i].title != ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 1473, ((const char*) (__func__)),
"entries[i].title != NULL"); } while (0)
;
1474 }
1475 else
1476 {
1477 entries[i].key = NULL((void*)0);
1478 entries[i].title = NULL((void*)0);
1479 entries[i].icon = NULL((void*)0);
1480 entries[i].win_surface = NULL((void*)0);
1481 entries[i].blank = TRUE(!(0));
1482 }
1483 entries[i].hidden = FALSE(0);
1484 entries[i].demands_attention = FALSE(0);
1485
1486 ++i;
1487 }
1488
1489 screen->tab_popup = meta_ui_tab_popup_new (entries,
1490 screen,
1491 len,
1492 layout.cols,
1493 FALSE(0), /* expand_for_titles */
1494 BORDER_OUTLINE_WORKSPACE);
1495
1496 g_free (entries);
1497 meta_screen_free_workspace_layout (&layout);
1498
1499 /* don't show tab popup, since proper space isn't selected yet */
1500}
1501
1502static gboolean
1503meta_screen_tile_preview_update_timeout (gpointer data)
1504{
1505 MetaScreen *screen = data;
1506 MetaWindow *window = screen->display->grab_window;
1507 gboolean needs_preview = FALSE(0);
1508
1509 screen->tile_preview_timeout_id = 0;
1510
1511 if (!screen->tile_preview)
1512 screen->tile_preview = meta_tile_preview_new ();
1513
1514 if (window)
1515 {
1516 switch (window->tile_mode)
1517 {
1518 case META_TILE_MAXIMIZED:
1519 if (!META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
)
1520 needs_preview = TRUE(!(0));
1521 break;
1522
1523 case META_TILE_NONE:
1524 needs_preview = FALSE(0);
1525 break;
1526
1527 default:
1528 if (!META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
)
1529 needs_preview = TRUE(!(0));
1530 break;
1531
1532 }
1533 }
1534
1535 if (needs_preview)
1536 {
1537 MetaRectangle tile_rect;
1538
1539 meta_window_get_current_tile_area (window, &tile_rect);
1540 meta_tile_preview_show (screen->tile_preview, &tile_rect, screen);
1541 }
1542 else
1543 meta_tile_preview_hide (screen->tile_preview);
1544
1545 return FALSE(0);
1546}
1547
1548#define TILE_PREVIEW_TIMEOUT_MS200 200
1549
1550void
1551meta_screen_tile_preview_update (MetaScreen *screen,
1552 gboolean delay)
1553{
1554 if (delay)
1555 {
1556 if (screen->tile_preview_timeout_id > 0)
1557 return;
1558
1559 screen->tile_preview_timeout_id =
1560 g_timeout_add (TILE_PREVIEW_TIMEOUT_MS200,
1561 meta_screen_tile_preview_update_timeout,
1562 screen);
1563 }
1564 else
1565 {
1566 if (screen->tile_preview_timeout_id > 0)
1567 g_source_remove (screen->tile_preview_timeout_id);
1568
1569 meta_screen_tile_preview_update_timeout ((gpointer)screen);
1570 }
1571}
1572
1573void
1574meta_screen_tile_preview_hide (MetaScreen *screen)
1575{
1576 if (screen->tile_preview_timeout_id > 0)
1577 g_source_remove (screen->tile_preview_timeout_id);
1578
1579 if (screen->tile_preview)
1580 meta_tile_preview_hide (screen->tile_preview);
1581}
1582
1583MetaWindow*
1584meta_screen_get_mouse_window (MetaScreen *screen,
1585 MetaWindow *not_this_one)
1586{
1587 MetaWindow *window;
1588 Window root_return, child_return;
1589 int root_x_return, root_y_return;
1590 int win_x_return, win_y_return;
1591 unsigned int mask_return;
1592
1593 if (not_this_one)
1594 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1595 "Focusing mouse window excluding %s\n", not_this_one->desc);
1596
1597 meta_error_trap_push (screen->display);
1598 XQueryPointer (screen->display->xdisplay,
1599 screen->xroot,
1600 &root_return,
1601 &child_return,
1602 &root_x_return,
1603 &root_y_return,
1604 &win_x_return,
1605 &win_y_return,
1606 &mask_return);
1607 meta_error_trap_pop (screen->display, TRUE(!(0)));
1608
1609 window = meta_stack_get_default_focus_window_at_point (screen->stack,
1610 screen->active_workspace,
1611 not_this_one,
1612 root_x_return,
1613 root_y_return);
1614
1615 return window;
1616}
1617
1618const MetaXineramaScreenInfo*
1619meta_screen_get_xinerama_for_rect (MetaScreen *screen,
1620 MetaRectangle *rect)
1621{
1622 int i;
1623 int best_xinerama, xinerama_score;
1624
1625 if (screen->n_xinerama_infos == 1)
1626 return &screen->xinerama_infos[0];
1627
1628 best_xinerama = 0;
1629 xinerama_score = 0;
1630
1631 for (i = 0; i < screen->n_xinerama_infos; i++)
1632 {
1633 MetaRectangle dest;
1634 if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
1635 rect,
1636 &dest))
1637 {
1638 int cur = meta_rectangle_area (&dest);
1639 if (cur > xinerama_score)
1640 {
1641 xinerama_score = cur;
1642 best_xinerama = i;
1643 }
1644 }
1645 }
1646
1647 return &screen->xinerama_infos[best_xinerama];
1648}
1649
1650const MetaXineramaScreenInfo*
1651meta_screen_get_xinerama_for_window (MetaScreen *screen,
1652 MetaWindow *window)
1653{
1654 MetaRectangle window_rect;
1655
1656 meta_window_get_outer_rect (window, &window_rect);
1657
1658 return meta_screen_get_xinerama_for_rect (screen, &window_rect);
1659}
1660
1661const MetaXineramaScreenInfo*
1662meta_screen_get_xinerama_neighbor (MetaScreen *screen,
1663 int which_xinerama,
1664 MetaScreenDirection direction)
1665{
1666 MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
1667 MetaXineramaScreenInfo* current;
1668 int i;
1669
1670 for (i = 0; i < screen->n_xinerama_infos; i++)
1671 {
1672 current = screen->xinerama_infos + i;
1673
1674 if ((direction == META_SCREEN_RIGHT &&
1675 current->rect.x == input->rect.x + input->rect.width &&
1676 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1677 (direction == META_SCREEN_LEFT &&
1678 input->rect.x == current->rect.x + current->rect.width &&
1679 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1680 (direction == META_SCREEN_UP &&
1681 input->rect.y == current->rect.y + current->rect.height &&
1682 meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
1683 (direction == META_SCREEN_DOWN &&
1684 current->rect.y == input->rect.y + input->rect.height &&
1685 meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
1686 {
1687 return current;
1688 }
1689 }
1690
1691 return NULL((void*)0);
1692}
1693
1694void
1695meta_screen_get_natural_xinerama_list (MetaScreen *screen,
1696 int** xineramas_list,
1697 int* n_xineramas)
1698{
1699 const MetaXineramaScreenInfo* current;
1700 const MetaXineramaScreenInfo* tmp;
1701 GQueue* xinerama_queue;
1702 int* visited;
1703 int cur = 0;
1704 int i;
1705
1706 *n_xineramas = screen->n_xinerama_infos;
1707 *xineramas_list = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1708
1709 /* we calculate a natural ordering by which to choose xineramas for
1710 * window placement. We start at the current xinerama, and perform
1711 * a breadth-first search of the xineramas starting from that
1712 * xinerama. We choose preferentially left, then right, then down,
1713 * then up. The visitation order produced by this traversal is the
1714 * natural xinerama ordering.
1715 */
1716
1717 visited = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1718 for (i = 0; i < screen->n_xinerama_infos; i++)
1
Assuming 'i' is < field 'n_xinerama_infos'
2
Loop condition is true. Entering loop body
3
Assuming 'i' is >= field 'n_xinerama_infos'
4
Loop condition is false. Execution continues on line 1723
1719 {
1720 visited[i] = FALSE(0);
1721 }
1722
1723 current = meta_screen_get_current_xinerama (screen);
1724 xinerama_queue = g_queue_new ();
1725 g_queue_push_tail (xinerama_queue, (gpointer) current);
1726 visited[current->number] = TRUE(!(0));
1727
1728 while (!g_queue_is_empty (xinerama_queue))
5
Assuming the condition is true
6
Loop condition is true. Entering loop body
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
1729 {
1730 current = (const MetaXineramaScreenInfo*)
1731 g_queue_pop_head (xinerama_queue);
1732
1733 (*xineramas_list)[cur++] = current->number;
11
Out of bound memory access (access exceeds upper limit of memory block)
1734
1735 /* enqueue each of the directions */
1736 tmp = meta_screen_get_xinerama_neighbor (screen,
1737 current->number,
1738 META_SCREEN_LEFT);
1739 if (tmp
6.1
'tmp' is null
&& !visited[tmp->number])
1740 {
1741 g_queue_push_tail (xinerama_queue,
1742 (MetaXineramaScreenInfo*) tmp);
1743 visited[tmp->number] = TRUE(!(0));
1744 }
1745 tmp = meta_screen_get_xinerama_neighbor (screen,
1746 current->number,
1747 META_SCREEN_RIGHT);
1748 if (tmp
6.2
'tmp' is null
&& !visited[tmp->number])
1749 {
1750 g_queue_push_tail (xinerama_queue,
1751 (MetaXineramaScreenInfo*) tmp);
1752 visited[tmp->number] = TRUE(!(0));
1753 }
1754 tmp = meta_screen_get_xinerama_neighbor (screen,
1755 current->number,
1756 META_SCREEN_UP);
1757 if (tmp && !visited[tmp->number])
7
Assuming 'tmp' is null
1758 {
1759 g_queue_push_tail (xinerama_queue,
1760 (MetaXineramaScreenInfo*) tmp);
1761 visited[tmp->number] = TRUE(!(0));
1762 }
1763 tmp = meta_screen_get_xinerama_neighbor (screen,
1764 current->number,
1765 META_SCREEN_DOWN);
1766 if (tmp && !visited[tmp->number])
8
Assuming 'tmp' is null
1767 {
1768 g_queue_push_tail (xinerama_queue,
1769 (MetaXineramaScreenInfo*) tmp);
1770 visited[tmp->number] = TRUE(!(0));
1771 }
1772 }
1773
1774 /* in case we somehow missed some set of xineramas, go through the
1775 * visited list and add in any xineramas that were missed
1776 */
1777 for (i = 0; i < screen->n_xinerama_infos; i++)
1778 {
1779 if (visited[i] == FALSE(0))
1780 {
1781 (*xineramas_list)[cur++] = i;
1782 }
1783 }
1784
1785 g_free (visited);
1786 g_queue_free (xinerama_queue);
1787}
1788
1789const MetaXineramaScreenInfo*
1790meta_screen_get_current_xinerama (MetaScreen *screen)
1791{
1792 if (screen->n_xinerama_infos == 1)
1793 return &screen->xinerama_infos[0];
1794
1795 /* Sadly, we have to do it this way. Yuck.
1796 */
1797
1798 if (screen->display->xinerama_cache_invalidated)
1799 {
1800 Window root_return, child_return;
1801 int win_x_return, win_y_return;
1802 unsigned int mask_return;
1803 int i;
1804 MetaRectangle pointer_position;
1805
1806 screen->display->xinerama_cache_invalidated = FALSE(0);
1807
1808 pointer_position.width = pointer_position.height = 1;
1809 XQueryPointer (screen->display->xdisplay,
1810 screen->xroot,
1811 &root_return,
1812 &child_return,
1813 &pointer_position.x,
1814 &pointer_position.y,
1815 &win_x_return,
1816 &win_y_return,
1817 &mask_return);
1818
1819 screen->last_xinerama_index = 0;
1820 for (i = 0; i < screen->n_xinerama_infos; i++)
1821 {
1822 if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
1823 &pointer_position))
1824 {
1825 screen->last_xinerama_index = i;
1826 break;
1827 }
1828 }
1829
1830 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
1831 "Rechecked current Xinerama, now %d\n",
1832 screen->last_xinerama_index);
1833 }
1834
1835 return &screen->xinerama_infos[screen->last_xinerama_index];
1836}
1837
1838#define _NET_WM_ORIENTATION_HORZ0 0
1839#define _NET_WM_ORIENTATION_VERT1 1
1840
1841#define _NET_WM_TOPLEFT0 0
1842#define _NET_WM_TOPRIGHT1 1
1843#define _NET_WM_BOTTOMRIGHT2 2
1844#define _NET_WM_BOTTOMLEFT3 3
1845
1846void
1847meta_screen_update_workspace_layout (MetaScreen *screen)
1848{
1849 gulong *list;
1850 int n_items;
1851
1852 list = NULL((void*)0);
1853 n_items = 0;
1854
1855 if (meta_prop_get_cardinal_list (screen->display,
1856 screen->xroot,
1857 screen->display->atom__NET_DESKTOP_LAYOUT,
1858 &list, &n_items))
1859 {
1860 if (n_items == 3 || n_items == 4)
1861 {
1862 int cols, rows;
1863
1864 switch (list[0])
1865 {
1866 case _NET_WM_ORIENTATION_HORZ0:
1867 screen->vertical_workspaces = FALSE(0);
1868 break;
1869 case _NET_WM_ORIENTATION_VERT1:
1870 screen->vertical_workspaces = TRUE(!(0));
1871 break;
1872 default:
1873 meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
1874 break;
1875 }
1876
1877 cols = list[1];
1878 rows = list[2];
1879
1880 if (rows <= 0 && cols <= 0)
1881 {
1882 meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
1883 }
1884 else
1885 {
1886 if (rows > 0)
1887 screen->rows_of_workspaces = rows;
1888 else
1889 screen->rows_of_workspaces = -1;
1890
1891 if (cols > 0)
1892 screen->columns_of_workspaces = cols;
1893 else
1894 screen->columns_of_workspaces = -1;
1895 }
1896
1897 if (n_items == 4)
1898 {
1899 switch (list[3])
1900 {
1901 case _NET_WM_TOPLEFT0:
1902 screen->starting_corner = META_SCREEN_TOPLEFT;
1903 break;
1904 case _NET_WM_TOPRIGHT1:
1905 screen->starting_corner = META_SCREEN_TOPRIGHT;
1906 break;
1907 case _NET_WM_BOTTOMRIGHT2:
1908 screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
1909 break;
1910 case _NET_WM_BOTTOMLEFT3:
1911 screen->starting_corner = META_SCREEN_BOTTOMLEFT;
1912 break;
1913 default:
1914 meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
1915 break;
1916 }
1917 }
1918 else
1919 screen->starting_corner = META_SCREEN_TOPLEFT;
1920 }
1921 else
1922 {
1923 meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
1924 "(3 is accepted for backwards compat)\n", n_items);
1925 }
1926
1927 meta_XFree (list)do { if ((list)) XFree ((list)); } while (0);
1928 }
1929
1930 meta_verbosemeta_verbose_real ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
1931 screen->rows_of_workspaces,
1932 screen->columns_of_workspaces,
1933 screen->vertical_workspaces,
1934 screen->starting_corner);
1935}
1936
1937static void
1938set_workspace_names (MetaScreen *screen)
1939{
1940 /* This updates names on root window when the pref changes,
1941 * note we only get prefs change notify if things have
1942 * really changed.
1943 */
1944 GString *flattened;
1945 int i;
1946 int n_spaces;
1947
1948 /* flatten to nul-separated list */
1949 n_spaces = meta_screen_get_n_workspaces (screen);
1950 flattened = g_string_new ("");
1951 i = 0;
1952 while (i < n_spaces)
1953 {
1954 const char *name;
1955
1956 name = meta_prefs_get_workspace_name (i);
1957
1958 if (name)
1959 g_string_append_len (flattened, name,g_string_append_len_inline (flattened, name, strlen (name) + 1
)
1960 strlen (name) + 1)g_string_append_len_inline (flattened, name, strlen (name) + 1
)
;
1961 else
1962 g_string_append_len (flattened, "", 1)g_string_append_len_inline (flattened, "", 1);
1963
1964 ++i;
1965 }
1966
1967 meta_error_trap_push (screen->display);
1968 XChangeProperty (screen->display->xdisplay,
1969 screen->xroot,
1970 screen->display->atom__NET_DESKTOP_NAMES,
1971 screen->display->atom_UTF8_STRING,
1972 8, PropModeReplace0,
1973 (unsigned char *)flattened->str, flattened->len);
1974 meta_error_trap_pop (screen->display, FALSE(0));
1975
1976 g_string_free (flattened, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(flattened), ((!(0)))) : g_string_free_and_steal (flattened))
: (g_string_free) ((flattened), ((!(0)))))
;
1977}
1978
1979void
1980meta_screen_update_workspace_names (MetaScreen *screen)
1981{
1982 char **names;
1983 int n_names;
1984 int i;
1985
1986 /* this updates names in prefs when the root window property changes,
1987 * iff the new property contents don't match what's already in prefs
1988 */
1989
1990 names = NULL((void*)0);
1991 n_names = 0;
1992 if (!meta_prop_get_utf8_list (screen->display,
1993 screen->xroot,
1994 screen->display->atom__NET_DESKTOP_NAMES,
1995 &names, &n_names))
1996 {
1997 meta_verbosemeta_verbose_real ("Failed to get workspace names from root window %d\n",
1998 screen->number);
1999 return;
2000 }
2001
2002 i = 0;
2003 while (i < n_names)
2004 {
2005 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2006 "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
2007 i, names[i] ? names[i] : "null");
2008 meta_prefs_change_workspace_name (i, names[i]);
2009
2010 ++i;
2011 }
2012
2013 g_strfreev (names);
2014}
2015
2016Window
2017meta_create_offscreen_window (Display *xdisplay,
2018 Window parent,
2019 long valuemask)
2020{
2021 XSetWindowAttributes attrs;
2022
2023 /* we want to be override redirect because sometimes we
2024 * create a window on a screen we aren't managing.
2025 * (but on a display we are managing at least one screen for)
2026 */
2027 attrs.override_redirect = True1;
2028 attrs.event_mask = valuemask;
2029
2030 return XCreateWindow (xdisplay,
2031 parent,
2032 -100, -100, 1, 1,
2033 0,
2034 CopyFromParent0L,
2035 CopyFromParent0L,
2036 (Visual *)CopyFromParent0L,
2037 CWOverrideRedirect(1L<<9) | CWEventMask(1L<<11),
2038 &attrs);
2039}
2040
2041static void
2042set_workspace_work_area_hint (MetaWorkspace *workspace,
2043 MetaScreen *screen)
2044{
2045 unsigned long *data;
2046 unsigned long *tmp;
2047 int i;
2048 gchar *workarea_name;
2049 Atom workarea_atom;
2050
2051 data = g_new (unsigned long, screen->n_xinerama_infos * 4)((unsigned long *) g_malloc_n ((screen->n_xinerama_infos *
4), sizeof (unsigned long)))
;
2052 tmp = data;
2053
2054 for (i = 0; i < screen->n_xinerama_infos; i++)
2055 {
2056 MetaRectangle area;
2057
2058 meta_workspace_get_work_area_for_xinerama (workspace, i, &area);
2059
2060 tmp[0] = area.x;
2061 tmp[1] = area.y;
2062 tmp[2] = area.width;
2063 tmp[3] = area.height;
2064
2065 tmp += 4;
2066 }
2067
2068 workarea_name = g_strdup_printf ("_GTK_WORKAREAS_D%d",
2069 meta_workspace_index (workspace));
2070
2071 workarea_atom = XInternAtom (screen->display->xdisplay, workarea_name, False0);
2072 g_free (workarea_name);
2073
2074 meta_error_trap_push (screen->display);
2075 XChangeProperty (screen->display->xdisplay, screen->xroot, workarea_atom,
2076 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2077 (guchar*) data, screen->n_xinerama_infos * 4);
2078 meta_error_trap_pop (screen->display, TRUE(!(0)));
2079
2080 g_free (data);
2081}
2082
2083static void
2084set_work_area_hint (MetaScreen *screen)
2085{
2086 int num_workspaces;
2087 GList *tmp_list;
2088 unsigned long *data, *tmp;
2089 MetaRectangle area;
2090
2091 num_workspaces = meta_screen_get_n_workspaces (screen);
2092 data = g_new (unsigned long, num_workspaces * 4)((unsigned long *) g_malloc_n ((num_workspaces * 4), sizeof (
unsigned long)))
;
2093 tmp_list = screen->workspaces;
2094 tmp = data;
2095
2096 while (tmp_list != NULL((void*)0))
2097 {
2098 MetaWorkspace *workspace = tmp_list->data;
2099
2100 if (workspace->screen == screen)
2101 {
2102 meta_workspace_get_work_area_all_xineramas (workspace, &area);
2103 set_workspace_work_area_hint (workspace, screen);
2104 tmp[0] = area.x;
2105 tmp[1] = area.y;
2106 tmp[2] = area.width;
2107 tmp[3] = area.height;
2108
2109 tmp += 4;
2110 }
2111
2112 tmp_list = tmp_list->next;
2113 }
2114
2115 meta_error_trap_push (screen->display);
2116 XChangeProperty (screen->display->xdisplay, screen->xroot,
2117 screen->display->atom__NET_WORKAREA,
2118 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2119 (guchar*) data, num_workspaces*4);
2120 g_free (data);
2121 meta_error_trap_pop (screen->display, FALSE(0));
2122}
2123
2124static gboolean
2125set_work_area_idle_func (MetaScreen *screen)
2126{
2127 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2128 "Running work area idle function\n");
2129
2130 screen->work_area_idle = 0;
2131
2132 set_work_area_hint (screen);
2133
2134 return FALSE(0);
2135}
2136
2137void
2138meta_screen_queue_workarea_recalc (MetaScreen *screen)
2139{
2140 /* Recompute work area in an idle */
2141 if (screen->work_area_idle == 0)
2142 {
2143 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2144 "Adding work area hint idle function\n");
2145 screen->work_area_idle =
2146 g_idle_add_full (META_PRIORITY_WORK_AREA_HINT(200 + 15),
2147 (GSourceFunc) set_work_area_idle_func,
2148 screen,
2149 NULL((void*)0));
2150 }
2151}
2152
2153#ifdef WITH_VERBOSE_MODE1
2154static char *
2155meta_screen_corner_to_string (MetaScreenCorner corner)
2156{
2157 switch (corner)
2158 {
2159 case META_SCREEN_TOPLEFT:
2160 return "TopLeft";
2161 case META_SCREEN_TOPRIGHT:
2162 return "TopRight";
2163 case META_SCREEN_BOTTOMLEFT:
2164 return "BottomLeft";
2165 case META_SCREEN_BOTTOMRIGHT:
2166 return "BottomRight";
2167 }
2168
2169 return "Unknown";
2170}
2171#endif /* WITH_VERBOSE_MODE */
2172
2173void
2174meta_screen_calc_workspace_layout (MetaScreen *screen,
2175 int num_workspaces,
2176 int current_space,
2177 MetaWorkspaceLayout *layout)
2178{
2179 int rows, cols;
2180 int grid_area;
2181 int *grid;
2182 int i, r, c;
2183 int current_row, current_col;
2184
2185 rows = screen->rows_of_workspaces;
2186 cols = screen->columns_of_workspaces;
2187 if (rows <= 0 && cols <= 0)
2188 cols = num_workspaces;
2189
2190 if (rows <= 0)
2191 rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
2192 if (cols <= 0)
2193 cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
2194
2195 /* paranoia */
2196 if (rows < 1)
2197 rows = 1;
2198 if (cols < 1)
2199 cols = 1;
2200
2201 g_assert (rows != 0 && cols != 0)do { if (rows != 0 && cols != 0) ; else g_assertion_message_expr
("marco", "core/screen.c", 2201, ((const char*) (__func__)),
"rows != 0 && cols != 0"); } while (0)
;
2202
2203 grid_area = rows * cols;
2204
2205 meta_verbosemeta_verbose_real ("Getting layout rows = %d cols = %d current = %d "
2206 "num_spaces = %d vertical = %s corner = %s\n",
2207 rows, cols, current_space, num_workspaces,
2208 screen->vertical_workspaces ? "(true)" : "(false)",
2209 meta_screen_corner_to_string (screen->starting_corner));
2210
2211 /* ok, we want to setup the distances in the workspace array to go
2212 * in each direction. Remember, there are many ways that a workspace
2213 * array can be setup.
2214 * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
2215 * and look at the _NET_DESKTOP_LAYOUT section for details.
2216 * For instance:
2217 */
2218 /* starting_corner = META_SCREEN_TOPLEFT
2219 * vertical_workspaces = 0 vertical_workspaces=1
2220 * 1234 1357
2221 * 5678 2468
2222 *
2223 * starting_corner = META_SCREEN_TOPRIGHT
2224 * vertical_workspaces = 0 vertical_workspaces=1
2225 * 4321 7531
2226 * 8765 8642
2227 *
2228 * starting_corner = META_SCREEN_BOTTOMLEFT
2229 * vertical_workspaces = 0 vertical_workspaces=1
2230 * 5678 2468
2231 * 1234 1357
2232 *
2233 * starting_corner = META_SCREEN_BOTTOMRIGHT
2234 * vertical_workspaces = 0 vertical_workspaces=1
2235 * 8765 8642
2236 * 4321 7531
2237 *
2238 */
2239 /* keep in mind that we could have a ragged layout, e.g. the "8"
2240 * in the above grids could be missing
2241 */
2242
2243 grid = g_new (int, grid_area)((int *) g_malloc_n ((grid_area), sizeof (int)));
2244
2245 i = 0;
2246 switch (screen->starting_corner)
2247 {
2248 case META_SCREEN_TOPLEFT:
2249 if (screen->vertical_workspaces)
2250 {
2251 c = 0;
2252 while (c < cols)
2253 {
2254 r = 0;
2255 while (r < rows)
2256 {
2257 grid[r*cols+c] = i;
2258 ++i;
2259 ++r;
2260 }
2261 ++c;
2262 }
2263 }
2264 else
2265 {
2266 r = 0;
2267 while (r < rows)
2268 {
2269 c = 0;
2270 while (c < cols)
2271 {
2272 grid[r*cols+c] = i;
2273 ++i;
2274 ++c;
2275 }
2276 ++r;
2277 }
2278 }
2279 break;
2280 case META_SCREEN_TOPRIGHT:
2281 if (screen->vertical_workspaces)
2282 {
2283 c = cols - 1;
2284 while (c >= 0)
2285 {
2286 r = 0;
2287 while (r < rows)
2288 {
2289 grid[r*cols+c] = i;
2290 ++i;
2291 ++r;
2292 }
2293 --c;
2294 }
2295 }
2296 else
2297 {
2298 r = 0;
2299 while (r < rows)
2300 {
2301 c = cols - 1;
2302 while (c >= 0)
2303 {
2304 grid[r*cols+c] = i;
2305 ++i;
2306 --c;
2307 }
2308 ++r;
2309 }
2310 }
2311 break;
2312 case META_SCREEN_BOTTOMLEFT:
2313 if (screen->vertical_workspaces)
2314 {
2315 c = 0;
2316 while (c < cols)
2317 {
2318 r = rows - 1;
2319 while (r >= 0)
2320 {
2321 grid[r*cols+c] = i;
2322 ++i;
2323 --r;
2324 }
2325 ++c;
2326 }
2327 }
2328 else
2329 {
2330 r = rows - 1;
2331 while (r >= 0)
2332 {
2333 c = 0;
2334 while (c < cols)
2335 {
2336 grid[r*cols+c] = i;
2337 ++i;
2338 ++c;
2339 }
2340 --r;
2341 }
2342 }
2343 break;
2344 case META_SCREEN_BOTTOMRIGHT:
2345 if (screen->vertical_workspaces)
2346 {
2347 c = cols - 1;
2348 while (c >= 0)
2349 {
2350 r = rows - 1;
2351 while (r >= 0)
2352 {
2353 grid[r*cols+c] = i;
2354 ++i;
2355 --r;
2356 }
2357 --c;
2358 }
2359 }
2360 else
2361 {
2362 r = rows - 1;
2363 while (r >= 0)
2364 {
2365 c = cols - 1;
2366 while (c >= 0)
2367 {
2368 grid[r*cols+c] = i;
2369 ++i;
2370 --c;
2371 }
2372 --r;
2373 }
2374 }
2375 break;
2376 }
2377
2378 if (i != grid_area)
2379 meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
2380 G_STRFUNC((const char*) (__func__)), i);
2381
2382 current_row = 0;
2383 current_col = 0;
2384 r = 0;
2385 while (r < rows)
2386 {
2387 c = 0;
2388 while (c < cols)
2389 {
2390 if (grid[r*cols+c] == current_space)
2391 {
2392 current_row = r;
2393 current_col = c;
2394 }
2395 else if (grid[r*cols+c] >= num_workspaces)
2396 {
2397 /* flag nonexistent spaces with -1 */
2398 grid[r*cols+c] = -1;
2399 }
2400 ++c;
2401 }
2402 ++r;
2403 }
2404
2405 layout->rows = rows;
2406 layout->cols = cols;
2407 layout->grid = grid;
2408 layout->grid_area = grid_area;
2409 layout->current_row = current_row;
2410 layout->current_col = current_col;
2411
2412#ifdef WITH_VERBOSE_MODE1
2413 if (meta_is_verbose ())
2414 {
2415 r = 0;
2416 while (r < layout->rows)
2417 {
2418 meta_verbosemeta_verbose_real (" ");
2419 meta_push_no_msg_prefix ();
2420 c = 0;
2421 while (c < layout->cols)
2422 {
2423 if (r == layout->current_row &&
2424 c == layout->current_col)
2425 meta_verbosemeta_verbose_real ("*%2d ", layout->grid[r*layout->cols+c]);
2426 else
2427 meta_verbosemeta_verbose_real ("%3d ", layout->grid[r*layout->cols+c]);
2428 ++c;
2429 }
2430 meta_verbosemeta_verbose_real ("\n");
2431 meta_pop_no_msg_prefix ();
2432 ++r;
2433 }
2434 }
2435#endif /* WITH_VERBOSE_MODE */
2436}
2437
2438void
2439meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
2440{
2441 g_free (layout->grid);
2442}
2443
2444static void
2445meta_screen_resize_func (MetaScreen *screen,
2446 MetaWindow *window,
2447 void *user_data)
2448{
2449 if (window->struts)
2450 {
2451 meta_window_update_struts (window);
2452 }
2453 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2454
2455 meta_window_recalc_features (window);
2456}
2457
2458void
2459meta_screen_resize (MetaScreen *screen,
2460 int width,
2461 int height)
2462{
2463 screen->rect.width = width;
2464 screen->rect.height = height;
2465
2466 reload_xinerama_infos (screen);
2467 set_desktop_geometry_hint (screen);
2468
2469 /* Queue a resize on all the windows */
2470 meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
2471}
2472
2473void
2474meta_screen_update_showing_desktop_hint (MetaScreen *screen)
2475{
2476 unsigned long data[1];
2477
2478 data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
2479
2480 meta_error_trap_push (screen->display);
2481 XChangeProperty (screen->display->xdisplay, screen->xroot,
2482 screen->display->atom__NET_SHOWING_DESKTOP,
2483 XA_CARDINAL((Atom) 6),
2484 32, PropModeReplace0, (guchar*) data, 1);
2485 meta_error_trap_pop (screen->display, FALSE(0));
2486}
2487
2488static void
2489queue_windows_showing (MetaScreen *screen)
2490{
2491 GSList *windows;
2492 GSList *tmp;
2493
2494 /* Must operate on all windows on display instead of just on the
2495 * active_workspace's window list, because the active_workspace's
2496 * window list may not contain the on_all_workspace windows.
2497 */
2498 windows = meta_display_list_windows (screen->display);
2499
2500 tmp = windows;
2501 while (tmp != NULL((void*)0))
2502 {
2503 MetaWindow *w = tmp->data;
2504
2505 if (w->screen == screen && !meta_prefs_is_in_skip_list (w->res_class))
2506 meta_window_queue (w, META_QUEUE_CALC_SHOWING);
2507
2508 tmp = tmp->next;
2509 }
2510
2511 g_slist_free (windows);
2512}
2513
2514void
2515meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
2516 MetaWindow *keep)
2517{
2518 GList *windows;
2519 GList *tmp;
2520
2521 windows = screen->active_workspace->windows;
2522
2523 tmp = windows;
2524 while (tmp != NULL((void*)0))
2525 {
2526 MetaWindow *w = tmp->data;
2527
2528 if (w->screen == screen &&
2529 w->has_minimize_func &&
2530 w != keep)
2531 meta_window_minimize (w);
2532
2533 tmp = tmp->next;
2534 }
2535}
2536
2537void
2538meta_screen_show_desktop (MetaScreen *screen,
2539 guint32 timestamp)
2540{
2541 GList *windows;
2542
2543 if (screen->active_workspace->showing_desktop)
2544 return;
2545
2546 screen->active_workspace->showing_desktop = TRUE(!(0));
2547
2548 queue_windows_showing (screen);
2549
2550 /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
2551 * see bug 159257.
2552 */
2553 windows = screen->active_workspace->mru_list;
2554 while (windows != NULL((void*)0))
2555 {
2556 MetaWindow *w = windows->data;
2557
2558 if (w->screen == screen &&
2559 w->type == META_WINDOW_DESKTOP &&
2560 !meta_prefs_is_in_skip_list (w->res_class))
2561 {
2562 meta_window_focus (w, timestamp);
2563 break;
2564 }
2565
2566 windows = windows->next;
2567 }
2568
2569 meta_screen_update_showing_desktop_hint (screen);
2570}
2571
2572void
2573meta_screen_unshow_desktop (MetaScreen *screen)
2574{
2575 if (!screen->active_workspace->showing_desktop)
2576 return;
2577
2578 screen->active_workspace->showing_desktop = FALSE(0);
2579
2580 queue_windows_showing (screen);
2581
2582 meta_screen_update_showing_desktop_hint (screen);
2583}
2584
2585#ifdef HAVE_STARTUP_NOTIFICATION
2586static gboolean startup_sequence_timeout (void *data);
2587
2588static void
2589update_startup_feedback (MetaScreen *screen)
2590{
2591 if (screen->startup_sequences != NULL((void*)0))
2592 {
2593 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2594 "Setting busy cursor\n");
2595 meta_screen_set_cursor (screen, META_CURSOR_BUSY);
2596 }
2597 else
2598 {
2599 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2600 "Setting default cursor\n");
2601 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
2602 }
2603}
2604
2605static void
2606add_sequence (MetaScreen *screen,
2607 SnStartupSequence *sequence)
2608{
2609 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2610 "Adding sequence %s\n",
2611 sn_startup_sequence_get_id (sequence));
2612 sn_startup_sequence_ref (sequence);
2613 screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
2614 sequence);
2615
2616 /* our timeout just polls every second, instead of bothering
2617 * to compute exactly when we may next time out
2618 */
2619 if (screen->startup_sequence_timeout == 0)
2620 screen->startup_sequence_timeout = g_timeout_add (1000,
2621 startup_sequence_timeout,
2622 screen);
2623
2624 update_startup_feedback (screen);
2625}
2626
2627static void
2628remove_sequence (MetaScreen *screen,
2629 SnStartupSequence *sequence)
2630{
2631 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2632 "Removing sequence %s\n",
2633 sn_startup_sequence_get_id (sequence));
2634
2635 screen->startup_sequences = g_slist_remove (screen->startup_sequences,
2636 sequence);
2637 sn_startup_sequence_unref (sequence);
2638
2639 if (screen->startup_sequences == NULL((void*)0) &&
2640 screen->startup_sequence_timeout != 0)
2641 {
2642 g_source_remove (screen->startup_sequence_timeout);
2643 screen->startup_sequence_timeout = 0;
2644 }
2645
2646 update_startup_feedback (screen);
2647}
2648
2649typedef struct
2650{
2651 GSList *list;
2652 gint64 now;
2653} CollectTimedOutData;
2654
2655/* This should be fairly long, as it should never be required unless
2656 * apps or .desktop files are buggy, and it's confusing if
2657 * OpenOffice or whatever seems to stop launching - people
2658 * might decide they need to launch it again.
2659 */
2660#define STARTUP_TIMEOUT15000 15000
2661
2662static void
2663collect_timed_out_foreach (void *element,
2664 void *data)
2665{
2666 CollectTimedOutData *ctod = data;
2667 SnStartupSequence *sequence = element;
2668 double elapsed;
2669
2670 time_t tv_sec;
2671 suseconds_t tv_usec;
2672 gint64 tv;
2673
2674 sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
2675 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
2676 elapsed = (ctod->now - tv) / 1000.0;
2677
2678 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2679 "Sequence used %g seconds vs. %g max: %s\n",
2680 elapsed, (double) STARTUP_TIMEOUT15000,
2681 sn_startup_sequence_get_id (sequence));
2682
2683 if (elapsed > STARTUP_TIMEOUT15000)
2684 ctod->list = g_slist_prepend (ctod->list, sequence);
2685}
2686
2687static gboolean
2688startup_sequence_timeout (void *data)
2689{
2690 MetaScreen *screen = data;
2691 CollectTimedOutData ctod;
2692 GSList *tmp;
2693
2694 ctod.list = NULL((void*)0);
2695
2696 ctod.now = g_get_real_time ();
2697 g_slist_foreach (screen->startup_sequences,
2698 collect_timed_out_foreach,
2699 &ctod);
2700
2701 tmp = ctod.list;
2702 while (tmp != NULL((void*)0))
2703 {
2704 SnStartupSequence *sequence = tmp->data;
2705
2706 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2707 "Timed out sequence %s\n",
2708 sn_startup_sequence_get_id (sequence));
2709
2710 sn_startup_sequence_complete (sequence);
2711
2712 tmp = tmp->next;
2713 }
2714
2715 g_slist_free (ctod.list);
2716
2717 if (screen->startup_sequences != NULL((void*)0))
2718 {
2719 return TRUE(!(0));
2720 }
2721 else
2722 {
2723 /* remove */
2724 screen->startup_sequence_timeout = 0;
2725 return FALSE(0);
2726 }
2727}
2728
2729static void
2730meta_screen_sn_event (SnMonitorEvent *event,
2731 void *user_data)
2732{
2733 MetaScreen *screen;
2734 SnStartupSequence *sequence;
2735
2736 screen = user_data;
2737
2738 sequence = sn_monitor_event_get_startup_sequence (event);
2739
2740 switch (sn_monitor_event_get_type (event))
2741 {
2742 case SN_MONITOR_EVENT_INITIATED:
2743 {
2744 const char *wmclass;
2745
2746 wmclass = sn_startup_sequence_get_wmclass (sequence);
2747
2748 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2749 "Received startup initiated for %s wmclass %s\n",
2750 sn_startup_sequence_get_id (sequence),
2751 wmclass ? wmclass : "(unset)");
2752 add_sequence (screen, sequence);
2753 }
2754 break;
2755
2756 case SN_MONITOR_EVENT_COMPLETED:
2757 {
2758 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2759 "Received startup completed for %s\n",
2760 sn_startup_sequence_get_id (sequence));
2761 remove_sequence (screen,
2762 sn_monitor_event_get_startup_sequence (event));
2763 }
2764 break;
2765
2766 case SN_MONITOR_EVENT_CHANGED:
2767 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2768 "Received startup changed for %s\n",
2769 sn_startup_sequence_get_id (sequence));
2770 break;
2771
2772 case SN_MONITOR_EVENT_CANCELED:
2773 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2774 "Received startup canceled for %s\n",
2775 sn_startup_sequence_get_id (sequence));
2776 break;
2777 }
2778}
2779#endif
2780
2781/* Sets the initial_timestamp and initial_workspace properties
2782 * of a window according to information given us by the
2783 * startup-notification library.
2784 *
2785 * Returns TRUE if startup properties have been applied, and
2786 * FALSE if they have not (for example, if they had already
2787 * been applied.)
2788 */
2789gboolean
2790meta_screen_apply_startup_properties (MetaScreen *screen,
2791 MetaWindow *window)
2792{
2793#ifdef HAVE_STARTUP_NOTIFICATION
2794 const char *startup_id;
2795 GSList *tmp;
2796 SnStartupSequence *sequence;
2797
2798 /* Does the window have a startup ID stored? */
2799 startup_id = meta_window_get_startup_id (window);
2800
2801 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2802 "Applying startup props to %s id \"%s\"\n",
2803 window->desc,
2804 startup_id ? startup_id : "(none)");
2805
2806 sequence = NULL((void*)0);
2807 if (startup_id == NULL((void*)0))
2808 {
2809 /* No startup ID stored for the window. Let's ask the
2810 * startup-notification library whether there's anything
2811 * stored for the resource name or resource class hints.
2812 */
2813 tmp = screen->startup_sequences;
2814 while (tmp != NULL((void*)0))
2815 {
2816 const char *wmclass;
2817
2818 wmclass = sn_startup_sequence_get_wmclass (tmp->data);
2819
2820 if (wmclass != NULL((void*)0) &&
2821 ((window->res_class &&
2822 strcmp (wmclass, window->res_class) == 0) ||
2823 (window->res_name &&
2824 strcmp (wmclass, window->res_name) == 0)))
2825 {
2826 sequence = tmp->data;
2827
2828 g_assert (window->startup_id == NULL)do { if (window->startup_id == ((void*)0)) ; else g_assertion_message_expr
("marco", "core/screen.c", 2828, ((const char*) (__func__)),
"window->startup_id == NULL"); } while (0)
;
2829 window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence))g_strdup_inline (sn_startup_sequence_get_id (sequence));
2830 startup_id = window->startup_id;
2831
2832 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2833 "Ending legacy sequence %s due to window %s\n",
2834 sn_startup_sequence_get_id (sequence),
2835 window->desc);
2836
2837 sn_startup_sequence_complete (sequence);
2838 break;
2839 }
2840
2841 tmp = tmp->next;
2842 }
2843 }
2844
2845 /* Still no startup ID? Bail. */
2846 if (startup_id == NULL((void*)0))
2847 return FALSE(0);
2848
2849 /* We might get this far and not know the sequence ID (if the window
2850 * already had a startup ID stored), so let's look for one if we don't
2851 * already know it.
2852 */
2853 if (sequence == NULL((void*)0))
2854 {
2855 tmp = screen->startup_sequences;
2856 while (tmp != NULL((void*)0))
2857 {
2858 const char *id;
2859
2860 id = sn_startup_sequence_get_id (tmp->data);
2861
2862 if (strcmp (id, startup_id) == 0)
2863 {
2864 sequence = tmp->data;
2865 break;
2866 }
2867
2868 tmp = tmp->next;
2869 }
2870 }
2871
2872 if (sequence != NULL((void*)0))
2873 {
2874 gboolean changed_something = FALSE(0);
2875
2876 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2877 "Found startup sequence for window %s ID \"%s\"\n",
2878 window->desc, startup_id);
2879
2880 if (!window->initial_workspace_set)
2881 {
2882 int space = sn_startup_sequence_get_workspace (sequence);
2883 if (space >= 0)
2884 {
2885 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2886 "Setting initial window workspace to %d based on startup info\n",
2887 space);
2888
2889 window->initial_workspace_set = TRUE(!(0));
2890 window->initial_workspace = space;
2891 changed_something = TRUE(!(0));
2892 }
2893 }
2894
2895 if (!window->initial_timestamp_set)
2896 {
2897 guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
2898 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2899 "Setting initial window timestamp to %u based on startup info\n",
2900 timestamp);
2901
2902 window->initial_timestamp_set = TRUE(!(0));
2903 window->initial_timestamp = timestamp;
2904 changed_something = TRUE(!(0));
2905 }
2906
2907 return changed_something;
2908 }
2909 else
2910 {
2911 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2912 "Did not find startup sequence for window %s ID \"%s\"\n",
2913 window->desc, startup_id);
2914 }
2915
2916#endif /* HAVE_STARTUP_NOTIFICATION */
2917
2918 return FALSE(0);
2919}
2920
2921int
2922meta_screen_get_screen_number (MetaScreen *screen)
2923{
2924 return screen->number;
2925}
2926
2927MetaDisplay *
2928meta_screen_get_display (MetaScreen *screen)
2929{
2930 return screen->display;
2931}
2932
2933Window
2934meta_screen_get_xroot (MetaScreen *screen)
2935{
2936 return screen->xroot;
2937}
2938
2939void
2940meta_screen_get_size (MetaScreen *screen,
2941 int *width,
2942 int *height)
2943{
2944 *width = screen->rect.width;
2945 *height = screen->rect.height;
2946}
2947
2948gpointer
2949meta_screen_get_compositor_data (MetaScreen *screen)
2950{
2951 return screen->compositor_data;
2952}
2953
2954void
2955meta_screen_set_compositor_data (MetaScreen *screen,
2956 gpointer compositor)
2957{
2958 screen->compositor_data = compositor;
2959}
2960
2961#ifdef HAVE_COMPOSITE_EXTENSIONS1
2962void
2963meta_screen_set_cm_selection (MetaScreen *screen)
2964{
2965 screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip (
2966 screen->display);
2967
2968 meta_verbosemeta_verbose_real ("Setting selection for screen: %d\n", screen->number);
2969 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2970 screen->wm_cm_selection_window, screen->wm_cm_timestamp);
2971}
2972
2973void
2974meta_screen_unset_cm_selection (MetaScreen *screen)
2975{
2976 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2977 None0L, screen->wm_cm_timestamp);
2978}
2979
2980gboolean
2981meta_screen_is_cm_selected (MetaScreen *screen)
2982{
2983 Window owner = XGetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom);
2984 return owner != None0L;
2985}
2986#endif /* HAVE_COMPOSITE_EXTENSIONS */
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ef49e8.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ef49e8.html new file mode 100644 index 00000000..7c3dfaff --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-ef49e8.html @@ -0,0 +1,8003 @@ + + + +ui/theme.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:ui/theme.c
Warning:line 6820, column 10
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I ./include -D MARCO_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D MARCO_LOCALEDIR="/usr/local/share/locale" -D MARCO_PKGDATADIR="/usr/local/share/marco" -D MARCO_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="marco" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c ui/theme.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Marco Theme Rendering */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24/**
25 * \file theme.c Making Marco look pretty
26 *
27 * The window decorations drawn by Marco are described by files on disk
28 * known internally as "themes" (externally as "window border themes" on
29 * http://art.gnome.org/themes/marco/ or "Marco themes"). This file
30 * contains most of the code necessary to support themes; it does not
31 * contain the XML parser, which is in theme-parser.c.
32 *
33 * \bug This is a big file with lots of different subsystems, which might
34 * be better split out into separate files.
35 */
36
37/**
38 * \defgroup tokenizer The theme expression tokenizer
39 *
40 * Themes can use a simple expression language to represent the values of
41 * things. This is the tokeniser used for that language.
42 *
43 * \bug We could remove almost all this code by using GScanner instead,
44 * but we would also have to find every expression in every existing theme
45 * we could and make sure the parse trees were the same.
46 */
47
48/**
49 * \defgroup parser The theme expression parser
50 *
51 * Themes can use a simple expression language to represent the values of
52 * things. This is the parser used for that language.
53 */
54
55#include <config.h>
56#include <glib/gi18n-lib.h>
57
58#include "prefs.h"
59#include "theme.h"
60#include "theme-parser.h"
61#include "util.h"
62#include "gradient.h"
63#include <gtk/gtk.h>
64#include <string.h>
65#include <stdlib.h>
66#define __USE_XOPEN
67#include <math.h>
68
69#define GDK_COLOR_RGBA(color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
\
70 ((guint32) (0xff | \
71 ((int)((color).red * 255) << 24) | \
72 ((int)((color).green * 255) << 16) | \
73 ((int)((color).blue * 255) << 8)))
74
75#define GDK_COLOR_RGB(color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
\
76 ((guint32) (((int)((color).red * 255) << 16) | \
77 ((int)((color).green * 255) << 8) | \
78 ((int)((color).blue * 255))))
79
80#define DEBUG_FILL_STRUCT(s)memset ((s), 0xef, sizeof (*(s))) memset ((s), 0xef, sizeof (*(s)))
81#define CLAMP_UCHAR(v)((guchar) ((((((int)v)) > ((int)255)) ? ((int)255) : (((((
int)v)) < ((int)0)) ? ((int)0) : (((int)v))))))
((guchar) (CLAMP (((int)v), (int)0, (int)255)(((((int)v)) > ((int)255)) ? ((int)255) : (((((int)v)) <
((int)0)) ? ((int)0) : (((int)v))))
))
82#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
83
84static void gtk_style_shade (GdkRGBA *a,
85 GdkRGBA *b,
86 gdouble k);
87static void rgb_to_hls (gdouble *r,
88 gdouble *g,
89 gdouble *b);
90static void hls_to_rgb (gdouble *h,
91 gdouble *l,
92 gdouble *s);
93
94/**
95 * The current theme. (Themes are singleton.)
96 */
97static MetaTheme *meta_current_theme = NULL((void*)0);
98
99static cairo_surface_t *
100scale_surface (cairo_surface_t *surface,
101 gdouble old_width,
102 gdouble old_height,
103 gdouble new_width,
104 gdouble new_height,
105 gboolean vertical_stripes,
106 gboolean horizontal_stripes)
107{
108 gdouble scale_x;
109 gdouble scale_y;
110 cairo_content_t content;
111 gdouble width;
112 gdouble height;
113 cairo_surface_t *scaled;
114 cairo_t *cr;
115
116 scale_x = new_width / old_width;
117 scale_y = new_height / old_height;
118
119 if (horizontal_stripes && !vertical_stripes)
120 {
121 new_width = old_width;
122 scale_x = 1.0;
123 }
124 else if (vertical_stripes && !horizontal_stripes)
125 {
126 new_height = old_height;
127 scale_y = 1.0;
128 }
129
130 content = CAIRO_CONTENT_COLOR_ALPHA;
131 width = ceil (new_width);
132 height = ceil (new_height);
133
134 scaled = cairo_surface_create_similar (surface, content, (int) width, (int) height);
135 cr = cairo_create (scaled);
136
137 cairo_scale (cr, scale_x, scale_y);
138 cairo_set_source_surface (cr, surface, 0, 0);
139
140 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
141
142 cairo_paint (cr);
143 cairo_destroy (cr);
144
145 return scaled;
146}
147
148static cairo_surface_t *
149get_surface_from_pixbuf (GdkPixbuf *pixbuf,
150 MetaImageFillType fill_type,
151 gdouble width,
152 gdouble height,
153 gboolean vertical_stripes,
154 gboolean horizontal_stripes)
155{
156 gdouble pixbuf_width;
157 gdouble pixbuf_height;
158 cairo_surface_t *surface;
159 cairo_content_t content;
160 cairo_surface_t *copy;
161 cairo_t *cr;
162
163 pixbuf_width = gdk_pixbuf_get_width (pixbuf);
164 pixbuf_height = gdk_pixbuf_get_height (pixbuf);
165 surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL((void*)0));
166
167 if (pixbuf_width == width && pixbuf_height == height)
168 {
169 return surface;
170 }
171
172 if (fill_type != META_IMAGE_FILL_TILE)
173 {
174 cairo_surface_t *scaled;
175
176 scaled = scale_surface (surface, pixbuf_width, pixbuf_height,
177 width, height, vertical_stripes,
178 horizontal_stripes);
179
180 cairo_surface_destroy (surface);
181 surface = scaled;
182 }
183
184 content = CAIRO_CONTENT_COLOR_ALPHA;
185 width = ceil (width);
186 height = ceil (height);
187
188 copy = cairo_surface_create_similar (surface, content, (int) width, (int) height);
189 cr = cairo_create (copy);
190
191 cairo_set_source_surface (cr, surface, 0, 0);
192
193 if (fill_type == META_IMAGE_FILL_TILE ||
194 vertical_stripes || horizontal_stripes)
195 {
196 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
197 }
198
199 cairo_paint (cr);
200 cairo_destroy (cr);
201
202 cairo_surface_destroy (surface);
203
204 return copy;
205}
206
207static GdkPixbuf *
208colorize_pixbuf (GdkPixbuf *orig,
209 GdkRGBA *new_color)
210{
211 GdkPixbuf *pixbuf;
212 double intensity;
213 int x, y;
214 const guchar *src;
215 guchar *dest;
216 int orig_rowstride;
217 int dest_rowstride;
218 int width, height;
219 gboolean has_alpha;
220 const guchar *src_pixels;
221 guchar *dest_pixels;
222
223 pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
224 gdk_pixbuf_get_bits_per_sample (orig),
225 gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
226
227 if (pixbuf == NULL((void*)0))
228 return NULL((void*)0);
229
230 orig_rowstride = gdk_pixbuf_get_rowstride (orig);
231 dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
232 width = gdk_pixbuf_get_width (pixbuf);
233 height = gdk_pixbuf_get_height (pixbuf);
234 has_alpha = gdk_pixbuf_get_has_alpha (orig);
235 src_pixels = gdk_pixbuf_get_pixels (orig);
236 dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
237
238 for (y = 0; y < height; y++)
239 {
240 src = src_pixels + y * orig_rowstride;
241 dest = dest_pixels + y * dest_rowstride;
242
243 for (x = 0; x < width; x++)
244 {
245 double dr, dg, db;
246
247 intensity = INTENSITY (src[0], src[1], src[2])((src[0]) * 0.30 + (src[1]) * 0.59 + (src[2]) * 0.11) / 255.0;
248
249 if (intensity <= 0.5)
250 {
251 /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
252 dr = new_color->red * intensity * 2.0;
253 dg = new_color->green * intensity * 2.0;
254 db = new_color->blue * intensity * 2.0;
255 }
256 else
257 {
258 /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
259 dr = new_color->red + (1.0 - new_color->red) * (intensity - 0.5) * 2.0;
260 dg = new_color->green + (1.0 - new_color->green) * (intensity - 0.5) * 2.0;
261 db = new_color->blue + (1.0 - new_color->blue) * (intensity - 0.5) * 2.0;
262 }
263
264 dest[0] = CLAMP_UCHAR (255 * dr)((guchar) ((((((int)255 * dr)) > ((int)255)) ? ((int)255) :
(((((int)255 * dr)) < ((int)0)) ? ((int)0) : (((int)255 *
dr))))))
;
265 dest[1] = CLAMP_UCHAR (255 * dg)((guchar) ((((((int)255 * dg)) > ((int)255)) ? ((int)255) :
(((((int)255 * dg)) < ((int)0)) ? ((int)0) : (((int)255 *
dg))))))
;
266 dest[2] = CLAMP_UCHAR (255 * db)((guchar) ((((((int)255 * db)) > ((int)255)) ? ((int)255) :
(((((int)255 * db)) < ((int)0)) ? ((int)0) : (((int)255 *
db))))))
;
267
268 if (has_alpha)
269 {
270 dest[3] = src[3];
271 src += 4;
272 dest += 4;
273 }
274 else
275 {
276 src += 3;
277 dest += 3;
278 }
279 }
280 }
281
282 return pixbuf;
283}
284
285static void
286color_composite (const GdkRGBA *bg,
287 const GdkRGBA *fg,
288 double alpha,
289 GdkRGBA *color)
290{
291 *color = *bg;
292 color->red = color->red + (fg->red - color->red) * alpha;
293 color->green = color->green + (fg->green - color->green) * alpha;
294 color->blue = color->blue + (fg->blue - color->blue) * alpha;
295}
296
297/**
298 * Sets all the fields of a border to dummy values.
299 *
300 * \param border The border whose fields should be reset.
301 */
302static void
303init_border (GtkBorder *border)
304{
305 border->top = -1;
306 border->bottom = -1;
307 border->left = -1;
308 border->right = -1;
309}
310
311/**
312 * Creates a new, empty MetaFrameLayout. The fields will be set to dummy
313 * values.
314 *
315 * \return The newly created MetaFrameLayout.
316 */
317MetaFrameLayout*
318meta_frame_layout_new (void)
319{
320 MetaFrameLayout *layout;
321
322 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
323
324 layout->refcount = 1;
325
326 /* Fill with -1 values to detect invalid themes */
327 layout->left_width = -1;
328 layout->right_width = -1;
329 layout->bottom_height = -1;
330
331 layout->invisible_border.left = 10;
332 layout->invisible_border.right = 10;
333 layout->invisible_border.bottom = 10;
334 layout->invisible_border.top = 10;
335
336 init_border (&layout->title_border);
337
338 layout->title_vertical_pad = -1;
339
340 layout->right_titlebar_edge = -1;
341 layout->left_titlebar_edge = -1;
342
343 layout->button_sizing = META_BUTTON_SIZING_LAST;
344 layout->button_aspect = 1.0;
345 layout->button_width = -1;
346 layout->button_height = -1;
347
348 layout->has_title = TRUE(!(0));
349 layout->title_scale = 1.0;
350
351 init_border (&layout->button_border);
352
353 return layout;
354}
355
356/**
357 *
358 */
359static gboolean
360validate_border (const GtkBorder *border,
361 const char **bad)
362{
363 *bad = NULL((void*)0);
364
365 if (border->top < 0)
366 *bad = _("top")((char *) g_dgettext ("marco", "top"));
367 else if (border->bottom < 0)
368 *bad = _("bottom")((char *) g_dgettext ("marco", "bottom"));
369 else if (border->left < 0)
370 *bad = _("left")((char *) g_dgettext ("marco", "left"));
371 else if (border->right < 0)
372 *bad = _("right")((char *) g_dgettext ("marco", "right"));
373
374 return *bad == NULL((void*)0);
375}
376
377/**
378 * Ensures that the theme supplied a particular dimension. When a
379 * MetaFrameLayout is created, all its integer fields are set to -1
380 * by meta_frame_layout_new(). After an instance of this type
381 * should have been initialised, this function checks that
382 * a given field is not still at -1. It is never called directly, but
383 * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER
384 * macros.
385 *
386 * \param val The value to check
387 * \param name The name to use in the error message
388 * \param[out] error Set to an error if val was not initialised
389 */
390static gboolean
391validate_geometry_value (int val,
392 const char *name,
393 GError **error)
394{
395 if (val < 0)
396 {
397 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
398 META_THEME_ERROR_FRAME_GEOMETRY,
399 _("frame geometry does not specify \"%s\" dimension")((char *) g_dgettext ("marco", "frame geometry does not specify \"%s\" dimension"
))
,
400 name);
401 return FALSE(0);
402 }
403 else
404 return TRUE(!(0));
405}
406
407static gboolean
408validate_geometry_border (const GtkBorder *border,
409 const char *name,
410 GError **error)
411{
412 const char *bad;
413
414 if (!validate_border (border, &bad))
415 {
416 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
417 META_THEME_ERROR_FRAME_GEOMETRY,
418 _("frame geometry does not specify dimension \"%s\" for border \"%s\"")((char *) g_dgettext ("marco", "frame geometry does not specify dimension \"%s\" for border \"%s\""
))
,
419 bad, name);
420 return FALSE(0);
421 }
422 else
423 return TRUE(!(0));
424}
425
426gboolean
427meta_frame_layout_validate (const MetaFrameLayout *layout,
428 GError **error)
429{
430 g_return_val_if_fail (layout != NULL, FALSE)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
((0)); } } while (0)
;
431
432#define CHECK_GEOMETRY_VALUE(vname)if (!validate_geometry_value (layout->vname, "vname", error
)) return (0)
if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE(0)
433
434#define CHECK_GEOMETRY_BORDER(bname)if (!validate_geometry_border (&layout->bname, "bname"
, error)) return (0)
if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE(0)
435
436 CHECK_GEOMETRY_VALUE (left_width)if (!validate_geometry_value (layout->left_width, "left_width"
, error)) return (0)
;
437 CHECK_GEOMETRY_VALUE (right_width)if (!validate_geometry_value (layout->right_width, "right_width"
, error)) return (0)
;
438 CHECK_GEOMETRY_VALUE (bottom_height)if (!validate_geometry_value (layout->bottom_height, "bottom_height"
, error)) return (0)
;
439
440 CHECK_GEOMETRY_BORDER (title_border)if (!validate_geometry_border (&layout->title_border, "title_border"
, error)) return (0)
;
441
442 CHECK_GEOMETRY_VALUE (title_vertical_pad)if (!validate_geometry_value (layout->title_vertical_pad, "title_vertical_pad"
, error)) return (0)
;
443
444 CHECK_GEOMETRY_VALUE (right_titlebar_edge)if (!validate_geometry_value (layout->right_titlebar_edge,
"right_titlebar_edge", error)) return (0)
;
445 CHECK_GEOMETRY_VALUE (left_titlebar_edge)if (!validate_geometry_value (layout->left_titlebar_edge, "left_titlebar_edge"
, error)) return (0)
;
446
447 switch (layout->button_sizing)
448 {
449 case META_BUTTON_SIZING_ASPECT:
450 if (layout->button_aspect < (0.1) ||
451 layout->button_aspect > (15.0))
452 {
453 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
454 META_THEME_ERROR_FRAME_GEOMETRY,
455 _("Button aspect ratio %g is not reasonable")((char *) g_dgettext ("marco", "Button aspect ratio %g is not reasonable"
))
,
456 layout->button_aspect);
457 return FALSE(0);
458 }
459 break;
460 case META_BUTTON_SIZING_FIXED:
461 CHECK_GEOMETRY_VALUE (button_width)if (!validate_geometry_value (layout->button_width, "button_width"
, error)) return (0)
;
462 CHECK_GEOMETRY_VALUE (button_height)if (!validate_geometry_value (layout->button_height, "button_height"
, error)) return (0)
;
463 break;
464 case META_BUTTON_SIZING_LAST:
465 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
466 META_THEME_ERROR_FRAME_GEOMETRY,
467 _("Frame geometry does not specify size of buttons")((char *) g_dgettext ("marco", "Frame geometry does not specify size of buttons"
))
);
468 return FALSE(0);
469 }
470
471 CHECK_GEOMETRY_BORDER (button_border)if (!validate_geometry_border (&layout->button_border,
"button_border", error)) return (0)
;
472
473 return TRUE(!(0));
474}
475
476MetaFrameLayout*
477meta_frame_layout_copy (const MetaFrameLayout *src)
478{
479 MetaFrameLayout *layout;
480
481 layout = g_new0 (MetaFrameLayout, 1)((MetaFrameLayout *) g_malloc0_n ((1), sizeof (MetaFrameLayout
)))
;
482
483 *layout = *src;
484
485 layout->refcount = 1;
486
487 return layout;
488}
489
490void
491meta_frame_layout_ref (MetaFrameLayout *layout)
492{
493 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
494
495 layout->refcount += 1;
496}
497
498void
499meta_frame_layout_unref (MetaFrameLayout *layout)
500{
501 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
502 g_return_if_fail (layout->refcount > 0)do { if ((layout->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout->refcount > 0"
); return; } } while (0)
;
503
504 layout->refcount -= 1;
505
506 if (layout->refcount == 0)
507 {
508 DEBUG_FILL_STRUCT (layout)memset ((layout), 0xef, sizeof (*(layout)));
509 g_free (layout);
510 }
511}
512
513void
514meta_frame_layout_get_borders (const MetaFrameLayout *layout,
515 int text_height,
516 MetaFrameFlags flags,
517 MetaFrameBorders *borders)
518{
519 int buttons_height, title_height;
520
521 meta_frame_borders_clear (borders);
522
523 /* For a full-screen window, we don't have any borders, visible or not. */
524 if (flags & META_FRAME_FULLSCREEN)
525 return;
526
527 g_return_if_fail (layout != NULL)do { if ((layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "layout != NULL"); return
; } } while (0)
;
528
529 if (!layout->has_title)
530 text_height = 0;
531
532 buttons_height = layout->button_height +
533 layout->button_border.top + layout->button_border.bottom;
534 title_height = text_height +
535 layout->title_vertical_pad +
536 layout->title_border.top + layout->title_border.bottom;
537
538 borders->visible.top = MAX (buttons_height, title_height)(((buttons_height) > (title_height)) ? (buttons_height) : (
title_height))
;
539 borders->visible.left = layout->left_width;
540 borders->visible.right = layout->right_width;
541 borders->visible.bottom = layout->bottom_height;
542
543 if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
544 {
545 borders->invisible.left = layout->invisible_border.left;
546 borders->invisible.right = layout->invisible_border.right;
547 }
548
549 if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
550 {
551 borders->invisible.bottom = layout->invisible_border.bottom;
552 borders->invisible.top = layout->invisible_border.top;
553 }
554
555 if (flags & META_FRAME_SHADED)
556 borders->visible.bottom = borders->invisible.bottom = 0;
557
558 borders->total.left = borders->invisible.left + borders->visible.left;
559 borders->total.right = borders->invisible.right + borders->visible.right;
560 borders->total.bottom = borders->invisible.bottom + borders->visible.bottom;
561 borders->total.top = borders->invisible.top + borders->visible.top;
562}
563
564static MetaButtonType
565map_button_function_to_type (MetaButtonFunction function)
566{
567 switch (function)
568 {
569 case META_BUTTON_FUNCTION_SHADE:
570 return META_BUTTON_TYPE_SHADE;
571 case META_BUTTON_FUNCTION_ABOVE:
572 return META_BUTTON_TYPE_ABOVE;
573 case META_BUTTON_FUNCTION_STICK:
574 return META_BUTTON_TYPE_STICK;
575 case META_BUTTON_FUNCTION_UNSHADE:
576 return META_BUTTON_TYPE_UNSHADE;
577 case META_BUTTON_FUNCTION_UNABOVE:
578 return META_BUTTON_TYPE_UNABOVE;
579 case META_BUTTON_FUNCTION_UNSTICK:
580 return META_BUTTON_TYPE_UNSTICK;
581 case META_BUTTON_FUNCTION_MENU:
582 return META_BUTTON_TYPE_MENU;
583 case META_BUTTON_FUNCTION_APPMENU:
584 return META_BUTTON_TYPE_APPMENU;
585 case META_BUTTON_FUNCTION_MINIMIZE:
586 return META_BUTTON_TYPE_MINIMIZE;
587 case META_BUTTON_FUNCTION_MAXIMIZE:
588 return META_BUTTON_TYPE_MAXIMIZE;
589 case META_BUTTON_FUNCTION_CLOSE:
590 return META_BUTTON_TYPE_CLOSE;
591 case META_BUTTON_FUNCTION_LAST:
592 return META_BUTTON_TYPE_LAST;
593 }
594
595 return META_BUTTON_TYPE_LAST;
596}
597
598static MetaButtonSpace*
599rect_for_function (MetaFrameGeometry *fgeom,
600 MetaFrameFlags flags,
601 MetaButtonFunction function,
602 MetaTheme *theme)
603{
604
605 /* Firstly, check version-specific things. */
606
607 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
608 {
609 switch (function)
610 {
611 case META_BUTTON_FUNCTION_SHADE:
612 if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
613 return &fgeom->shade_rect;
614 else
615 return NULL((void*)0);
616 case META_BUTTON_FUNCTION_ABOVE:
617 if (!(flags & META_FRAME_ABOVE))
618 return &fgeom->above_rect;
619 else
620 return NULL((void*)0);
621 case META_BUTTON_FUNCTION_STICK:
622 if (!(flags & META_FRAME_STUCK))
623 return &fgeom->stick_rect;
624 else
625 return NULL((void*)0);
626 case META_BUTTON_FUNCTION_UNSHADE:
627 if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
628 return &fgeom->unshade_rect;
629 else
630 return NULL((void*)0);
631 case META_BUTTON_FUNCTION_UNABOVE:
632 if (flags & META_FRAME_ABOVE)
633 return &fgeom->unabove_rect;
634 else
635 return NULL((void*)0);
636 case META_BUTTON_FUNCTION_UNSTICK:
637 if (flags & META_FRAME_STUCK)
638 return &fgeom->unstick_rect;
639 default:
640 /* just go on to the next switch block */;
641 }
642 }
643
644 /* now consider the buttons which exist in all versions */
645
646 switch (function)
647 {
648 case META_BUTTON_FUNCTION_MENU:
649 if (flags & META_FRAME_ALLOWS_MENU)
650 return &fgeom->menu_rect;
651 else
652 return NULL((void*)0);
653 case META_BUTTON_FUNCTION_APPMENU:
654 if (flags & META_FRAME_ALLOWS_APPMENU)
655 return &fgeom->appmenu_rect;
656 else
657 return NULL((void*)0);
658 case META_BUTTON_FUNCTION_MINIMIZE:
659 if (flags & META_FRAME_ALLOWS_MINIMIZE)
660 return &fgeom->min_rect;
661 else
662 return NULL((void*)0);
663 case META_BUTTON_FUNCTION_MAXIMIZE:
664 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
665 return &fgeom->max_rect;
666 else
667 return NULL((void*)0);
668 case META_BUTTON_FUNCTION_CLOSE:
669 if (flags & META_FRAME_ALLOWS_DELETE)
670 return &fgeom->close_rect;
671 else
672 return NULL((void*)0);
673 case META_BUTTON_FUNCTION_STICK:
674 case META_BUTTON_FUNCTION_SHADE:
675 case META_BUTTON_FUNCTION_ABOVE:
676 case META_BUTTON_FUNCTION_UNSTICK:
677 case META_BUTTON_FUNCTION_UNSHADE:
678 case META_BUTTON_FUNCTION_UNABOVE:
679 /* we are being asked for a >v1 button which hasn't been handled yet,
680 * so obviously we're not in a theme which supports that version.
681 * therefore, we don't show the button. return NULL and all will
682 * be well.
683 */
684 return NULL((void*)0);
685
686 case META_BUTTON_FUNCTION_LAST:
687 return NULL((void*)0);
688 }
689
690 return NULL((void*)0);
691}
692
693static gboolean
694strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
695 GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST],
696 int *n_rects,
697 MetaButtonSpace *to_strip)
698{
699 int i;
700
701 i = 0;
702 while (i < *n_rects)
703 {
704 if (func_rects[i] == to_strip)
705 {
706 *n_rects -= 1;
707
708 /* shift the other rects back in the array */
709 while (i < *n_rects)
710 {
711 func_rects[i] = func_rects[i+1];
712 bg_rects[i] = bg_rects[i+1];
713
714 ++i;
715 }
716
717 func_rects[i] = NULL((void*)0);
718 bg_rects[i] = NULL((void*)0);
719
720 return TRUE(!(0));
721 }
722
723 ++i;
724 }
725
726 return FALSE(0); /* did not strip anything */
727}
728
729void
730meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
731 int text_height,
732 MetaFrameFlags flags,
733 int client_width,
734 int client_height,
735 const MetaButtonLayout *button_layout,
736 MetaFrameGeometry *fgeom,
737 MetaTheme *theme)
738{
739 int i, n_left, n_right, n_left_spacers, n_right_spacers;
740 int x;
741 int button_y;
742 int title_right_edge;
743 int width, height;
744 int button_width, button_height;
745 int min_size_for_rounding;
746
747 /* the left/right rects in order; the max # of rects
748 * is the number of button functions
749 */
750 MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
751 MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
752 GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
753 gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
754 GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
755 gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST];
756
757 MetaFrameBorders borders;
758
759 meta_frame_layout_get_borders (layout, text_height,
760 flags,
761 &borders);
762
763 fgeom->borders = borders;
764
765 width = client_width + borders.total.left + borders.total.right;
766
767 height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
768 borders.total.top + borders.total.bottom;
769
770 fgeom->width = width;
771 fgeom->height = height;
772
773 fgeom->top_titlebar_edge = layout->title_border.top;
774 fgeom->bottom_titlebar_edge = layout->title_border.bottom;
775 fgeom->left_titlebar_edge = layout->left_titlebar_edge;
776 fgeom->right_titlebar_edge = layout->right_titlebar_edge;
777
778 switch (layout->button_sizing)
779 {
780 case META_BUTTON_SIZING_ASPECT:
781 button_height = borders.visible.top - layout->button_border.top - layout->button_border.bottom;
782 button_width = (int) (((double) button_height) / layout->button_aspect);
783 break;
784 case META_BUTTON_SIZING_FIXED:
785 button_width = layout->button_width;
786 button_height = layout->button_height;
787 break;
788 case META_BUTTON_SIZING_LAST:
789 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 789, ((
const char*) (__func__)), ((void*)0)); } while (0)
;
790 default:
791 button_width = -1;
792 button_height = -1;
793 }
794
795 /* FIXME all this code sort of pretends that duplicate buttons
796 * with the same function are allowed, but that breaks the
797 * code in frames.c, so isn't really allowed right now.
798 * Would need left_close_rect, right_close_rect, etc.
799 */
800
801 /* Init all button rects to 0, lame hack */
802 memset (ADDRESS_OF_BUTTON_RECTS (fgeom)(((char*)(fgeom)) + ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
, '\0',
803 LENGTH_OF_BUTTON_RECTS(((glong) __builtin_offsetof(MetaFrameGeometry, right_single_background
)) + sizeof (GdkRectangle) - ((glong) __builtin_offsetof(MetaFrameGeometry
, close_rect)))
);
804
805 n_left = 0;
806 n_right = 0;
807 n_left_spacers = 0;
808 n_right_spacers = 0;
809
810 if (!layout->hide_buttons)
811 {
812 /* Try to fill in rects */
813 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
814 {
815 left_func_rects[n_left] = rect_for_function (fgeom, flags,
816 button_layout->left_buttons[i],
817 theme);
818 if (left_func_rects[n_left] != NULL((void*)0))
819 {
820 left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
821 if (button_layout->left_buttons_has_spacer[i])
822 ++n_left_spacers;
823
824 ++n_left;
825 }
826 }
827
828 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
829 {
830 right_func_rects[n_right] = rect_for_function (fgeom, flags,
831 button_layout->right_buttons[i],
832 theme);
833 if (right_func_rects[n_right] != NULL((void*)0))
834 {
835 right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
836 if (button_layout->right_buttons_has_spacer[i])
837 ++n_right_spacers;
838
839 ++n_right;
840 }
841 }
842 }
843
844 for (i = 0; i < MAX_BUTTONS_PER_CORNERMETA_BUTTON_FUNCTION_LAST; i++)
845 {
846 left_bg_rects[i] = NULL((void*)0);
847 right_bg_rects[i] = NULL((void*)0);
848 }
849
850 for (i = 0; i < n_left; i++)
851 {
852 if (n_left == 1)
853 left_bg_rects[i] = &fgeom->left_single_background;
854 else if (i == 0)
855 left_bg_rects[i] = &fgeom->left_left_background;
856 else if (i == (n_left - 1))
857 left_bg_rects[i] = &fgeom->left_right_background;
858 else
859 left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
860 }
861
862 for (i = 0; i < n_right; i++)
863 {
864 if (n_right == 1)
865 right_bg_rects[i] = &fgeom->right_single_background;
866 else if (i == (n_right - 1))
867 right_bg_rects[i] = &fgeom->right_right_background;
868 else if (i == 0)
869 right_bg_rects[i] = &fgeom->right_left_background;
870 else
871 right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
872 }
873
874 /* Be sure buttons fit */
875 while (n_left > 0 || n_right > 0)
876 {
877 int space_used_by_buttons;
878 int space_available;
879
880 space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
881
882 space_used_by_buttons = 0;
883
884 space_used_by_buttons += button_width * n_left;
885 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_left_spacers));
886 space_used_by_buttons += layout->button_border.left * n_left;
887 space_used_by_buttons += layout->button_border.right * n_left;
888
889 space_used_by_buttons += button_width * n_right;
890 space_used_by_buttons += (int) (0.75 * (double) (button_width * n_right_spacers));
891 space_used_by_buttons += layout->button_border.left * n_right;
892 space_used_by_buttons += layout->button_border.right * n_right;
893
894 if (space_used_by_buttons <= space_available)
895 break; /* Everything fits, bail out */
896
897 /* First try to remove separators */
898 if (n_left_spacers > 0)
899 {
900 left_buttons_has_spacer[--n_left_spacers] = FALSE(0);
901 continue;
902 }
903 else if (n_right_spacers > 0)
904 {
905 right_buttons_has_spacer[--n_right_spacers] = FALSE(0);
906 continue;
907 }
908
909 /* Otherwise we need to shave out a button. Shave
910 * above, stick, shade, min, max, close, then menu (menu is most useful);
911 * prefer the default button locations.
912 */
913 if (strip_button (left_func_rects, left_bg_rects,
914 &n_left, &fgeom->above_rect))
915 continue;
916 else if (strip_button (right_func_rects, right_bg_rects,
917 &n_right, &fgeom->above_rect))
918 continue;
919 else if (strip_button (left_func_rects, left_bg_rects,
920 &n_left, &fgeom->stick_rect))
921 continue;
922 else if (strip_button (right_func_rects, right_bg_rects,
923 &n_right, &fgeom->stick_rect))
924 continue;
925 else if (strip_button (left_func_rects, left_bg_rects,
926 &n_left, &fgeom->shade_rect))
927 continue;
928 else if (strip_button (right_func_rects, right_bg_rects,
929 &n_right, &fgeom->shade_rect))
930 continue;
931 else if (strip_button (left_func_rects, left_bg_rects,
932 &n_left, &fgeom->min_rect))
933 continue;
934 else if (strip_button (right_func_rects, right_bg_rects,
935 &n_right, &fgeom->min_rect))
936 continue;
937 else if (strip_button (left_func_rects, left_bg_rects,
938 &n_left, &fgeom->max_rect))
939 continue;
940 else if (strip_button (right_func_rects, right_bg_rects,
941 &n_right, &fgeom->max_rect))
942 continue;
943 else if (strip_button (left_func_rects, left_bg_rects,
944 &n_left, &fgeom->close_rect))
945 continue;
946 else if (strip_button (right_func_rects, right_bg_rects,
947 &n_right, &fgeom->close_rect))
948 continue;
949 else if (strip_button (right_func_rects, right_bg_rects,
950 &n_right, &fgeom->menu_rect))
951 continue;
952 else if (strip_button (left_func_rects, left_bg_rects,
953 &n_left, &fgeom->menu_rect))
954 continue;
955 else if (strip_button (right_func_rects, right_bg_rects,
956 &n_right, &fgeom->appmenu_rect))
957 continue;
958 else if (strip_button (left_func_rects, left_bg_rects,
959 &n_left, &fgeom->appmenu_rect))
960 continue;
961 else
962 {
963 meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
964 n_left, n_right);
965 }
966 }
967
968 /* Save the button layout */
969 fgeom->button_layout = *button_layout;
970 fgeom->n_left_buttons = n_left;
971 fgeom->n_right_buttons = n_right;
972
973 /* center buttons vertically */
974 button_y = (borders.visible.top -
975 (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top + borders.invisible.top;
976
977 /* right edge of farthest-right button */
978 x = width - layout->right_titlebar_edge - borders.invisible.right;
979
980 i = n_right - 1;
981 while (i >= 0)
982 {
983 MetaButtonSpace *rect;
984
985 if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
986 break;
987
988 rect = right_func_rects[i];
989 rect->visible.x = x - layout->button_border.right - button_width;
990 if (right_buttons_has_spacer[i])
991 rect->visible.x -= (int) (0.75 * (double) button_width);
992
993 rect->visible.y = button_y;
994 rect->visible.width = button_width;
995 rect->visible.height = button_height;
996
997 if (flags & META_FRAME_MAXIMIZED ||
998 flags & META_FRAME_TILED_LEFT ||
999 flags & META_FRAME_TILED_RIGHT)
1000 {
1001 rect->clickable.x = rect->visible.x;
1002 rect->clickable.y = rect->visible.y;
1003 rect->clickable.width = button_width;
1004 rect->clickable.height = button_height;
1005
1006 if (i == n_right - 1)
1007 rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
1008
1009 }
1010 else
1011 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1012
1013 *(right_bg_rects[i]) = rect->visible;
1014
1015 x = rect->visible.x - layout->button_border.left;
1016
1017 --i;
1018 }
1019
1020 /* save right edge of titlebar for later use */
1021 title_right_edge = x - layout->title_border.right;
1022
1023 /* Now x changes to be position from the left and we go through
1024 * the left-side buttons
1025 */
1026 x = layout->left_titlebar_edge + borders.invisible.left;
1027 for (i = 0; i < n_left; i++)
1028 {
1029 MetaButtonSpace *rect;
1030
1031 rect = left_func_rects[i];
1032
1033 rect->visible.x = x + layout->button_border.left;
1034 rect->visible.y = button_y;
1035 rect->visible.width = button_width;
1036 rect->visible.height = button_height;
1037
1038 if (flags & META_FRAME_MAXIMIZED)
1039 {
1040 rect->clickable.x = rect->visible.x;
1041 rect->clickable.y = rect->visible.y;
1042 rect->clickable.width = button_width;
1043 rect->clickable.height = button_height;
1044 }
1045 else
1046 memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
1047
1048 x = rect->visible.x + rect->visible.width + layout->button_border.right;
1049 if (left_buttons_has_spacer[i])
1050 x += (int) (0.75 * (double) button_width);
1051
1052 *(left_bg_rects[i]) = rect->visible;
1053 }
1054
1055 /* We always fill as much vertical space as possible with title rect,
1056 * rather than centering it like the buttons
1057 */
1058 fgeom->title_rect.x = x + layout->title_border.left;
1059 fgeom->title_rect.y = layout->title_border.top + borders.invisible.top;
1060 fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
1061 fgeom->title_rect.height = borders.visible.top - layout->title_border.top - layout->title_border.bottom;
1062
1063 /* Nuke title if it won't fit */
1064 if (fgeom->title_rect.width < 0 ||
1065 fgeom->title_rect.height < 0)
1066 {
1067 fgeom->title_rect.width = 0;
1068 fgeom->title_rect.height = 0;
1069 }
1070
1071 if (flags & META_FRAME_SHADED)
1072 min_size_for_rounding = 0;
1073 else
1074 min_size_for_rounding = 5;
1075
1076 fgeom->top_left_corner_rounded_radius = 0;
1077 fgeom->top_right_corner_rounded_radius = 0;
1078 fgeom->bottom_left_corner_rounded_radius = 0;
1079 fgeom->bottom_right_corner_rounded_radius = 0;
1080
1081 if (borders.visible.top + borders.visible.left >= min_size_for_rounding)
1082 fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
1083 if (borders.visible.top + borders.visible.right >= min_size_for_rounding)
1084 fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
1085
1086 if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding)
1087 fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
1088 if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding)
1089 fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
1090}
1091
1092MetaGradientSpec*
1093meta_gradient_spec_new (MetaGradientType type)
1094{
1095 MetaGradientSpec *spec;
1096
1097 spec = g_new (MetaGradientSpec, 1)((MetaGradientSpec *) g_malloc_n ((1), sizeof (MetaGradientSpec
)))
;
1098
1099 spec->type = type;
1100 spec->color_specs = NULL((void*)0);
1101
1102 return spec;
1103}
1104
1105static cairo_pattern_t *
1106create_cairo_pattern_from_gradient_spec (const MetaGradientSpec *spec,
1107 const MetaAlphaGradientSpec *alpha_spec,
1108 GtkStyleContext *context)
1109{
1110 gint n_colors;
1111 cairo_pattern_t *pattern;
1112 GSList *tmp;
1113 gint i;
1114
1115 n_colors = g_slist_length (spec->color_specs);
1116 if (n_colors == 0)
1117 return NULL((void*)0);
1118
1119 if (alpha_spec != NULL((void*)0) && alpha_spec->n_alphas != 1)
1120 g_assert (n_colors == alpha_spec->n_alphas)do { if (n_colors == alpha_spec->n_alphas) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1120, ((const char*) (__func__)), "n_colors == alpha_spec->n_alphas"
); } while (0)
;
1121
1122 if (spec->type == META_GRADIENT_HORIZONTAL)
1123 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1124 else if (spec->type == META_GRADIENT_VERTICAL)
1125 pattern = cairo_pattern_create_linear (0, 0, 0, 1);
1126 else if (spec->type == META_GRADIENT_DIAGONAL)
1127 pattern = cairo_pattern_create_linear (0, 0, 1, 1);
1128 else
1129 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1129, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1130
1131 i = 0;
1132 tmp = spec->color_specs;
1133 while (tmp != NULL((void*)0))
1134 {
1135 GdkRGBA color;
1136
1137 meta_color_spec_render (tmp->data, context, &color);
1138
1139 if (alpha_spec != NULL((void*)0))
1140 {
1141 gdouble alpha;
1142
1143 if (alpha_spec->n_alphas == 1)
1144 alpha = alpha_spec->alphas[0] / 255.0;
1145 else
1146 alpha = alpha_spec->alphas[i] / 255.0;
1147
1148 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_colors - 1),
1149 color.red, color.green, color.blue,
1150 alpha);
1151 }
1152 else
1153 cairo_pattern_add_color_stop_rgb (pattern, i / (gfloat) (n_colors - 1),
1154 color.red, color.green, color.blue);
1155
1156 tmp = tmp->next;
1157 ++i;
1158 }
1159
1160 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1161 {
1162 cairo_pattern_destroy (pattern);
1163 return NULL((void*)0);
1164 }
1165
1166 return pattern;
1167}
1168
1169static void
1170free_color_spec (gpointer spec, gpointer user_data)
1171{
1172 meta_color_spec_free (spec);
1173}
1174
1175void
1176meta_gradient_spec_free (MetaGradientSpec *spec)
1177{
1178 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1179
1180 g_slist_foreach (spec->color_specs, free_color_spec, NULL((void*)0));
1181 g_slist_free (spec->color_specs);
1182
1183 DEBUG_FILL_STRUCT (spec)memset ((spec), 0xef, sizeof (*(spec)));
1184 g_free (spec);
1185}
1186
1187void
1188meta_gradient_spec_render (const MetaGradientSpec *spec,
1189 const MetaAlphaGradientSpec *alpha_spec,
1190 cairo_t *cr,
1191 GtkStyleContext *context,
1192 gint x,
1193 gint y,
1194 gint width,
1195 gint height)
1196{
1197 cairo_pattern_t *pattern;
1198
1199 pattern = create_cairo_pattern_from_gradient_spec (spec, alpha_spec, context);
1200 if (pattern == NULL((void*)0))
1201 return;
1202
1203 cairo_save (cr);
1204
1205 cairo_rectangle (cr, x, y, width, height);
1206
1207 cairo_translate (cr, x, y);
1208 cairo_scale (cr, width, height);
1209
1210 cairo_set_source (cr, pattern);
1211 cairo_fill (cr);
1212 cairo_pattern_destroy (pattern);
1213
1214 cairo_restore (cr);
1215}
1216
1217gboolean
1218meta_gradient_spec_validate (MetaGradientSpec *spec,
1219 GError **error)
1220{
1221 g_return_val_if_fail (spec != NULL, FALSE)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
((0)); } } while (0)
;
1222
1223 if (g_slist_length (spec->color_specs) < 2)
1224 {
1225 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1226 META_THEME_ERROR_FAILED,
1227 _("Gradients should have at least two colors")((char *) g_dgettext ("marco", "Gradients should have at least two colors"
))
);
1228 return FALSE(0);
1229 }
1230
1231 return TRUE(!(0));
1232}
1233
1234MetaAlphaGradientSpec*
1235meta_alpha_gradient_spec_new (MetaGradientType type,
1236 int n_alphas)
1237{
1238 MetaAlphaGradientSpec *spec;
1239
1240 g_return_val_if_fail (n_alphas > 0, NULL)do { if ((n_alphas > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_alphas > 0"); return
(((void*)0)); } } while (0)
;
1241
1242 spec = g_new0 (MetaAlphaGradientSpec, 1)((MetaAlphaGradientSpec *) g_malloc0_n ((1), sizeof (MetaAlphaGradientSpec
)))
;
1243
1244 spec->type = type;
1245 spec->alphas = g_new0 (unsigned char, n_alphas)((unsigned char *) g_malloc0_n ((n_alphas), sizeof (unsigned char
)))
;
1246 spec->n_alphas = n_alphas;
1247
1248 return spec;
1249}
1250
1251void
1252meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
1253{
1254 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1255
1256 g_free (spec->alphas);
1257 g_free (spec);
1258}
1259
1260cairo_pattern_t *
1261meta_alpha_gradient_spec_get_mask (const MetaAlphaGradientSpec *spec)
1262{
1263 gint n_alphas;
1264 cairo_pattern_t *pattern;
1265 gint i;
1266
1267 /* Hardcoded in theme-parser.c */
1268 g_assert (spec->type == META_GRADIENT_HORIZONTAL)do { if (spec->type == META_GRADIENT_HORIZONTAL) ; else g_assertion_message_expr
("marco", "ui/theme.c", 1268, ((const char*) (__func__)), "spec->type == META_GRADIENT_HORIZONTAL"
); } while (0)
;
1269
1270 n_alphas = spec->n_alphas;
1271 if (n_alphas == 0)
1272 return NULL((void*)0);
1273
1274 if (n_alphas == 1)
1275 return cairo_pattern_create_rgba (0, 0, 0, spec->alphas[0] / 255.0);
1276
1277 pattern = cairo_pattern_create_linear (0, 0, 1, 0);
1278
1279 for (i = 0; i < n_alphas; i++)
1280 cairo_pattern_add_color_stop_rgba (pattern, i / (gfloat) (n_alphas - 1),
1281 0, 0, 0, spec->alphas[i] / 255.0);
1282
1283 if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
1284 {
1285 cairo_pattern_destroy (pattern);
1286 return NULL((void*)0);
1287 }
1288
1289 return pattern;
1290}
1291
1292MetaColorSpec*
1293meta_color_spec_new (MetaColorSpecType type)
1294{
1295 MetaColorSpec *spec;
1296 MetaColorSpec dummy;
1297 int size;
1298
1299 size = G_STRUCT_OFFSET (MetaColorSpec, data)((glong) __builtin_offsetof(MetaColorSpec, data));
1300
1301 switch (type)
1302 {
1303 case META_COLOR_SPEC_BASIC:
1304 size += sizeof (dummy.data.basic);
1305 break;
1306
1307 case META_COLOR_SPEC_GTK:
1308 size += sizeof (dummy.data.gtk);
1309 break;
1310
1311 case META_COLOR_SPEC_GTK_CUSTOM:
1312 size += sizeof (dummy.data.gtkcustom);
1313 break;
1314
1315 case META_COLOR_SPEC_BLEND:
1316 size += sizeof (dummy.data.blend);
1317 break;
1318
1319 case META_COLOR_SPEC_SHADE:
1320 size += sizeof (dummy.data.shade);
1321 break;
1322 }
1323
1324 spec = g_malloc0 (size);
1325
1326 spec->type = type;
1327
1328 return spec;
1329}
1330
1331void
1332meta_color_spec_free (MetaColorSpec *spec)
1333{
1334 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1335
1336 switch (spec->type)
1337 {
1338 case META_COLOR_SPEC_BASIC:
1339 DEBUG_FILL_STRUCT (&spec->data.basic)memset ((&spec->data.basic), 0xef, sizeof (*(&spec
->data.basic)))
;
1340 break;
1341
1342 case META_COLOR_SPEC_GTK:
1343 DEBUG_FILL_STRUCT (&spec->data.gtk)memset ((&spec->data.gtk), 0xef, sizeof (*(&spec->
data.gtk)))
;
1344 break;
1345
1346 case META_COLOR_SPEC_GTK_CUSTOM:
1347 if (spec->data.gtkcustom.color_name)
1348 g_free (spec->data.gtkcustom.color_name);
1349 if (spec->data.gtkcustom.fallback)
1350 meta_color_spec_free (spec->data.gtkcustom.fallback);
1351 DEBUG_FILL_STRUCT (&spec->data.gtkcustom)memset ((&spec->data.gtkcustom), 0xef, sizeof (*(&
spec->data.gtkcustom)))
;
1352 break;
1353
1354 case META_COLOR_SPEC_BLEND:
1355 if (spec->data.blend.foreground)
1356 meta_color_spec_free (spec->data.blend.foreground);
1357 if (spec->data.blend.background)
1358 meta_color_spec_free (spec->data.blend.background);
1359 DEBUG_FILL_STRUCT (&spec->data.blend)memset ((&spec->data.blend), 0xef, sizeof (*(&spec
->data.blend)))
;
1360 break;
1361
1362 case META_COLOR_SPEC_SHADE:
1363 if (spec->data.shade.base)
1364 meta_color_spec_free (spec->data.shade.base);
1365 DEBUG_FILL_STRUCT (&spec->data.shade)memset ((&spec->data.shade), 0xef, sizeof (*(&spec
->data.shade)))
;
1366 break;
1367 }
1368
1369 g_free (spec);
1370}
1371
1372MetaColorSpec*
1373meta_color_spec_new_from_string (const char *str,
1374 GError **err)
1375{
1376 MetaColorSpec *spec;
1377
1378 spec = NULL((void*)0);
1379
1380 if (strncmp (str, "gtk:custom", 10) == 0)
1381 {
1382 const char *color_name_start, *fallback_str_start, *end;
1383 char *color_name;
1384 MetaColorSpec *fallback = NULL((void*)0);
1385 static gboolean debug, debug_set = FALSE(0);
1386
1387 if (!debug_set)
1388 {
1389 debug = g_getenv ("MARCO_DISABLE_FALLBACK_COLOR") != NULL((void*)0);
1390 debug_set = TRUE(!(0));
1391 }
1392
1393 if (str[10] != '(')
1394 {
1395 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1396 META_THEME_ERROR_FAILED,
1397 _("GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK custom color specification must have color name and fallback in parentheses, e.g. gtk:custom(foo,bar); could not parse \"%s\""
))
,
1398 str);
1399 return NULL((void*)0);
1400 }
1401
1402 color_name_start = str + 11;
1403
1404 fallback_str_start = color_name_start;
1405 while (*fallback_str_start && *fallback_str_start != ',')
1406 {
1407 if (!(g_ascii_isalnum (*fallback_str_start)((g_ascii_table[(guchar) (*fallback_str_start)] & G_ASCII_ALNUM
) != 0)
1408 || *fallback_str_start == '-'
1409 || *fallback_str_start == '_'))
1410 {
1411 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1412 META_THEME_ERROR_FAILED,
1413 _("Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid")((char *) g_dgettext ("marco", "Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-_ are valid"
))
,
1414 *fallback_str_start);
1415 return NULL((void*)0);
1416 }
1417 fallback_str_start++;
1418 }
1419 fallback_str_start++;
1420
1421 end = strrchr (str, ')');
1422
1423 if (color_name_start == NULL((void*)0) || fallback_str_start == NULL((void*)0) || end == NULL((void*)0))
1424 {
1425 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1426 META_THEME_ERROR_FAILED,
1427 _("Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not fit the format"
))
,
1428 str);
1429 return NULL((void*)0);
1430 }
1431
1432 if (!debug)
1433 {
1434 char *fallback_str;
1435 fallback_str = g_strndup (fallback_str_start,
1436 end - fallback_str_start);
1437 fallback = meta_color_spec_new_from_string (fallback_str, err);
1438 g_free (fallback_str);
1439 }
1440 else
1441 {
1442 fallback = meta_color_spec_new_from_string ("pink", err);
1443 }
1444
1445 if (fallback == NULL((void*)0))
1446 return NULL((void*)0);
1447
1448 color_name = g_strndup (color_name_start, fallback_str_start - color_name_start - 1);
1449
1450 spec = meta_color_spec_new (META_COLOR_SPEC_GTK_CUSTOM);
1451 spec->data.gtkcustom.color_name = color_name;
1452 spec->data.gtkcustom.fallback = fallback;
1453 }
1454 else if (strncmp (str, "gtk:", 4) == 0)
1455 {
1456 /* GTK color */
1457 const char *bracket;
1458 const char *end_bracket;
1459 char *tmp;
1460 GtkStateFlags state;
1461 MetaGtkColorComponent component;
1462
1463 bracket = str;
1464 while (*bracket && *bracket != '[')
1465 ++bracket;
1466
1467 if (*bracket == '\0')
1468 {
1469 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1470 META_THEME_ERROR_FAILED,
1471 _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1472 str);
1473 return NULL((void*)0);
1474 }
1475
1476 end_bracket = bracket;
1477 ++end_bracket;
1478 while (*end_bracket && *end_bracket != ']')
1479 ++end_bracket;
1480
1481 if (*end_bracket == '\0')
1482 {
1483 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1484 META_THEME_ERROR_FAILED,
1485 _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\"")((char *) g_dgettext ("marco", "GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""
))
,
1486 str);
1487 return NULL((void*)0);
1488 }
1489
1490 tmp = g_strndup (bracket + 1, end_bracket - bracket - 1);
1491 state = meta_gtk_state_from_string (tmp);
1492 if (((int) state) == -1)
1493 {
1494 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1495 META_THEME_ERROR_FAILED,
1496 _("Did not understand state \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand state \"%s\" in color specification"
))
,
1497 tmp);
1498 g_free (tmp);
1499 return NULL((void*)0);
1500 }
1501 g_free (tmp);
1502
1503 tmp = g_strndup (str + 4, bracket - str - 4);
1504 component = meta_color_component_from_string (tmp);
1505 if (component == META_GTK_COLOR_LAST)
1506 {
1507 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1508 META_THEME_ERROR_FAILED,
1509 _("Did not understand color component \"%s\" in color specification")((char *) g_dgettext ("marco", "Did not understand color component \"%s\" in color specification"
))
,
1510 tmp);
1511 g_free (tmp);
1512 return NULL((void*)0);
1513 }
1514 g_free (tmp);
1515
1516 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1517 spec->data.gtk.state = state;
1518 spec->data.gtk.component = component;
1519 g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST)do { if (spec->data.gtk.component < META_GTK_COLOR_LAST
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 1519
, ((const char*) (__func__)), "spec->data.gtk.component < META_GTK_COLOR_LAST"
); } while (0)
;
1520 }
1521 else if (strncmp (str, "blend/", 6) == 0)
1522 {
1523 /* blend */
1524 char **split;
1525 double alpha;
1526 char *end;
1527 MetaColorSpec *fg;
1528 MetaColorSpec *bg;
1529
1530 split = g_strsplit (str, "/", 4);
1531
1532 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1533 split[2] == NULL((void*)0) || split[3] == NULL((void*)0))
1534 {
1535 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1536 META_THEME_ERROR_FAILED,
1537 _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"
))
,
1538 str);
1539 g_strfreev (split);
1540 return NULL((void*)0);
1541 }
1542
1543 alpha = g_ascii_strtod (split[3], &end);
1544 if (end == split[3])
1545 {
1546 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1547 META_THEME_ERROR_FAILED,
1548 _("Could not parse alpha value \"%s\" in blended color")((char *) g_dgettext ("marco", "Could not parse alpha value \"%s\" in blended color"
))
,
1549 split[3]);
1550 g_strfreev (split);
1551 return NULL((void*)0);
1552 }
1553
1554 if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6))
1555 {
1556 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1557 META_THEME_ERROR_FAILED,
1558 _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0")((char *) g_dgettext ("marco", "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
))
,
1559 split[3]);
1560 g_strfreev (split);
1561 return NULL((void*)0);
1562 }
1563
1564 fg = NULL((void*)0);
1565 bg = NULL((void*)0);
1566
1567 bg = meta_color_spec_new_from_string (split[1], err);
1568 if (bg == NULL((void*)0))
1569 {
1570 g_strfreev (split);
1571 return NULL((void*)0);
1572 }
1573
1574 fg = meta_color_spec_new_from_string (split[2], err);
1575 if (fg == NULL((void*)0))
1576 {
1577 meta_color_spec_free (bg);
1578 g_strfreev (split);
1579 return NULL((void*)0);
1580 }
1581
1582 g_strfreev (split);
1583
1584 spec = meta_color_spec_new (META_COLOR_SPEC_BLEND);
1585 spec->data.blend.alpha = alpha;
1586 spec->data.blend.background = bg;
1587 spec->data.blend.foreground = fg;
1588 }
1589 else if (strncmp (str, "shade/", 6) == 0)
1590 {
1591 /* shade */
1592 char **split;
1593 double factor;
1594 char *end;
1595 MetaColorSpec *base;
1596
1597 split = g_strsplit (str, "/", 3);
1598
1599 if (split[0] == NULL((void*)0) || split[1] == NULL((void*)0) ||
1600 split[2] == NULL((void*)0))
1601 {
1602 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1603 META_THEME_ERROR_FAILED,
1604 _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format")((char *) g_dgettext ("marco", "Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
))
,
1605 str);
1606 g_strfreev (split);
1607 return NULL((void*)0);
1608 }
1609
1610 factor = g_ascii_strtod (split[2], &end);
1611 if (end == split[2])
1612 {
1613 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1614 META_THEME_ERROR_FAILED,
1615 _("Could not parse shade factor \"%s\" in shaded color")((char *) g_dgettext ("marco", "Could not parse shade factor \"%s\" in shaded color"
))
,
1616 split[2]);
1617 g_strfreev (split);
1618 return NULL((void*)0);
1619 }
1620
1621 if (factor < (0.0 - 1e6))
1622 {
1623 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1624 META_THEME_ERROR_FAILED,
1625 _("Shade factor \"%s\" in shaded color is negative")((char *) g_dgettext ("marco", "Shade factor \"%s\" in shaded color is negative"
))
,
1626 split[2]);
1627 g_strfreev (split);
1628 return NULL((void*)0);
1629 }
1630
1631 base = NULL((void*)0);
1632
1633 base = meta_color_spec_new_from_string (split[1], err);
1634 if (base == NULL((void*)0))
1635 {
1636 g_strfreev (split);
1637 return NULL((void*)0);
1638 }
1639
1640 g_strfreev (split);
1641
1642 spec = meta_color_spec_new (META_COLOR_SPEC_SHADE);
1643 spec->data.shade.factor = factor;
1644 spec->data.shade.base = base;
1645 }
1646 else
1647 {
1648 spec = meta_color_spec_new (META_COLOR_SPEC_BASIC);
1649
1650 if (!gdk_rgba_parse (&spec->data.basic.color, str))
1651 {
1652 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
1653 META_THEME_ERROR_FAILED,
1654 _("Could not parse color \"%s\"")((char *) g_dgettext ("marco", "Could not parse color \"%s\""
))
,
1655 str);
1656 meta_color_spec_free (spec);
1657 return NULL((void*)0);
1658 }
1659 }
1660
1661 g_assert (spec)do { if (spec) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 1661, ((const char*) (__func__)), "spec"); } while (0)
;
1662
1663 return spec;
1664}
1665
1666MetaColorSpec*
1667meta_color_spec_new_gtk (MetaGtkColorComponent component,
1668 GtkStateFlags state)
1669{
1670 MetaColorSpec *spec;
1671
1672 spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
1673
1674 spec->data.gtk.component = component;
1675 spec->data.gtk.state = state;
1676
1677 return spec;
1678}
1679
1680static void
1681get_background_color_real (GtkStyleContext *context,
1682 GtkStateFlags state,
1683 GdkRGBA *color)
1684{
1685 GdkRGBA *c;
1686
1687 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "color != NULL"); return
; } } while (0)
;
1688 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context)); GType __t = ((gtk_style_context_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("marco", ((const char
*) (__func__)), "GTK_IS_STYLE_CONTEXT (context)"); return; } }
while (0)
;
1689
1690 gtk_style_context_get (context,
1691 state,
1692 "background-color", &c,
1693 NULL((void*)0));
1694
1695 *color = *c;
1696 gdk_rgba_free (c);
1697}
1698
1699static void
1700get_background_color (GtkStyleContext *context,
1701 GtkStateFlags state,
1702 GdkRGBA *color)
1703{
1704 GdkRGBA empty = { 0.0, 0.0, 0.0, 0.0 };
1705 GdkRGBA rgba;
1706
1707 get_background_color_real (context, state, &rgba);
1708
1709 if (gdk_rgba_equal (&rgba, &empty))
1710 {
1711 GtkWidget *toplevel;
1712 GtkStyleContext *tmp;
1713
1714 toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1715 tmp = gtk_widget_get_style_context (toplevel);
1716
1717 get_background_color_real (tmp, state, &rgba);
1718
1719 gtk_widget_destroy (toplevel);
1720 }
1721
1722 *color = rgba;
1723}
1724
1725/* Based on set_color() in gtkstyle.c */
1726#define LIGHTNESS_MULT1.3 1.3
1727#define DARKNESS_MULT0.7 0.7
1728void
1729meta_gtk_style_get_light_color (GtkStyleContext *style,
1730 GtkStateFlags state,
1731 GdkRGBA *color)
1732{
1733 get_background_color (style, state, color);
1734 gtk_style_shade (color, color, LIGHTNESS_MULT1.3);
1735}
1736
1737void
1738meta_gtk_style_get_dark_color (GtkStyleContext *style,
1739 GtkStateFlags state,
1740 GdkRGBA *color)
1741{
1742 get_background_color (style, state, color);
1743 gtk_style_shade (color, color, DARKNESS_MULT0.7);
1744}
1745
1746static void
1747meta_set_color_from_style (GdkRGBA *color,
1748 GtkStyleContext *context,
1749 GtkStateFlags state,
1750 MetaGtkColorComponent component)
1751{
1752 GdkRGBA other;
1753
1754 /* Add background class to context to get the correct colors from the GTK+
1755 theme instead of white text over black background. */
1756 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND"background");
1757
1758 switch (component)
1759 {
1760 case META_GTK_COLOR_BG:
1761 case META_GTK_COLOR_BASE:
1762 get_background_color (context, state, color);
1763 break;
1764 case META_GTK_COLOR_FG:
1765 case META_GTK_COLOR_TEXT:
1766 gtk_style_context_get_color (context, state, color);
1767 break;
1768 case META_GTK_COLOR_TEXT_AA:
1769 gtk_style_context_get_color (context, state, color);
1770 meta_set_color_from_style (&other, context, state, META_GTK_COLOR_BASE);
1771
1772 color->red = (color->red + other.red) / 2;
1773 color->green = (color->green + other.green) / 2;
1774 color->blue = (color->blue + other.blue) / 2;
1775 break;
1776 case META_GTK_COLOR_MID:
1777 meta_gtk_style_get_light_color (context, state, color);
1778 meta_gtk_style_get_dark_color (context, state, &other);
1779
1780 color->red = (color->red + other.red) / 2;
1781 color->green = (color->green + other.green) / 2;
1782 color->blue = (color->blue + other.blue) / 2;
1783 break;
1784 case META_GTK_COLOR_LIGHT:
1785 meta_gtk_style_get_light_color (context, state, color);
1786 break;
1787 case META_GTK_COLOR_DARK:
1788 meta_gtk_style_get_dark_color (context, state, color);
1789 break;
1790 case META_GTK_COLOR_LAST:
1791 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 1791, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1792 break;
1793 }
1794}
1795
1796static void
1797meta_set_custom_color_from_style (GdkRGBA *color,
1798 GtkStyleContext *context,
1799 char *color_name,
1800 MetaColorSpec *fallback)
1801{
1802 if (!gtk_style_context_lookup_color (context, color_name, color))
1803 meta_color_spec_render (fallback, context, color);
1804}
1805
1806void
1807meta_color_spec_render (MetaColorSpec *spec,
1808 GtkStyleContext *style,
1809 GdkRGBA *color)
1810{
1811 g_return_if_fail (spec != NULL)do { if ((spec != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "spec != NULL"); return
; } } while (0)
;
1812
1813 g_return_if_fail (GTK_IS_STYLE_CONTEXT (style))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((style)); GType __t = ((gtk_style_context_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GTK_IS_STYLE_CONTEXT (style)"); return; } } while (0)
;
1814
1815 switch (spec->type)
1816 {
1817 case META_COLOR_SPEC_BASIC:
1818 *color = spec->data.basic.color;
1819 break;
1820
1821 case META_COLOR_SPEC_GTK:
1822 meta_set_color_from_style (color,
1823 style,
1824 spec->data.gtk.state,
1825 spec->data.gtk.component);
1826 break;
1827
1828 case META_COLOR_SPEC_GTK_CUSTOM:
1829 meta_set_custom_color_from_style (color,
1830 style,
1831 spec->data.gtkcustom.color_name,
1832 spec->data.gtkcustom.fallback);
1833 break;
1834
1835 case META_COLOR_SPEC_BLEND:
1836 {
1837 GdkRGBA bg, fg;
1838
1839 meta_color_spec_render (spec->data.blend.background, style, &bg);
1840 meta_color_spec_render (spec->data.blend.foreground, style, &fg);
1841
1842 color_composite (&bg, &fg, spec->data.blend.alpha,
1843 &spec->data.blend.color);
1844
1845 *color = spec->data.blend.color;
1846 }
1847 break;
1848
1849 case META_COLOR_SPEC_SHADE:
1850 {
1851 meta_color_spec_render (spec->data.shade.base, style,
1852 &spec->data.shade.color);
1853
1854 gtk_style_shade (&spec->data.shade.color,
1855 &spec->data.shade.color, spec->data.shade.factor);
1856
1857 *color = spec->data.shade.color;
1858 }
1859 break;
1860 }
1861}
1862
1863/**
1864 * Represents an operation as a string.
1865 *
1866 * \param type an operation, such as addition
1867 * \return a string, such as "+"
1868 */
1869static const char*
1870op_name (PosOperatorType type)
1871{
1872 switch (type)
1873 {
1874 case POS_OP_ADD:
1875 return "+";
1876 case POS_OP_SUBTRACT:
1877 return "-";
1878 case POS_OP_MULTIPLY:
1879 return "*";
1880 case POS_OP_DIVIDE:
1881 return "/";
1882 case POS_OP_MOD:
1883 return "%";
1884 case POS_OP_MAX:
1885 return "`max`";
1886 case POS_OP_MIN:
1887 return "`min`";
1888 case POS_OP_NONE:
1889 break;
1890 }
1891
1892 return "<unknown>";
1893}
1894
1895/**
1896 * Parses a string and returns an operation.
1897 *
1898 * \param p a pointer into a string representing an operation; part of an
1899 * expression somewhere, so not null-terminated
1900 * \param len set to the length of the string found. Set to 0 if none is.
1901 * \return the operation found. If none was, returns POS_OP_NONE.
1902 */
1903static PosOperatorType
1904op_from_string (const char *p,
1905 int *len)
1906{
1907 *len = 0;
1908
1909 switch (*p)
1910 {
1911 case '+':
1912 *len = 1;
1913 return POS_OP_ADD;
1914 case '-':
1915 *len = 1;
1916 return POS_OP_SUBTRACT;
1917 case '*':
1918 *len = 1;
1919 return POS_OP_MULTIPLY;
1920 case '/':
1921 *len = 1;
1922 return POS_OP_DIVIDE;
1923 case '%':
1924 *len = 1;
1925 return POS_OP_MOD;
1926
1927 case '`':
1928 if (strncmp (p, "`max`", 5) == 0)
1929 {
1930 *len = 5;
1931 return POS_OP_MAX;
1932 }
1933 else if (strncmp (p, "`min`", 5) == 0)
1934 {
1935 *len = 5;
1936 return POS_OP_MIN;
1937 }
1938 }
1939
1940 return POS_OP_NONE;
1941}
1942
1943/**
1944 * Frees an array of tokens. All the tokens and their associated memory
1945 * will be freed.
1946 *
1947 * \param tokens an array of tokens to be freed
1948 * \param n_tokens how many tokens are in the array.
1949 */
1950static void
1951free_tokens (PosToken *tokens,
1952 int n_tokens)
1953{
1954 int i;
1955
1956 /* n_tokens can be 0 since tokens may have been allocated more than
1957 * it was initialized
1958 */
1959
1960 for (i = 0; i < n_tokens; i++)
1961 if (tokens[i].type == POS_TOKEN_VARIABLE)
1962 g_free (tokens[i].d.v.name);
1963
1964 g_free (tokens);
1965}
1966
1967/**
1968 * Tokenises a number in an expression.
1969 *
1970 * \param p a pointer into a string representing an operation; part of an
1971 * expression somewhere, so not null-terminated
1972 * \param end_return set to a pointer to the end of the number found; but
1973 * not updated if no number was found at all
1974 * \param next set to either an integer or a float token
1975 * \param[out] err set to the problem if there was a problem
1976 * \return TRUE if a valid number was found, FALSE otherwise (and "err" will
1977 * have been set)
1978 *
1979 * \bug The "while (*start)..." part: what's wrong with strchr-ish things?
1980 * \bug The name is wrong: it doesn't parse anything.
1981 * \ingroup tokenizer
1982 */
1983static gboolean
1984parse_number (const char *p,
1985 const char **end_return,
1986 PosToken *next,
1987 GError **err)
1988{
1989 const char *start = p;
1990 char *end;
1991 gboolean is_float;
1992 char *num_str;
1993
1994 while (*p && (*p == '.' || g_ascii_isdigit (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0)))
1995 ++p;
1996
1997 if (p == start)
1998 {
1999 char buf[7] = { '\0' };
2000 buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0';
2001 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2002 META_THEME_ERROR_BAD_CHARACTER,
2003 _("Coordinate expression contains character '%s' which is not allowed")((char *) g_dgettext ("marco", "Coordinate expression contains character '%s' which is not allowed"
))
,
2004 buf);
2005 return FALSE(0);
2006 }
2007
2008 *end_return = p;
2009
2010 /* we need this to exclude floats like "1e6" */
2011 num_str = g_strndup (start, p - start);
2012 start = num_str;
2013 is_float = FALSE(0);
2014 while (*start)
2015 {
2016 if (*start == '.')
2017 is_float = TRUE(!(0));
2018 ++start;
2019 }
2020
2021 if (is_float)
2022 {
2023 next->type = POS_TOKEN_DOUBLE;
2024 next->d.d.val = g_ascii_strtod (num_str, &end);
2025
2026 if (end == num_str)
2027 {
2028 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2029 META_THEME_ERROR_FAILED,
2030 _("Coordinate expression contains floating point number '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains floating point number '%s' which could not be parsed"
))
,
2031 num_str);
2032 g_free (num_str);
2033 return FALSE(0);
2034 }
2035 }
2036 else
2037 {
2038 next->type = POS_TOKEN_INT;
2039 next->d.i.val = strtol (num_str, &end, 10);
2040 if (end == num_str)
2041 {
2042 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2043 META_THEME_ERROR_FAILED,
2044 _("Coordinate expression contains integer '%s' which could not be parsed")((char *) g_dgettext ("marco", "Coordinate expression contains integer '%s' which could not be parsed"
))
,
2045 num_str);
2046 g_free (num_str);
2047 return FALSE(0);
2048 }
2049 }
2050
2051 g_free (num_str);
2052
2053 g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE)do { if (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE
) ; else g_assertion_message_expr ("marco", "ui/theme.c", 2053
, ((const char*) (__func__)), "next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE"
); } while (0)
;
2054
2055 return TRUE(!(0));
2056}
2057
2058/**
2059 * Whether a variable can validly appear as part of the name of a variable.
2060 */
2061#define IS_VARIABLE_CHAR(c)(((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) ||
(c) == '_')
(g_ascii_isalpha ((c))((g_ascii_table[(guchar) ((c))] & G_ASCII_ALPHA) != 0) || (c) == '_')
2062
2063#if 0
2064static void
2065debug_print_tokens (PosToken *tokens,
2066 int n_tokens)
2067{
2068 int i;
2069
2070 for (i = 0; i < n_tokens; i++)
2071 {
2072 PosToken *t = &tokens[i];
2073
2074 g_print (" ");
2075
2076 switch (t->type)
2077 {
2078 case POS_TOKEN_INT:
2079 g_print ("\"%d\"", t->d.i.val);
2080 break;
2081 case POS_TOKEN_DOUBLE:
2082 g_print ("\"%g\"", t->d.d.val);
2083 break;
2084 case POS_TOKEN_OPEN_PAREN:
2085 g_print ("\"(\"");
2086 break;
2087 case POS_TOKEN_CLOSE_PAREN:
2088 g_print ("\")\"");
2089 break;
2090 case POS_TOKEN_VARIABLE:
2091 g_print ("\"%s\"", t->d.v.name);
2092 break;
2093 case POS_TOKEN_OPERATOR:
2094 g_print ("\"%s\"", op_name (t->d.o.op));
2095 break;
2096 }
2097 }
2098
2099 g_print ("\n");
2100}
2101#endif
2102
2103/**
2104 * Tokenises an expression.
2105 *
2106 * \param expr The expression
2107 * \param[out] tokens_p The resulting tokens
2108 * \param[out] n_tokens_p The number of resulting tokens
2109 * \param[out] err set to the problem if there was a problem
2110 *
2111 * \return True if the expression was successfully tokenised; false otherwise.
2112 *
2113 * \ingroup tokenizer
2114 */
2115static gboolean
2116pos_tokenize (const char *expr,
2117 PosToken **tokens_p,
2118 int *n_tokens_p,
2119 GError **err)
2120{
2121 PosToken *tokens;
2122 int n_tokens;
2123 int allocated;
2124 const char *p;
2125
2126 *tokens_p = NULL((void*)0);
2127 *n_tokens_p = 0;
2128
2129 allocated = 3;
2130 n_tokens = 0;
2131 tokens = g_new (PosToken, allocated)((PosToken *) g_malloc_n ((allocated), sizeof (PosToken)));
2132
2133 p = expr;
2134 while (*p)
2135 {
2136 PosToken *next;
2137 int len;
2138
2139 if (n_tokens == allocated)
2140 {
2141 allocated *= 2;
2142 tokens = g_renew (PosToken, tokens, allocated)((PosToken *) g_realloc_n (tokens, (allocated), sizeof (PosToken
)))
;
2143 }
2144
2145 next = &tokens[n_tokens];
2146
2147 switch (*p)
2148 {
2149 case '*':
2150 case '/':
2151 case '+':
2152 case '-': /* negative numbers aren't allowed so this is easy */
2153 case '%':
2154 case '`':
2155 next->type = POS_TOKEN_OPERATOR;
2156 next->d.o.op = op_from_string (p, &len);
2157 if (next->d.o.op != POS_OP_NONE)
2158 {
2159 ++n_tokens;
2160 p = p + (len - 1); /* -1 since we ++p later */
2161 }
2162 else
2163 {
2164 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2165 META_THEME_ERROR_FAILED,
2166 _("Coordinate expression contained unknown operator at the start of this text: \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression contained unknown operator at the start of this text: \"%s\""
))
,
2167 p);
2168
2169 goto error;
2170 }
2171 break;
2172
2173 case '(':
2174 next->type = POS_TOKEN_OPEN_PAREN;
2175 ++n_tokens;
2176 break;
2177
2178 case ')':
2179 next->type = POS_TOKEN_CLOSE_PAREN;
2180 ++n_tokens;
2181 break;
2182
2183 case ' ':
2184 case '\t':
2185 case '\n':
2186 break;
2187
2188 default:
2189 if (IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2190 {
2191 /* Assume variable */
2192 const char *start = p;
2193 while (*p && IS_VARIABLE_CHAR (*p)(((g_ascii_table[(guchar) ((*p))] & G_ASCII_ALPHA) != 0) ||
(*p) == '_')
)
2194 ++p;
2195 g_assert (p != start)do { if (p != start) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2195, ((const char*) (__func__)), "p != start"
); } while (0)
;
2196 next->type = POS_TOKEN_VARIABLE;
2197 next->d.v.name = g_strndup (start, p - start);
2198 ++n_tokens;
2199 --p; /* since we ++p again at the end of while loop */
2200 }
2201 else
2202 {
2203 /* Assume number */
2204 const char *end;
2205
2206 if (!parse_number (p, &end, next, err))
2207 goto error;
2208
2209 ++n_tokens;
2210 p = end - 1; /* -1 since we ++p again at the end of while loop */
2211 }
2212
2213 break;
2214 }
2215
2216 ++p;
2217 }
2218
2219 if (n_tokens == 0)
2220 {
2221 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2222 META_THEME_ERROR_FAILED,
2223 _("Coordinate expression was empty or not understood")((char *) g_dgettext ("marco", "Coordinate expression was empty or not understood"
))
);
2224
2225 goto error;
2226 }
2227
2228 *tokens_p = tokens;
2229 *n_tokens_p = n_tokens;
2230
2231 return TRUE(!(0));
2232
2233 error:
2234 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2234, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2235
2236 free_tokens (tokens, n_tokens);
2237 return FALSE(0);
2238}
2239
2240/**
2241 * The type of a PosExpr: either integer, double, or an operation.
2242 * \ingroup parser
2243 */
2244typedef enum
2245{
2246 POS_EXPR_INT,
2247 POS_EXPR_DOUBLE,
2248 POS_EXPR_OPERATOR
2249} PosExprType;
2250
2251/**
2252 * Type and value of an expression in a parsed sequence. We don't
2253 * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR,
2254 * the arguments of the operator will be in the array positions
2255 * immediately preceding and following this operator; they cannot
2256 * themselves be operators.
2257 *
2258 * \bug operator is char; it should really be of PosOperatorType.
2259 * \ingroup parser
2260 */
2261typedef struct
2262{
2263 PosExprType type;
2264 union
2265 {
2266 double double_val;
2267 int int_val;
2268 char operator;
2269 } d;
2270} PosExpr;
2271
2272#if 0
2273static void
2274debug_print_exprs (PosExpr *exprs,
2275 int n_exprs)
2276{
2277 int i;
2278
2279 for (i = 0; i < n_exprs; i++)
2280 {
2281 switch (exprs[i].type)
2282 {
2283 case POS_EXPR_INT:
2284 g_print (" %d", exprs[i].d.int_val);
2285 break;
2286 case POS_EXPR_DOUBLE:
2287 g_print (" %g", exprs[i].d.double_val);
2288 break;
2289 case POS_EXPR_OPERATOR:
2290 g_print (" %s", op_name (exprs[i].d.operator));
2291 break;
2292 }
2293 }
2294 g_print ("\n");
2295}
2296#endif
2297
2298static gboolean
2299do_operation (PosExpr *a,
2300 PosExpr *b,
2301 PosOperatorType op,
2302 GError **err)
2303{
2304 /* Promote types to double if required */
2305 if (a->type == POS_EXPR_DOUBLE ||
2306 b->type == POS_EXPR_DOUBLE)
2307 {
2308 if (a->type != POS_EXPR_DOUBLE)
2309 {
2310 a->type = POS_EXPR_DOUBLE;
2311 a->d.double_val = a->d.int_val;
2312 }
2313 if (b->type != POS_EXPR_DOUBLE)
2314 {
2315 b->type = POS_EXPR_DOUBLE;
2316 b->d.double_val = b->d.int_val;
2317 }
2318 }
2319
2320 g_assert (a->type == b->type)do { if (a->type == b->type) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2320, ((const char*) (__func__)), "a->type == b->type"
); } while (0)
;
2321
2322 if (a->type == POS_EXPR_INT)
2323 {
2324 switch (op)
2325 {
2326 case POS_OP_MULTIPLY:
2327 a->d.int_val = a->d.int_val * b->d.int_val;
2328 break;
2329 case POS_OP_DIVIDE:
2330 if (b->d.int_val == 0)
2331 {
2332 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2333 META_THEME_ERROR_DIVIDE_BY_ZERO,
2334 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2335 return FALSE(0);
2336 }
2337 a->d.int_val = a->d.int_val / b->d.int_val;
2338 break;
2339 case POS_OP_MOD:
2340 if (b->d.int_val == 0)
2341 {
2342 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2343 META_THEME_ERROR_DIVIDE_BY_ZERO,
2344 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2345 return FALSE(0);
2346 }
2347 a->d.int_val = a->d.int_val % b->d.int_val;
2348 break;
2349 case POS_OP_ADD:
2350 a->d.int_val = a->d.int_val + b->d.int_val;
2351 break;
2352 case POS_OP_SUBTRACT:
2353 a->d.int_val = a->d.int_val - b->d.int_val;
2354 break;
2355 case POS_OP_MAX:
2356 a->d.int_val = MAX (a->d.int_val, b->d.int_val)(((a->d.int_val) > (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2357 break;
2358 case POS_OP_MIN:
2359 a->d.int_val = MIN (a->d.int_val, b->d.int_val)(((a->d.int_val) < (b->d.int_val)) ? (a->d.int_val
) : (b->d.int_val))
;
2360 break;
2361 case POS_OP_NONE:
2362 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2362, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2363 break;
2364 }
2365 }
2366 else if (a->type == POS_EXPR_DOUBLE)
2367 {
2368 switch (op)
2369 {
2370 case POS_OP_MULTIPLY:
2371 a->d.double_val = a->d.double_val * b->d.double_val;
2372 break;
2373 case POS_OP_DIVIDE:
2374 if (b->d.double_val == 0.0)
2375 {
2376 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2377 META_THEME_ERROR_DIVIDE_BY_ZERO,
2378 _("Coordinate expression results in division by zero")((char *) g_dgettext ("marco", "Coordinate expression results in division by zero"
))
);
2379 return FALSE(0);
2380 }
2381 a->d.double_val = a->d.double_val / b->d.double_val;
2382 break;
2383 case POS_OP_MOD:
2384 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2385 META_THEME_ERROR_MOD_ON_FLOAT,
2386 _("Coordinate expression tries to use mod operator on a floating-point number")((char *) g_dgettext ("marco", "Coordinate expression tries to use mod operator on a floating-point number"
))
);
2387 return FALSE(0);
2388 case POS_OP_ADD:
2389 a->d.double_val = a->d.double_val + b->d.double_val;
2390 break;
2391 case POS_OP_SUBTRACT:
2392 a->d.double_val = a->d.double_val - b->d.double_val;
2393 break;
2394 case POS_OP_MAX:
2395 a->d.double_val = MAX (a->d.double_val, b->d.double_val)(((a->d.double_val) > (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2396 break;
2397 case POS_OP_MIN:
2398 a->d.double_val = MIN (a->d.double_val, b->d.double_val)(((a->d.double_val) < (b->d.double_val)) ? (a->d.
double_val) : (b->d.double_val))
;
2399 break;
2400 case POS_OP_NONE:
2401 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2401, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2402 break;
2403 }
2404 }
2405 else
2406 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2406, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2407
2408 return TRUE(!(0));
2409}
2410
2411static gboolean
2412do_operations (PosExpr *exprs,
2413 int *n_exprs,
2414 int precedence,
2415 GError **err)
2416{
2417 int i;
2418
2419#if 0
2420 g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs);
2421 debug_print_exprs (exprs, *n_exprs);
2422#endif
2423
2424 i = 1;
2425 while (i < *n_exprs)
2426 {
2427 gboolean compress;
2428
2429 /* exprs[i-1] first operand
2430 * exprs[i] operator
2431 * exprs[i+1] second operand
2432 *
2433 * we replace first operand with result of mul/div/mod,
2434 * or skip over operator and second operand if we have
2435 * an add/subtract
2436 */
2437
2438 if (exprs[i-1].type == POS_EXPR_OPERATOR)
2439 {
2440 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2441 META_THEME_ERROR_FAILED,
2442 _("Coordinate expression has an operator \"%s\" where an operand was expected")((char *) g_dgettext ("marco", "Coordinate expression has an operator \"%s\" where an operand was expected"
))
,
2443 op_name (exprs[i-1].d.operator));
2444 return FALSE(0);
2445 }
2446
2447 if (exprs[i].type != POS_EXPR_OPERATOR)
2448 {
2449 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2450 META_THEME_ERROR_FAILED,
2451 _("Coordinate expression had an operand where an operator was expected")((char *) g_dgettext ("marco", "Coordinate expression had an operand where an operator was expected"
))
);
2452 return FALSE(0);
2453 }
2454
2455 if (i == (*n_exprs - 1))
2456 {
2457 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2458 META_THEME_ERROR_FAILED,
2459 _("Coordinate expression ended with an operator instead of an operand")((char *) g_dgettext ("marco", "Coordinate expression ended with an operator instead of an operand"
))
);
2460 return FALSE(0);
2461 }
2462
2463 g_assert ((i+1) < *n_exprs)do { if ((i+1) < *n_exprs) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2463, ((const char*) (__func__)), "(i+1) < *n_exprs"
); } while (0)
;
2464
2465 if (exprs[i+1].type == POS_EXPR_OPERATOR)
2466 {
2467 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2468 META_THEME_ERROR_FAILED,
2469 _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between")((char *) g_dgettext ("marco", "Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"
))
,
2470 exprs[i+1].d.operator,
2471 exprs[i].d.operator);
2472 return FALSE(0);
2473 }
2474
2475 compress = FALSE(0);
2476
2477 switch (precedence)
2478 {
2479 case 2:
2480 switch (exprs[i].d.operator)
2481 {
2482 case POS_OP_DIVIDE:
2483 case POS_OP_MOD:
2484 case POS_OP_MULTIPLY:
2485 compress = TRUE(!(0));
2486 if (!do_operation (&exprs[i-1], &exprs[i+1],
2487 exprs[i].d.operator,
2488 err))
2489 return FALSE(0);
2490 break;
2491 }
2492 break;
2493 case 1:
2494 switch (exprs[i].d.operator)
2495 {
2496 case POS_OP_ADD:
2497 case POS_OP_SUBTRACT:
2498 compress = TRUE(!(0));
2499 if (!do_operation (&exprs[i-1], &exprs[i+1],
2500 exprs[i].d.operator,
2501 err))
2502 return FALSE(0);
2503 break;
2504 }
2505 break;
2506 /* I have no rationale at all for making these low-precedence */
2507 case 0:
2508 switch (exprs[i].d.operator)
2509 {
2510 case POS_OP_MAX:
2511 case POS_OP_MIN:
2512 compress = TRUE(!(0));
2513 if (!do_operation (&exprs[i-1], &exprs[i+1],
2514 exprs[i].d.operator,
2515 err))
2516 return FALSE(0);
2517 break;
2518 }
2519 break;
2520 }
2521
2522 if (compress)
2523 {
2524 /* exprs[i-1] first operand (now result)
2525 * exprs[i] operator
2526 * exprs[i+1] second operand
2527 * exprs[i+2] new operator
2528 *
2529 * we move new operator just after first operand
2530 */
2531 if ((i+2) < *n_exprs)
2532 {
2533 memmove (&exprs[i], &exprs[i+2],
2534 sizeof (PosExpr) * (*n_exprs - i - 2));
2535 }
2536
2537 *n_exprs -= 2;
2538 }
2539 else
2540 {
2541 /* Skip operator and next operand */
2542 i += 2;
2543 }
2544 }
2545
2546 return TRUE(!(0));
2547}
2548
2549/**
2550 * There is a predefined set of variables which can appear in an expression.
2551 * Here we take a token representing a variable, and return the current value
2552 * of that variable in a particular environment.
2553 * (The value is always an integer.)
2554 *
2555 * There are supposedly some circumstances in which this function can be
2556 * called from outside Marco, in which case env->theme will be NULL, and
2557 * therefore we can't use it to find out quark values, so we do the comparison
2558 * using strcmp, which is slower.
2559 *
2560 * \param t The token representing a variable
2561 * \param[out] result The value of that variable; not set if the token did
2562 * not represent a known variable
2563 * \param env The environment within which t should be evaluated
2564 * \param[out] err set to the problem if there was a problem
2565 *
2566 * \return true if we found the variable asked for, false if we didn't
2567 *
2568 * \bug shouldn't t be const?
2569 * \bug we should perhaps consider some sort of lookup arrangement into an
2570 * array; also, the duplication of code is unlovely; perhaps using glib
2571 * string hashes instead of quarks would fix both problems?
2572 * \ingroup parser
2573 */
2574static gboolean
2575pos_eval_get_variable (PosToken *t,
2576 int *result,
2577 const MetaPositionExprEnv *env,
2578 GError **err)
2579{
2580 if (env->theme)
2581 {
2582 if (t->d.v.name_quark == env->theme->quark_width)
2583 *result = env->rect.width;
2584 else if (t->d.v.name_quark == env->theme->quark_height)
2585 *result = env->rect.height;
2586 else if (env->object_width >= 0 &&
2587 t->d.v.name_quark == env->theme->quark_object_width)
2588 *result = env->object_width;
2589 else if (env->object_height >= 0 &&
2590 t->d.v.name_quark == env->theme->quark_object_height)
2591 *result = env->object_height;
2592 else if (t->d.v.name_quark == env->theme->quark_left_width)
2593 *result = env->left_width;
2594 else if (t->d.v.name_quark == env->theme->quark_right_width)
2595 *result = env->right_width;
2596 else if (t->d.v.name_quark == env->theme->quark_top_height)
2597 *result = env->top_height;
2598 else if (t->d.v.name_quark == env->theme->quark_bottom_height)
2599 *result = env->bottom_height;
2600 else if (t->d.v.name_quark == env->theme->quark_mini_icon_width)
2601 *result = env->mini_icon_width;
2602 else if (t->d.v.name_quark == env->theme->quark_mini_icon_height)
2603 *result = env->mini_icon_height;
2604 else if (t->d.v.name_quark == env->theme->quark_icon_width)
2605 *result = env->icon_width;
2606 else if (t->d.v.name_quark == env->theme->quark_icon_height)
2607 *result = env->icon_height;
2608 else if (t->d.v.name_quark == env->theme->quark_title_width)
2609 *result = env->title_width;
2610 else if (t->d.v.name_quark == env->theme->quark_title_height)
2611 *result = env->title_height;
2612 else if (t->d.v.name_quark == env->theme->quark_frame_x_center)
2613 *result = env->frame_x_center;
2614 else if (t->d.v.name_quark == env->theme->quark_frame_y_center)
2615 *result = env->frame_y_center;
2616 else
2617 {
2618 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2619 META_THEME_ERROR_UNKNOWN_VARIABLE,
2620 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2621 t->d.v.name);
2622 return FALSE(0);
2623 }
2624 }
2625 else
2626 {
2627 if (strcmp (t->d.v.name, "width") == 0)
2628 *result = env->rect.width;
2629 else if (strcmp (t->d.v.name, "height") == 0)
2630 *result = env->rect.height;
2631 else if (env->object_width >= 0 &&
2632 strcmp (t->d.v.name, "object_width") == 0)
2633 *result = env->object_width;
2634 else if (env->object_height >= 0 &&
2635 strcmp (t->d.v.name, "object_height") == 0)
2636 *result = env->object_height;
2637 else if (strcmp (t->d.v.name, "left_width") == 0)
2638 *result = env->left_width;
2639 else if (strcmp (t->d.v.name, "right_width") == 0)
2640 *result = env->right_width;
2641 else if (strcmp (t->d.v.name, "top_height") == 0)
2642 *result = env->top_height;
2643 else if (strcmp (t->d.v.name, "bottom_height") == 0)
2644 *result = env->bottom_height;
2645 else if (strcmp (t->d.v.name, "mini_icon_width") == 0)
2646 *result = env->mini_icon_width;
2647 else if (strcmp (t->d.v.name, "mini_icon_height") == 0)
2648 *result = env->mini_icon_height;
2649 else if (strcmp (t->d.v.name, "icon_width") == 0)
2650 *result = env->icon_width;
2651 else if (strcmp (t->d.v.name, "icon_height") == 0)
2652 *result = env->icon_height;
2653 else if (strcmp (t->d.v.name, "title_width") == 0)
2654 *result = env->title_width;
2655 else if (strcmp (t->d.v.name, "title_height") == 0)
2656 *result = env->title_height;
2657 else if (strcmp (t->d.v.name, "frame_x_center") == 0)
2658 *result = env->frame_x_center;
2659 else if (strcmp (t->d.v.name, "frame_y_center") == 0)
2660 *result = env->frame_y_center;
2661 else
2662 {
2663 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2664 META_THEME_ERROR_UNKNOWN_VARIABLE,
2665 _("Coordinate expression had unknown variable or constant \"%s\"")((char *) g_dgettext ("marco", "Coordinate expression had unknown variable or constant \"%s\""
))
,
2666 t->d.v.name);
2667 return FALSE(0);
2668 }
2669 }
2670
2671 return TRUE(!(0));
2672}
2673
2674/**
2675 * Evaluates a sequence of tokens within a particular environment context,
2676 * and returns the current value. May recur if parantheses are found.
2677 *
2678 * \param tokens A list of tokens to evaluate.
2679 * \param n_tokens How many tokens are in the list.
2680 * \param env The environment context in which to evaluate the expression.
2681 * \param[out] result The current value of the expression
2682 *
2683 * \bug Yes, we really do reparse the expression every time it's evaluated.
2684 * We should keep the parse tree around all the time and just
2685 * run the new values through it.
2686 * \ingroup parser
2687 */
2688static gboolean
2689pos_eval_helper (PosToken *tokens,
2690 int n_tokens,
2691 const MetaPositionExprEnv *env,
2692 PosExpr *result,
2693 GError **err)
2694{
2695 /* Lazy-ass hardcoded limit on number of terms in expression */
2696#define MAX_EXPRS32 32
2697 int paren_level;
2698 int first_paren;
2699 int i;
2700 PosExpr exprs[MAX_EXPRS32];
2701 int n_exprs;
2702 int precedence;
2703
2704 /* Our first goal is to get a list of PosExpr, essentially
2705 * substituting variables and handling parentheses.
2706 */
2707
2708 first_paren = 0;
2709 paren_level = 0;
2710 n_exprs = 0;
2711 for (i = 0; i < n_tokens; i++)
2712 {
2713 PosToken *t = &tokens[i];
2714
2715 if (n_exprs >= MAX_EXPRS32)
2716 {
2717 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2718 META_THEME_ERROR_FAILED,
2719 _("Coordinate expression parser overflowed its buffer.")((char *) g_dgettext ("marco", "Coordinate expression parser overflowed its buffer."
))
);
2720 return FALSE(0);
2721 }
2722
2723 if (paren_level == 0)
2724 {
2725 switch (t->type)
2726 {
2727 case POS_TOKEN_INT:
2728 exprs[n_exprs].type = POS_EXPR_INT;
2729 exprs[n_exprs].d.int_val = t->d.i.val;
2730 ++n_exprs;
2731 break;
2732
2733 case POS_TOKEN_DOUBLE:
2734 exprs[n_exprs].type = POS_EXPR_DOUBLE;
2735 exprs[n_exprs].d.double_val = t->d.d.val;
2736 ++n_exprs;
2737 break;
2738
2739 case POS_TOKEN_OPEN_PAREN:
2740 ++paren_level;
2741 if (paren_level == 1)
2742 first_paren = i;
2743 break;
2744
2745 case POS_TOKEN_CLOSE_PAREN:
2746 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2747 META_THEME_ERROR_BAD_PARENS,
2748 _("Coordinate expression had a close parenthesis with no open parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had a close parenthesis with no open parenthesis"
))
);
2749 return FALSE(0);
2750
2751 case POS_TOKEN_VARIABLE:
2752 exprs[n_exprs].type = POS_EXPR_INT;
2753
2754 /* FIXME we should just dump all this crap
2755 * in a hash, maybe keep width/height out
2756 * for optimization purposes
2757 */
2758 if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err))
2759 return FALSE(0);
2760
2761 ++n_exprs;
2762 break;
2763
2764 case POS_TOKEN_OPERATOR:
2765 exprs[n_exprs].type = POS_EXPR_OPERATOR;
2766 exprs[n_exprs].d.operator = t->d.o.op;
2767 ++n_exprs;
2768 break;
2769 }
2770 }
2771 else
2772 {
2773 g_assert (paren_level > 0)do { if (paren_level > 0) ; else g_assertion_message_expr (
"marco", "ui/theme.c", 2773, ((const char*) (__func__)), "paren_level > 0"
); } while (0)
;
2774
2775 switch (t->type)
2776 {
2777 case POS_TOKEN_INT:
2778 case POS_TOKEN_DOUBLE:
2779 case POS_TOKEN_VARIABLE:
2780 case POS_TOKEN_OPERATOR:
2781 break;
2782
2783 case POS_TOKEN_OPEN_PAREN:
2784 ++paren_level;
2785 break;
2786
2787 case POS_TOKEN_CLOSE_PAREN:
2788 if (paren_level == 1)
2789 {
2790 /* We closed a toplevel paren group, so recurse */
2791 if (!pos_eval_helper (&tokens[first_paren+1],
2792 i - first_paren - 1,
2793 env,
2794 &exprs[n_exprs],
2795 err))
2796 return FALSE(0);
2797
2798 ++n_exprs;
2799 }
2800
2801 --paren_level;
2802 break;
2803
2804 }
2805 }
2806 }
2807
2808 if (paren_level > 0)
2809 {
2810 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2811 META_THEME_ERROR_BAD_PARENS,
2812 _("Coordinate expression had an open parenthesis with no close parenthesis")((char *) g_dgettext ("marco", "Coordinate expression had an open parenthesis with no close parenthesis"
))
);
2813 return FALSE(0);
2814 }
2815
2816 /* Now we have no parens and no vars; so we just do all the multiplies
2817 * and divides, then all the add and subtract.
2818 */
2819 if (n_exprs == 0)
2820 {
2821 g_set_error (err, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
2822 META_THEME_ERROR_FAILED,
2823 _("Coordinate expression doesn't seem to have any operators or operands")((char *) g_dgettext ("marco", "Coordinate expression doesn't seem to have any operators or operands"
))
);
2824 return FALSE(0);
2825 }
2826
2827 /* precedence 1 ops */
2828 precedence = 2;
2829 while (precedence >= 0)
2830 {
2831 if (!do_operations (exprs, &n_exprs, precedence, err))
2832 return FALSE(0);
2833 --precedence;
2834 }
2835
2836 g_assert (n_exprs == 1)do { if (n_exprs == 1) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 2836, ((const char*) (__func__)), "n_exprs == 1"
); } while (0)
;
2837
2838 *result = *exprs;
2839
2840 return TRUE(!(0));
2841}
2842
2843/*
2844 * expr = int | double | expr * expr | expr / expr |
2845 * expr + expr | expr - expr | (expr)
2846 *
2847 * so very not worth fooling with bison, yet so very painful by hand.
2848 */
2849/**
2850 * Evaluates an expression.
2851 *
2852 * \param spec The expression to evaluate.
2853 * \param env The environment context to evaluate the expression in.
2854 * \param[out] val_p The integer value of the expression; if the expression
2855 * is of type float, this will be rounded. If we return
2856 * FALSE because the expression is invalid, this will be
2857 * zero.
2858 * \param[out] err The error, if anything went wrong.
2859 *
2860 * \return True if we evaluated the expression successfully; false otherwise.
2861 *
2862 * \bug Shouldn't spec be const?
2863 * \ingroup parser
2864 */
2865static gboolean
2866pos_eval (MetaDrawSpec *spec,
2867 const MetaPositionExprEnv *env,
2868 int *val_p,
2869 GError **err)
2870{
2871 PosExpr expr;
2872
2873 *val_p = 0;
2874
2875 if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err))
2876 {
2877 switch (expr.type)
2878 {
2879 case POS_EXPR_INT:
2880 *val_p = expr.d.int_val;
2881 break;
2882 case POS_EXPR_DOUBLE:
2883 *val_p = (int) expr.d.double_val;
2884 break;
2885 case POS_EXPR_OPERATOR:
2886 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 2886, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
2887 break;
2888 }
2889 return TRUE(!(0));
2890 }
2891 else
2892 {
2893 return FALSE(0);
2894 }
2895}
2896
2897/* We always return both X and Y, but only one will be meaningful in
2898 * most contexts.
2899 */
2900
2901gboolean
2902meta_parse_position_expression (MetaDrawSpec *spec,
2903 const MetaPositionExprEnv *env,
2904 int *x_return,
2905 int *y_return,
2906 GError **err)
2907{
2908 /* All positions are in a coordinate system with x, y at the origin.
2909 * The expression can have -, +, *, / as operators, floating point
2910 * or integer constants, and the variables "width" and "height" and
2911 * optionally "object_width" and object_height". Negative numbers
2912 * aren't allowed.
2913 */
2914 int val;
2915
2916 if (spec->constant)
2917 val = spec->value;
2918 else
2919 {
2920 if (!pos_eval (spec, env, &spec->value, err))
2921 {
2922 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2922, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2923 return FALSE(0);
2924 }
2925
2926 val = spec->value;
2927 }
2928
2929 if (x_return)
2930 *x_return = env->rect.x + val;
2931 if (y_return)
2932 *y_return = env->rect.y + val;
2933
2934 return TRUE(!(0));
2935}
2936
2937gboolean
2938meta_parse_size_expression (MetaDrawSpec *spec,
2939 const MetaPositionExprEnv *env,
2940 int *val_return,
2941 GError **err)
2942{
2943 int val;
2944
2945 if (spec->constant)
2946 val = spec->value;
2947 else
2948 {
2949 if (!pos_eval (spec, env, &spec->value, err))
2950 {
2951 g_assert (err == NULL || *err != NULL)do { if (err == ((void*)0) || *err != ((void*)0)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 2951, ((const char*) (__func__)), "err == NULL || *err != NULL"
); } while (0)
;
2952 return FALSE(0);
2953 }
2954
2955 val = spec->value;
2956 }
2957
2958 if (val_return)
2959 *val_return = MAX (val, 1)(((val) > (1)) ? (val) : (1)); /* require that sizes be at least 1x1 */
2960
2961 return TRUE(!(0));
2962}
2963
2964/* To do this we tokenize, replace variable tokens
2965 * that are constants, then reassemble. The purpose
2966 * here is to optimize expressions so we don't do hash
2967 * lookups to eval them. Obviously it's a tradeoff that
2968 * slows down theme load times.
2969 */
2970gboolean
2971meta_theme_replace_constants (MetaTheme *theme,
2972 PosToken *tokens,
2973 int n_tokens,
2974 GError **err)
2975{
2976 int i;
2977 double dval;
2978 int ival;
2979 gboolean is_constant = TRUE(!(0));
2980
2981 /* Loop through tokenized string looking for variables to replace */
2982 for (i = 0; i < n_tokens; i++)
2983 {
2984 PosToken *t = &tokens[i];
2985
2986 if (t->type == POS_TOKEN_VARIABLE)
2987 {
2988 if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival))
2989 {
2990 g_free (t->d.v.name);
2991 t->type = POS_TOKEN_INT;
2992 t->d.i.val = ival;
2993 }
2994 else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval))
2995 {
2996 g_free (t->d.v.name);
2997 t->type = POS_TOKEN_DOUBLE;
2998 t->d.d.val = dval;
2999 }
3000 else
3001 {
3002 /* If we've found a variable that cannot be replaced then the
3003 expression is not a constant expression and we want to
3004 replace it with a GQuark */
3005
3006 t->d.v.name_quark = g_quark_from_string (t->d.v.name);
3007 is_constant = FALSE(0);
3008 }
3009 }
3010 }
3011
3012 return is_constant;
3013}
3014
3015static int
3016parse_x_position_unchecked (MetaDrawSpec *spec,
3017 const MetaPositionExprEnv *env)
3018{
3019 int retval;
3020 GError *error;
3021
3022 retval = 0;
3023 error = NULL((void*)0);
3024 if (!meta_parse_position_expression (spec, env, &retval, NULL((void*)0), &error))
3025 {
3026 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3027 error->message);
3028
3029 g_error_free (error);
3030 }
3031
3032 return retval;
3033}
3034
3035static int
3036parse_y_position_unchecked (MetaDrawSpec *spec,
3037 const MetaPositionExprEnv *env)
3038{
3039 int retval;
3040 GError *error;
3041
3042 retval = 0;
3043 error = NULL((void*)0);
3044 if (!meta_parse_position_expression (spec, env, NULL((void*)0), &retval, &error))
3045 {
3046 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3047 error->message);
3048
3049 g_error_free (error);
3050 }
3051
3052 return retval;
3053}
3054
3055static int
3056parse_size_unchecked (MetaDrawSpec *spec,
3057 MetaPositionExprEnv *env)
3058{
3059 int retval;
3060 GError *error;
3061
3062 retval = 0;
3063 error = NULL((void*)0);
3064 if (!meta_parse_size_expression (spec, env, &retval, &error))
3065 {
3066 meta_warning (_("Theme contained an expression that resulted in an error: %s\n")((char *) g_dgettext ("marco", "Theme contained an expression that resulted in an error: %s\n"
))
,
3067 error->message);
3068
3069 g_error_free (error);
3070 }
3071
3072 return retval;
3073}
3074
3075void
3076meta_draw_spec_free (MetaDrawSpec *spec)
3077{
3078 if (!spec) return;
3079 free_tokens (spec->tokens, spec->n_tokens);
3080 g_slice_free (MetaDrawSpec, spec)do { if (1) g_slice_free1 (sizeof (MetaDrawSpec), (spec)); else
(void) ((MetaDrawSpec*) 0 == (spec)); } while (0)
;
3081}
3082
3083MetaDrawSpec *
3084meta_draw_spec_new (MetaTheme *theme,
3085 const char *expr,
3086 GError **error)
3087{
3088 MetaDrawSpec *spec;
3089
3090 spec = g_slice_new0 (MetaDrawSpec)((MetaDrawSpec*) g_slice_alloc0 (sizeof (MetaDrawSpec)));
3091
3092 pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL((void*)0));
3093
3094 spec->constant = meta_theme_replace_constants (theme, spec->tokens,
3095 spec->n_tokens, NULL((void*)0));
3096 if (spec->constant)
3097 {
3098 if (!pos_eval (spec, NULL((void*)0), &spec->value, error))
3099 {
3100 meta_draw_spec_free (spec);
3101 return NULL((void*)0);
3102 }
3103 }
3104
3105 return spec;
3106}
3107
3108MetaDrawOp*
3109meta_draw_op_new (MetaDrawType type)
3110{
3111 MetaDrawOp *op;
3112 MetaDrawOp dummy;
3113 int size;
3114
3115 size = G_STRUCT_OFFSET (MetaDrawOp, data)((glong) __builtin_offsetof(MetaDrawOp, data));
3116
3117 switch (type)
3118 {
3119 case META_DRAW_LINE:
3120 size += sizeof (dummy.data.line);
3121 break;
3122
3123 case META_DRAW_RECTANGLE:
3124 size += sizeof (dummy.data.rectangle);
3125 break;
3126
3127 case META_DRAW_ARC:
3128 size += sizeof (dummy.data.arc);
3129 break;
3130
3131 case META_DRAW_CLIP:
3132 size += sizeof (dummy.data.clip);
3133 break;
3134
3135 case META_DRAW_TINT:
3136 size += sizeof (dummy.data.tint);
3137 break;
3138
3139 case META_DRAW_GRADIENT:
3140 size += sizeof (dummy.data.gradient);
3141 break;
3142
3143 case META_DRAW_IMAGE:
3144 size += sizeof (dummy.data.image);
3145 break;
3146
3147 case META_DRAW_GTK_ARROW:
3148 size += sizeof (dummy.data.gtk_arrow);
3149 break;
3150
3151 case META_DRAW_GTK_BOX:
3152 size += sizeof (dummy.data.gtk_box);
3153 break;
3154
3155 case META_DRAW_GTK_VLINE:
3156 size += sizeof (dummy.data.gtk_vline);
3157 break;
3158
3159 case META_DRAW_ICON:
3160 size += sizeof (dummy.data.icon);
3161 break;
3162
3163 case META_DRAW_TITLE:
3164 size += sizeof (dummy.data.title);
3165 break;
3166 case META_DRAW_OP_LIST:
3167 size += sizeof (dummy.data.op_list);
3168 break;
3169 case META_DRAW_TILE:
3170 size += sizeof (dummy.data.tile);
3171 break;
3172 }
3173
3174 op = g_malloc0 (size);
3175
3176 op->type = type;
3177
3178 return op;
3179}
3180
3181void
3182meta_draw_op_free (MetaDrawOp *op)
3183{
3184 g_return_if_fail (op != NULL)do { if ((op != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op != NULL"); return;
} } while (0)
;
3185
3186 switch (op->type)
3187 {
3188 case META_DRAW_LINE:
3189 if (op->data.line.color_spec)
3190 meta_color_spec_free (op->data.line.color_spec);
3191
3192 meta_draw_spec_free (op->data.line.x1);
3193 meta_draw_spec_free (op->data.line.y1);
3194 meta_draw_spec_free (op->data.line.x2);
3195 meta_draw_spec_free (op->data.line.y2);
3196 break;
3197
3198 case META_DRAW_RECTANGLE:
3199 if (op->data.rectangle.color_spec)
3200 g_free (op->data.rectangle.color_spec);
3201
3202 meta_draw_spec_free (op->data.rectangle.x);
3203 meta_draw_spec_free (op->data.rectangle.y);
3204 meta_draw_spec_free (op->data.rectangle.width);
3205 meta_draw_spec_free (op->data.rectangle.height);
3206 break;
3207
3208 case META_DRAW_ARC:
3209 if (op->data.arc.color_spec)
3210 g_free (op->data.arc.color_spec);
3211
3212 meta_draw_spec_free (op->data.arc.x);
3213 meta_draw_spec_free (op->data.arc.y);
3214 meta_draw_spec_free (op->data.arc.width);
3215 meta_draw_spec_free (op->data.arc.height);
3216 break;
3217
3218 case META_DRAW_CLIP:
3219 meta_draw_spec_free (op->data.clip.x);
3220 meta_draw_spec_free (op->data.clip.y);
3221 meta_draw_spec_free (op->data.clip.width);
3222 meta_draw_spec_free (op->data.clip.height);
3223 break;
3224
3225 case META_DRAW_TINT:
3226 if (op->data.tint.color_spec)
3227 meta_color_spec_free (op->data.tint.color_spec);
3228
3229 if (op->data.tint.alpha_spec)
3230 meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
3231
3232 meta_draw_spec_free (op->data.tint.x);
3233 meta_draw_spec_free (op->data.tint.y);
3234 meta_draw_spec_free (op->data.tint.width);
3235 meta_draw_spec_free (op->data.tint.height);
3236 break;
3237
3238 case META_DRAW_GRADIENT:
3239 if (op->data.gradient.gradient_spec)
3240 meta_gradient_spec_free (op->data.gradient.gradient_spec);
3241
3242 if (op->data.gradient.alpha_spec)
3243 meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
3244
3245 meta_draw_spec_free (op->data.gradient.x);
3246 meta_draw_spec_free (op->data.gradient.y);
3247 meta_draw_spec_free (op->data.gradient.width);
3248 meta_draw_spec_free (op->data.gradient.height);
3249 break;
3250
3251 case META_DRAW_IMAGE:
3252 if (op->data.image.alpha_spec)
3253 meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
3254
3255 if (op->data.image.pixbuf)
3256 g_object_unref (G_OBJECT (op->data.image.pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.pixbuf)), (((GType) ((20) << (2)
)))))))
);
3257
3258 if (op->data.image.colorize_spec)
3259 meta_color_spec_free (op->data.image.colorize_spec);
3260
3261 if (op->data.image.colorize_cache_pixbuf)
3262 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3263
3264 meta_draw_spec_free (op->data.image.x);
3265 meta_draw_spec_free (op->data.image.y);
3266 meta_draw_spec_free (op->data.image.width);
3267 meta_draw_spec_free (op->data.image.height);
3268 break;
3269
3270 case META_DRAW_GTK_ARROW:
3271 meta_draw_spec_free (op->data.gtk_arrow.x);
3272 meta_draw_spec_free (op->data.gtk_arrow.y);
3273 meta_draw_spec_free (op->data.gtk_arrow.width);
3274 meta_draw_spec_free (op->data.gtk_arrow.height);
3275 break;
3276
3277 case META_DRAW_GTK_BOX:
3278 meta_draw_spec_free (op->data.gtk_box.x);
3279 meta_draw_spec_free (op->data.gtk_box.y);
3280 meta_draw_spec_free (op->data.gtk_box.width);
3281 meta_draw_spec_free (op->data.gtk_box.height);
3282 break;
3283
3284 case META_DRAW_GTK_VLINE:
3285 meta_draw_spec_free (op->data.gtk_vline.x);
3286 meta_draw_spec_free (op->data.gtk_vline.y1);
3287 meta_draw_spec_free (op->data.gtk_vline.y2);
3288 break;
3289
3290 case META_DRAW_ICON:
3291 if (op->data.icon.alpha_spec)
3292 meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
3293
3294 meta_draw_spec_free (op->data.icon.x);
3295 meta_draw_spec_free (op->data.icon.y);
3296 meta_draw_spec_free (op->data.icon.width);
3297 meta_draw_spec_free (op->data.icon.height);
3298 break;
3299
3300 case META_DRAW_TITLE:
3301 if (op->data.title.color_spec)
3302 meta_color_spec_free (op->data.title.color_spec);
3303
3304 meta_draw_spec_free (op->data.title.x);
3305 meta_draw_spec_free (op->data.title.y);
3306 if (op->data.title.ellipsize_width)
3307 meta_draw_spec_free (op->data.title.ellipsize_width);
3308 break;
3309
3310 case META_DRAW_OP_LIST:
3311 if (op->data.op_list.op_list)
3312 meta_draw_op_list_unref (op->data.op_list.op_list);
3313
3314 meta_draw_spec_free (op->data.op_list.x);
3315 meta_draw_spec_free (op->data.op_list.y);
3316 meta_draw_spec_free (op->data.op_list.width);
3317 meta_draw_spec_free (op->data.op_list.height);
3318 break;
3319
3320 case META_DRAW_TILE:
3321 if (op->data.tile.op_list)
3322 meta_draw_op_list_unref (op->data.tile.op_list);
3323
3324 meta_draw_spec_free (op->data.tile.x);
3325 meta_draw_spec_free (op->data.tile.y);
3326 meta_draw_spec_free (op->data.tile.width);
3327 meta_draw_spec_free (op->data.tile.height);
3328 meta_draw_spec_free (op->data.tile.tile_xoffset);
3329 meta_draw_spec_free (op->data.tile.tile_yoffset);
3330 meta_draw_spec_free (op->data.tile.tile_width);
3331 meta_draw_spec_free (op->data.tile.tile_height);
3332 break;
3333 }
3334
3335 g_free (op);
3336}
3337
3338static GdkPixbuf*
3339apply_alpha (GdkPixbuf *pixbuf,
3340 MetaAlphaGradientSpec *spec,
3341 gboolean force_copy)
3342{
3343 GdkPixbuf *new_pixbuf;
3344 gboolean needs_alpha;
3345
3346 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pixbuf)); GType __t = ((gdk_pixbuf_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("marco", ((const char*) (__func__
)), "GDK_IS_PIXBUF (pixbuf)"); return (((void*)0)); } } while
(0)
;
3347
3348 needs_alpha = spec && (spec->n_alphas > 1 ||
3349 spec->alphas[0] != 0xff);
3350
3351 if (!needs_alpha)
3352 return pixbuf;
3353
3354 if (!gdk_pixbuf_get_has_alpha (pixbuf))
3355 {
3356 new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE(0), 0, 0, 0);
3357 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3358 pixbuf = new_pixbuf;
3359 }
3360 else if (force_copy)
3361 {
3362 new_pixbuf = gdk_pixbuf_copy (pixbuf);
3363 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
3364 pixbuf = new_pixbuf;
3365 }
3366
3367 g_assert (gdk_pixbuf_get_has_alpha (pixbuf))do { if (gdk_pixbuf_get_has_alpha (pixbuf)) ; else g_assertion_message_expr
("marco", "ui/theme.c", 3367, ((const char*) (__func__)), "gdk_pixbuf_get_has_alpha (pixbuf)"
); } while (0)
;
3368
3369 meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
3370
3371 return pixbuf;
3372}
3373
3374static GdkPixbuf*
3375pixbuf_tile (GdkPixbuf *tile,
3376 int width,
3377 int height)
3378{
3379 GdkPixbuf *pixbuf;
3380 int tile_width;
3381 int tile_height;
3382 int i, j;
3383
3384 tile_width = gdk_pixbuf_get_width (tile);
3385 tile_height = gdk_pixbuf_get_height (tile);
3386
3387 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3388 gdk_pixbuf_get_has_alpha (tile),
3389 8, width, height);
3390
3391 i = 0;
3392 while (i < width)
3393 {
3394 j = 0;
3395 while (j < height)
3396 {
3397 int w, h;
3398
3399 w = MIN (tile_width, width - i)(((tile_width) < (width - i)) ? (tile_width) : (width - i)
)
;
3400 h = MIN (tile_height, height - j)(((tile_height) < (height - j)) ? (tile_height) : (height -
j))
;
3401
3402 gdk_pixbuf_copy_area (tile,
3403 0, 0,
3404 w, h,
3405 pixbuf,
3406 i, j);
3407
3408 j += tile_height;
3409 }
3410
3411 i += tile_width;
3412 }
3413
3414 return pixbuf;
3415}
3416
3417static GdkPixbuf *
3418replicate_rows (GdkPixbuf *src,
3419 int src_x,
3420 int src_y,
3421 int width,
3422 int height)
3423{
3424 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3425 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3426 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3427 * n_channels);
3428 unsigned char *dest_pixels;
3429 GdkPixbuf *result;
3430 unsigned int dest_rowstride;
3431 int i;
3432
3433 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3434 width, height);
3435 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3436 dest_pixels = gdk_pixbuf_get_pixels (result);
3437
3438 for (i = 0; i < height; i++)
3439 memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
3440
3441 return result;
3442}
3443
3444static GdkPixbuf *
3445replicate_cols (GdkPixbuf *src,
3446 int src_x,
3447 int src_y,
3448 int width,
3449 int height)
3450{
3451 unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
3452 unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
3453 unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
3454 * n_channels);
3455 unsigned char *dest_pixels;
3456 GdkPixbuf *result;
3457 unsigned int dest_rowstride;
3458 int i, j;
3459
3460 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
3461 width, height);
3462 dest_rowstride = gdk_pixbuf_get_rowstride (result);
3463 dest_pixels = gdk_pixbuf_get_pixels (result);
3464
3465 for (i = 0; i < height; i++)
3466 {
3467 unsigned char *p = dest_pixels + dest_rowstride * i;
3468 unsigned char *q = pixels + src_rowstride * i;
3469
3470 unsigned char r = *(q++);
3471 unsigned char g = *(q++);
3472 unsigned char b = *(q++);
3473
3474 if (n_channels == 4)
3475 {
3476 unsigned char a;
3477
3478 a = *(q++);
3479
3480 for (j = 0; j < width; j++)
3481 {
3482 *(p++) = r;
3483 *(p++) = g;
3484 *(p++) = b;
3485 *(p++) = a;
3486 }
3487 }
3488 else
3489 {
3490 for (j = 0; j < width; j++)
3491 {
3492 *(p++) = r;
3493 *(p++) = g;
3494 *(p++) = b;
3495 }
3496 }
3497 }
3498
3499 return result;
3500}
3501
3502static GdkPixbuf*
3503scale_and_alpha_pixbuf (GdkPixbuf *src,
3504 MetaAlphaGradientSpec *alpha_spec,
3505 MetaImageFillType fill_type,
3506 int width,
3507 int height,
3508 gboolean vertical_stripes,
3509 gboolean horizontal_stripes)
3510{
3511 GdkPixbuf *pixbuf;
3512 GdkPixbuf *temp_pixbuf;
3513
3514 pixbuf = NULL((void*)0);
3515
3516 pixbuf = src;
3517
3518 if (gdk_pixbuf_get_width (pixbuf) == width &&
3519 gdk_pixbuf_get_height (pixbuf) == height)
3520 {
3521 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
3522 }
3523 else
3524 {
3525 if (fill_type == META_IMAGE_FILL_TILE)
3526 {
3527 pixbuf = pixbuf_tile (pixbuf, width, height);
3528 }
3529 else
3530 {
3531 int src_h, src_w, dest_h, dest_w;
3532 src_h = gdk_pixbuf_get_height (src);
3533 src_w = gdk_pixbuf_get_width (src);
3534
3535 /* prefer to replicate_cols if possible, as that
3536 * is faster (no memory reads)
3537 */
3538 if (horizontal_stripes)
3539 {
3540 dest_w = gdk_pixbuf_get_width (src);
3541 dest_h = height;
3542 }
3543 else if (vertical_stripes)
3544 {
3545 dest_w = width;
3546 dest_h = gdk_pixbuf_get_height (src);
3547 }
3548
3549 else
3550 {
3551 dest_w = width;
3552 dest_h = height;
3553 }
3554
3555 if (dest_w == src_w && dest_h == src_h)
3556 {
3557 temp_pixbuf = src;
3558 g_object_ref (G_OBJECT (temp_pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2)))))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((temp_pixbuf)), (((GType) ((20) << (
2))))))))))
;
3559 }
3560 else
3561 {
3562 temp_pixbuf = gdk_pixbuf_scale_simple (src,
3563 dest_w, dest_h,
3564 GDK_INTERP_BILINEAR);
3565 }
3566
3567 /* prefer to replicate_cols if possible, as that
3568 * is faster (no memory reads)
3569 */
3570 if (horizontal_stripes)
3571 {
3572 pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
3573 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3574 }
3575 else if (vertical_stripes)
3576 {
3577 pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
3578 g_object_unref (G_OBJECT (temp_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((temp_pixbuf)), (((GType) ((20) << (2))))))))
);
3579 }
3580 else
3581 {
3582 pixbuf = temp_pixbuf;
3583 }
3584 }
3585 }
3586
3587 if (pixbuf)
3588 pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
3589
3590 return pixbuf;
3591}
3592
3593static GdkPixbuf*
3594draw_op_as_pixbuf (const MetaDrawOp *op,
3595 GtkStyleContext *style,
3596 const MetaDrawInfo *info,
3597 int width,
3598 int height)
3599{
3600 /* Try to get the op as a pixbuf, assuming w/h in the op
3601 * matches the width/height passed in. return NULL
3602 * if the op can't be converted to an equivalent pixbuf.
3603 */
3604 GdkPixbuf *pixbuf;
3605
3606 pixbuf = NULL((void*)0);
3607
3608 switch (op->type)
3609 {
3610 case META_DRAW_LINE:
3611 break;
3612
3613 case META_DRAW_RECTANGLE:
3614 if (op->data.rectangle.filled)
3615 {
3616 GdkRGBA color;
3617
3618 meta_color_spec_render (op->data.rectangle.color_spec,
3619 style,
3620 &color);
3621
3622 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3623 FALSE(0),
3624 8, width, height);
3625
3626 gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
);
3627 }
3628 break;
3629
3630 case META_DRAW_ARC:
3631 break;
3632
3633 case META_DRAW_CLIP:
3634 break;
3635
3636 case META_DRAW_TINT:
3637 {
3638 GdkRGBA color;
3639 guint32 rgba;
3640 gboolean has_alpha;
3641
3642 meta_color_spec_render (op->data.rectangle.color_spec,
3643 style,
3644 &color);
3645
3646 has_alpha =
3647 op->data.tint.alpha_spec &&
3648 (op->data.tint.alpha_spec->n_alphas > 1 ||
3649 op->data.tint.alpha_spec->alphas[0] != 0xff);
3650
3651 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
3652 has_alpha,
3653 8, width, height);
3654
3655 if (!has_alpha)
3656 {
3657 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3658
3659 gdk_pixbuf_fill (pixbuf, rgba);
3660 }
3661 else if (op->data.tint.alpha_spec->n_alphas == 1)
3662 {
3663 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3664 rgba &= ~0xff;
3665 rgba |= op->data.tint.alpha_spec->alphas[0];
3666
3667 gdk_pixbuf_fill (pixbuf, rgba);
3668 }
3669 else
3670 {
3671 rgba = GDK_COLOR_RGBA (color)((guint32) (0xff | ((int)((color).red * 255) << 24) | (
(int)((color).green * 255) << 16) | ((int)((color).blue
* 255) << 8)))
;
3672
3673 gdk_pixbuf_fill (pixbuf, rgba);
3674
3675 meta_gradient_add_alpha (pixbuf,
3676 op->data.tint.alpha_spec->alphas,
3677 op->data.tint.alpha_spec->n_alphas,
3678 op->data.tint.alpha_spec->type);
3679 }
3680 }
3681 break;
3682
3683 case META_DRAW_IMAGE:
3684 {
3685 if (op->data.image.colorize_spec)
3686 {
3687 GdkRGBA color;
3688
3689 meta_color_spec_render (op->data.image.colorize_spec,
3690 style, &color);
3691
3692 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3693 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3694 {
3695 if (op->data.image.colorize_cache_pixbuf)
3696 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3697
3698 /* const cast here */
3699 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3700 colorize_pixbuf (op->data.image.pixbuf,
3701 &color);
3702 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3703 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3704 }
3705
3706 if (op->data.image.colorize_cache_pixbuf)
3707 {
3708 pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
3709 op->data.image.alpha_spec,
3710 op->data.image.fill_type,
3711 width, height,
3712 op->data.image.vertical_stripes,
3713 op->data.image.horizontal_stripes);
3714 }
3715 }
3716 else
3717 {
3718 pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
3719 op->data.image.alpha_spec,
3720 op->data.image.fill_type,
3721 width, height,
3722 op->data.image.vertical_stripes,
3723 op->data.image.horizontal_stripes);
3724 }
3725 break;
3726 }
3727
3728 case META_DRAW_GRADIENT:
3729 case META_DRAW_GTK_ARROW:
3730 case META_DRAW_GTK_BOX:
3731 case META_DRAW_GTK_VLINE:
3732 break;
3733
3734 case META_DRAW_ICON:
3735 if (info->mini_icon &&
3736 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3737 height <= gdk_pixbuf_get_height (info->mini_icon))
3738 pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
3739 op->data.icon.alpha_spec,
3740 op->data.icon.fill_type,
3741 width, height,
3742 FALSE(0), FALSE(0));
3743 else if (info->icon)
3744 pixbuf = scale_and_alpha_pixbuf (info->icon,
3745 op->data.icon.alpha_spec,
3746 op->data.icon.fill_type,
3747 width, height,
3748 FALSE(0), FALSE(0));
3749 break;
3750
3751 case META_DRAW_TITLE:
3752 break;
3753
3754 case META_DRAW_OP_LIST:
3755 break;
3756
3757 case META_DRAW_TILE:
3758 break;
3759 }
3760
3761 return pixbuf;
3762}
3763
3764static cairo_surface_t *
3765draw_op_as_surface (const MetaDrawOp *op,
3766 GtkStyleContext *style,
3767 const MetaDrawInfo *info,
3768 gdouble width,
3769 gdouble height)
3770{
3771 cairo_surface_t *surface;
3772
3773 surface = NULL((void*)0);
3774
3775 switch (op->type)
3776 {
3777 case META_DRAW_IMAGE:
3778 {
3779 if (op->data.image.colorize_spec)
3780 {
3781 GdkRGBA color;
3782
3783 meta_color_spec_render (op->data.image.colorize_spec,
3784 style, &color);
3785
3786 if (op->data.image.colorize_cache_pixbuf == NULL((void*)0) ||
3787 op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
)
3788 {
3789 if (op->data.image.colorize_cache_pixbuf)
3790 g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((op->data.image.colorize_cache_pixbuf)), (((GType) ((20
) << (2))))))))
);
3791
3792 /* const cast here */
3793 ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
3794 colorize_pixbuf (op->data.image.pixbuf,
3795 &color);
3796 ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
3797 GDK_COLOR_RGB (color)((guint32) (((int)((color).red * 255) << 16) | ((int)((
color).green * 255) << 8) | ((int)((color).blue * 255))
))
;
3798 }
3799
3800 if (op->data.image.colorize_cache_pixbuf)
3801 {
3802 surface = get_surface_from_pixbuf (op->data.image.colorize_cache_pixbuf,
3803 op->data.image.fill_type,
3804 width, height,
3805 op->data.image.vertical_stripes,
3806 op->data.image.horizontal_stripes);
3807 }
3808 }
3809 else
3810 {
3811 surface = get_surface_from_pixbuf (op->data.image.pixbuf,
3812 op->data.image.fill_type,
3813 width, height,
3814 op->data.image.vertical_stripes,
3815 op->data.image.horizontal_stripes);
3816 }
3817 break;
3818 }
3819
3820 case META_DRAW_ICON:
3821 if (info->mini_icon &&
3822 width <= gdk_pixbuf_get_width (info->mini_icon) &&
3823 height <= gdk_pixbuf_get_height (info->mini_icon))
3824 surface = get_surface_from_pixbuf (info->mini_icon, op->data.icon.fill_type,
3825 width, height, FALSE(0), FALSE(0));
3826 else if (info->icon)
3827 surface = get_surface_from_pixbuf (info->icon, op->data.icon.fill_type,
3828 width, height, FALSE(0), FALSE(0));
3829 break;
3830
3831 case META_DRAW_TINT:
3832 case META_DRAW_LINE:
3833 case META_DRAW_RECTANGLE:
3834 case META_DRAW_ARC:
3835 case META_DRAW_CLIP:
3836 case META_DRAW_GRADIENT:
3837 case META_DRAW_GTK_ARROW:
3838 case META_DRAW_GTK_BOX:
3839 case META_DRAW_GTK_VLINE:
3840 case META_DRAW_TITLE:
3841 case META_DRAW_OP_LIST:
3842 case META_DRAW_TILE:
3843 break;
3844
3845 default:
3846 break;
3847 }
3848
3849 return surface;
3850}
3851
3852static void
3853fill_env (MetaPositionExprEnv *env,
3854 const MetaDrawInfo *info,
3855 MetaRectangle logical_region)
3856{
3857 /* FIXME this stuff could be raised into draw_op_list_draw() probably
3858 */
3859 env->rect = logical_region;
3860 env->object_width = -1;
3861 env->object_height = -1;
3862 if (info->fgeom)
3863 {
3864 env->left_width = info->fgeom->borders.visible.left;
3865 env->right_width = info->fgeom->borders.visible.right;
3866 env->top_height = info->fgeom->borders.visible.top;
3867 env->bottom_height = info->fgeom->borders.visible.bottom;
3868 env->frame_x_center = info->fgeom->width / 2 - logical_region.x;
3869 env->frame_y_center = info->fgeom->height / 2 - logical_region.y;
3870 }
3871 else
3872 {
3873 env->left_width = 0;
3874 env->right_width = 0;
3875 env->top_height = 0;
3876 env->bottom_height = 0;
3877 env->frame_x_center = 0;
3878 env->frame_y_center = 0;
3879 }
3880
3881 env->mini_icon_width = info->mini_icon ? gdk_pixbuf_get_width (info->mini_icon) : 0;
3882 env->mini_icon_height = info->mini_icon ? gdk_pixbuf_get_height (info->mini_icon) : 0;
3883 env->icon_width = info->icon ? gdk_pixbuf_get_width (info->icon) : 0;
3884 env->icon_height = info->icon ? gdk_pixbuf_get_height (info->icon) : 0;
3885
3886 env->title_width = info->title_layout_width;
3887 env->title_height = info->title_layout_height;
3888 env->theme = meta_current_theme;
3889}
3890
3891/* This code was originally rendering anti-aliased using X primitives, and
3892 * now has been switched to draw anti-aliased using cairo. In general, the
3893 * closest correspondence between X rendering and cairo rendering is given
3894 * by offsetting the geometry by 0.5 pixels in both directions before rendering
3895 * with cairo. This is because X samples at the upper left corner of the
3896 * pixel while cairo averages over the entire pixel. However, in the cases
3897 * where the X rendering was an exact rectangle with no "jaggies"
3898 * we need to be a bit careful about applying the offset. We want to produce
3899 * the exact same pixel-aligned rectangle, rather than a rectangle with
3900 * fuzz around the edges.
3901 */
3902static void
3903meta_draw_op_draw_with_env (const MetaDrawOp *op,
3904 GtkStyleContext *style_gtk,
3905 cairo_t *cr,
3906 const MetaDrawInfo *info,
3907 MetaRectangle rect,
3908 MetaPositionExprEnv *env)
3909{
3910 GdkRGBA color;
3911
3912 cairo_save (cr);
3913 gtk_style_context_save (style_gtk);
3914
3915 cairo_set_line_width (cr, 1.0);
3916
3917 switch (op->type)
3918 {
3919 case META_DRAW_LINE:
3920 {
3921 int x1, x2, y1, y2;
3922
3923 meta_color_spec_render (op->data.line.color_spec, style_gtk, &color);
3924 gdk_cairo_set_source_rgba (cr, &color);
3925
3926 if (op->data.line.width > 0)
3927 cairo_set_line_width (cr, op->data.line.width);
3928
3929 if (op->data.line.dash_on_length > 0 &&
3930 op->data.line.dash_off_length > 0)
3931 {
3932 double dash_list[2];
3933 dash_list[0] = op->data.line.dash_on_length;
3934 dash_list[1] = op->data.line.dash_off_length;
3935 cairo_set_dash (cr, dash_list, 2, 0);
3936 }
3937
3938 x1 = parse_x_position_unchecked (op->data.line.x1, env);
3939 y1 = parse_y_position_unchecked (op->data.line.y1, env);
3940
3941 if (!op->data.line.x2 &&
3942 !op->data.line.y2 &&
3943 op->data.line.width==0)
3944 {
3945 cairo_rectangle (cr, x1, y1, 1, 1);
3946 cairo_fill (cr);
3947 }
3948 else
3949 {
3950 if (op->data.line.x2)
3951 x2 = parse_x_position_unchecked (op->data.line.x2, env);
3952 else
3953 x2 = x1;
3954
3955 if (op->data.line.y2)
3956 y2 = parse_y_position_unchecked (op->data.line.y2, env);
3957 else
3958 y2 = y1;
3959
3960 /* This is one of the cases where we are matching the exact
3961 * pixel aligned rectangle produced by X; for zero-width lines
3962 * the generic algorithm produces the right result so we don't
3963 * need to handle them here.
3964 */
3965 if ((y1 == y2 || x1 == x2) && op->data.line.width != 0)
3966 {
3967 double offset = op->data.line.width % 2 ? .5 : 0;
3968
3969 if (y1 == y2)
3970 {
3971 cairo_move_to (cr, x1, y1 + offset);
3972 cairo_line_to (cr, x2, y2 + offset);
3973 }
3974 else
3975 {
3976 cairo_move_to (cr, x1 + offset, y1);
3977 cairo_line_to (cr, x2 + offset, y2);
3978 }
3979 }
3980 else
3981 {
3982 /* zero-width lines include both end-points in X, unlike wide lines */
3983 if (op->data.line.width == 0)
3984 cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
3985
3986 cairo_move_to (cr, x1 + .5, y1 + .5);
3987 cairo_line_to (cr, x2 + .5, y2 + .5);
3988 }
3989 cairo_stroke (cr);
3990 }
3991 }
3992 break;
3993
3994 case META_DRAW_RECTANGLE:
3995 {
3996 int rx, ry, rwidth, rheight;
3997
3998 meta_color_spec_render (op->data.rectangle.color_spec, style_gtk, &color);
3999 gdk_cairo_set_source_rgba (cr, &color);
4000
4001 rx = parse_x_position_unchecked (op->data.rectangle.x, env);
4002 ry = parse_y_position_unchecked (op->data.rectangle.y, env);
4003 rwidth = parse_size_unchecked (op->data.rectangle.width, env);
4004 rheight = parse_size_unchecked (op->data.rectangle.height, env);
4005
4006 /* Filled and stroked rectangles are the other cases
4007 * we pixel-align to X rasterization
4008 */
4009 if (op->data.rectangle.filled)
4010 {
4011 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4012 cairo_fill (cr);
4013 }
4014 else
4015 {
4016 cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight);
4017 cairo_stroke (cr);
4018 }
4019 }
4020 break;
4021
4022 case META_DRAW_ARC:
4023 {
4024 int rx, ry, rwidth, rheight;
4025 double start_angle, end_angle;
4026 double center_x, center_y;
4027
4028 meta_color_spec_render (op->data.arc.color_spec, style_gtk, &color);
4029 gdk_cairo_set_source_rgba (cr, &color);
4030
4031 rx = parse_x_position_unchecked (op->data.arc.x, env);
4032 ry = parse_y_position_unchecked (op->data.arc.y, env);
4033 rwidth = parse_size_unchecked (op->data.arc.width, env);
4034 rheight = parse_size_unchecked (op->data.arc.height, env);
4035
4036 start_angle = op->data.arc.start_angle * (M_PI3.14159265358979323846 / 180.)
4037 - (.5 * M_PI3.14159265358979323846); /* start at 12 instead of 3 oclock */
4038 end_angle = start_angle + op->data.arc.extent_angle * (M_PI3.14159265358979323846 / 180.);
4039 center_x = rx + (double)rwidth / 2. + .5;
4040 center_y = ry + (double)rheight / 2. + .5;
4041
4042 cairo_save (cr);
4043
4044 cairo_translate (cr, center_x, center_y);
4045 cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.);
4046
4047 if (op->data.arc.extent_angle >= 0)
4048 cairo_arc (cr, 0, 0, 1, start_angle, end_angle);
4049 else
4050 cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle);
4051
4052 cairo_restore (cr);
4053
4054 if (op->data.arc.filled)
4055 {
4056 cairo_line_to (cr, center_x, center_y);
4057 cairo_fill (cr);
4058 }
4059 else
4060 cairo_stroke (cr);
4061 }
4062 break;
4063
4064 case META_DRAW_CLIP:
4065 break;
4066
4067 case META_DRAW_TINT:
4068 {
4069 int rx, ry, rwidth, rheight;
4070 gboolean needs_alpha;
4071
4072 needs_alpha = op->data.tint.alpha_spec &&
4073 (op->data.tint.alpha_spec->n_alphas > 1 ||
4074 op->data.tint.alpha_spec->alphas[0] != 0xff);
4075
4076 rx = parse_x_position_unchecked (op->data.tint.x, env);
4077 ry = parse_y_position_unchecked (op->data.tint.y, env);
4078 rwidth = parse_size_unchecked (op->data.tint.width, env);
4079 rheight = parse_size_unchecked (op->data.tint.height, env);
4080
4081 if (!needs_alpha)
4082 {
4083 meta_color_spec_render (op->data.tint.color_spec, style_gtk, &color);
4084 gdk_cairo_set_source_rgba (cr, &color);
4085
4086 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4087 cairo_fill (cr);
4088 }
4089 else
4090 {
4091 GdkPixbuf *pixbuf;
4092
4093 pixbuf = draw_op_as_pixbuf (op, style_gtk, info,
4094 rwidth, rheight);
4095
4096 if (pixbuf)
4097 {
4098 gdk_cairo_set_source_pixbuf (cr, pixbuf, rx, ry);
4099 cairo_paint (cr);
4100
4101 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
4102 }
4103 }
4104 }
4105 break;
4106
4107 case META_DRAW_GRADIENT:
4108 {
4109 int rx, ry, rwidth, rheight;
4110
4111 rx = parse_x_position_unchecked (op->data.gradient.x, env);
4112 ry = parse_y_position_unchecked (op->data.gradient.y, env);
4113 rwidth = parse_size_unchecked (op->data.gradient.width, env);
4114 rheight = parse_size_unchecked (op->data.gradient.height, env);
4115
4116 meta_gradient_spec_render (op->data.gradient.gradient_spec,
4117 op->data.gradient.alpha_spec,
4118 cr, style_gtk, rx, ry, rwidth, rheight);
4119 }
4120 break;
4121
4122 case META_DRAW_IMAGE:
4123 {
4124 gint scale;
4125 gdouble rx, ry, rwidth, rheight;
4126 cairo_surface_t *surface;
4127
4128 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4129 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4130
4131 if (op->data.image.pixbuf)
4132 {
4133 env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf) / scale;
4134 env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf) / scale;
4135 }
4136
4137 rwidth = parse_size_unchecked (op->data.image.width, env) * scale;
4138 rheight = parse_size_unchecked (op->data.image.height, env) * scale;
4139
4140 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4141
4142 if (surface)
4143 {
4144 rx = parse_x_position_unchecked (op->data.image.x, env) * scale;
4145 ry = parse_y_position_unchecked (op->data.image.y, env) * scale;
4146
4147 cairo_set_source_surface (cr, surface, rx, ry);
4148
4149 if (op->data.image.alpha_spec)
4150 {
4151 cairo_pattern_t *pattern;
4152
4153 cairo_translate (cr, rx, ry);
4154 cairo_scale (cr, rwidth, rheight);
4155
4156 pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec);
4157 cairo_mask (cr, pattern);
4158
4159 cairo_pattern_destroy (pattern);
4160 }
4161 else
4162 {
4163 cairo_paint (cr);
4164 }
4165
4166 cairo_surface_destroy (surface);
4167 }
4168 }
4169 break;
4170
4171 case META_DRAW_GTK_ARROW:
4172 {
4173 int rx, ry, rwidth, rheight;
4174
4175 rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
4176 ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
4177 rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
4178 rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
4179
4180 double size = MAX(rwidth, rheight)(((rwidth) > (rheight)) ? (rwidth) : (rheight)), angle = 0;
4181
4182 switch (op->data.gtk_arrow.arrow)
4183 {
4184 case GTK_ARROW_UP:
4185 angle = 0;
4186 break;
4187 case GTK_ARROW_RIGHT:
4188 angle = M_PI3.14159265358979323846 / 2;
4189 break;
4190 case GTK_ARROW_DOWN:
4191 angle = M_PI3.14159265358979323846;
4192 break;
4193 case GTK_ARROW_LEFT:
4194 angle = 3 * M_PI3.14159265358979323846 / 2;
4195 break;
4196 case GTK_ARROW_NONE:
4197 return;
4198 }
4199
4200 gtk_style_context_set_state (style_gtk, op->data.gtk_arrow.state);
4201 gtk_render_arrow (style_gtk, cr, angle, rx, ry, size);
4202 }
4203 break;
4204
4205 case META_DRAW_GTK_BOX:
4206 {
4207 int rx, ry, rwidth, rheight;
4208
4209 rx = parse_x_position_unchecked (op->data.gtk_box.x, env);
4210 ry = parse_y_position_unchecked (op->data.gtk_box.y, env);
4211 rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
4212 rheight = parse_size_unchecked (op->data.gtk_box.height, env);
4213
4214 gtk_style_context_set_state (style_gtk, op->data.gtk_box.state);
4215 gtk_render_background (style_gtk, cr, rx, ry, rwidth, rheight);
4216 gtk_render_frame (style_gtk, cr, rx, ry, rwidth, rheight);
4217 }
4218 break;
4219
4220 case META_DRAW_GTK_VLINE:
4221 {
4222 int rx, ry1, ry2;
4223
4224 rx = parse_x_position_unchecked (op->data.gtk_vline.x, env);
4225 ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
4226 ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
4227
4228 gtk_style_context_set_state (style_gtk, op->data.gtk_vline.state);
4229 gtk_render_line (style_gtk, cr, rx, ry1, rx, ry2);
4230 }
4231 break;
4232
4233 case META_DRAW_ICON:
4234 {
4235 gint scale;
4236 gdouble rx, ry, rwidth, rheight;
4237 cairo_surface_t *surface;
4238
4239 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
4240 cairo_scale (cr, 1.0 / scale, 1.0 / scale);
4241
4242 rwidth = parse_size_unchecked (op->data.icon.width, env) * scale;
4243 rheight = parse_size_unchecked (op->data.icon.height, env) * scale;
4244
4245 surface = draw_op_as_surface (op, style_gtk, info, rwidth, rheight);
4246
4247 if (surface)
4248 {
4249 rx = parse_x_position_unchecked (op->data.icon.x, env) * scale;
4250 ry = parse_y_position_unchecked (op->data.icon.y, env) * scale;
4251
4252 cairo_set_source_surface (cr, surface, rx, ry);
4253
4254 if (op->data.icon.alpha_spec)
4255 {
4256 cairo_pattern_t *pattern;
4257
4258 cairo_translate (cr, rx, ry);
4259 cairo_scale (cr, rwidth, rheight);
4260
4261 pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec);
4262 cairo_mask (cr, pattern);
4263
4264 cairo_pattern_destroy (pattern);
4265 }
4266 else
4267 {
4268 cairo_paint (cr);
4269 }
4270
4271 cairo_surface_destroy (surface);
4272 }
4273 }
4274 break;
4275
4276 case META_DRAW_TITLE:
4277 if (info->title_layout)
4278 {
4279 int rx, ry;
4280 PangoRectangle ink_rect, logical_rect;
4281
4282 meta_color_spec_render (op->data.title.color_spec, style_gtk, &color);
4283 gdk_cairo_set_source_rgba (cr, &color);
4284
4285 rx = parse_x_position_unchecked (op->data.title.x, env);
4286 ry = parse_y_position_unchecked (op->data.title.y, env);
4287
4288 if (op->data.title.ellipsize_width)
4289 {
4290 int ellipsize_width;
4291 int right_bearing;
4292
4293 ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env);
4294 /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */
4295 ellipsize_width -= env->rect.x;
4296
4297 pango_layout_set_width (info->title_layout, -1);
4298 pango_layout_get_pixel_extents (info->title_layout,
4299 &ink_rect, &logical_rect);
4300
4301 /* Pango's idea of ellipsization is with respect to the logical rect.
4302 * correct for this, by reducing the ellipsization width by the overflow
4303 * of the un-ellipsized text on the right... it's always the visual
4304 * right we want regardless of bidi, since since the X we pass in to
4305 * cairo_move_to() is always the left edge of the line.
4306 */
4307 right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width);
4308 right_bearing = MAX (right_bearing, 0)(((right_bearing) > (0)) ? (right_bearing) : (0));
4309
4310 ellipsize_width -= right_bearing;
4311 ellipsize_width = MAX (ellipsize_width, 0)(((ellipsize_width) > (0)) ? (ellipsize_width) : (0));
4312
4313 /* Only ellipsizing when necessary is a performance optimization -
4314 * pango_layout_set_width() will force a relayout if it isn't the
4315 * same as the current width of -1.
4316 */
4317 if (ellipsize_width < logical_rect.width)
4318 pango_layout_set_width (info->title_layout, PANGO_SCALE1024 * ellipsize_width);
4319 }
4320 else if (rx - env->rect.x + env->title_width >= env->rect.width)
4321 {
4322 const double alpha_margin = 30.0;
4323 int text_space = env->rect.x + env->rect.width -
4324 (rx - env->rect.x) - env->right_width;
4325
4326 double startalpha = 1.0 - (alpha_margin/((double)text_space));
4327
4328 cairo_pattern_t *linpat;
4329 linpat = cairo_pattern_create_linear (rx, ry, text_space,
4330 env->title_height);
4331 cairo_pattern_add_color_stop_rgba (linpat, 0, color.red,
4332 color.green,
4333 color.blue,
4334 color.alpha);
4335 cairo_pattern_add_color_stop_rgba (linpat, startalpha,
4336 color.red,
4337 color.green,
4338 color.blue,
4339 color.alpha);
4340 cairo_pattern_add_color_stop_rgba (linpat, 1, color.red,
4341 color.green,
4342 color.blue, 0);
4343 cairo_set_source(cr, linpat);
4344 cairo_pattern_destroy(linpat);
4345 }
4346
4347 cairo_move_to (cr, rx, ry);
4348 pango_cairo_show_layout (cr, info->title_layout);
4349
4350 /* Remove any ellipsization we might have set; will short-circuit
4351 * if the width is already -1 */
4352 pango_layout_set_width (info->title_layout, -1);
4353 }
4354 break;
4355
4356 case META_DRAW_OP_LIST:
4357 {
4358 MetaRectangle d_rect;
4359
4360 d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env);
4361 d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env);
4362 d_rect.width = parse_size_unchecked (op->data.op_list.width, env);
4363 d_rect.height = parse_size_unchecked (op->data.op_list.height, env);
4364
4365 meta_draw_op_list_draw_with_style (op->data.op_list.op_list,
4366 style_gtk,
4367 cr,
4368 info, d_rect);
4369 }
4370 break;
4371
4372 case META_DRAW_TILE:
4373 {
4374 int rx, ry, rwidth, rheight;
4375 int tile_xoffset, tile_yoffset;
4376 MetaRectangle tile;
4377
4378 rx = parse_x_position_unchecked (op->data.tile.x, env);
4379 ry = parse_y_position_unchecked (op->data.tile.y, env);
4380 rwidth = parse_size_unchecked (op->data.tile.width, env);
4381 rheight = parse_size_unchecked (op->data.tile.height, env);
4382
4383 cairo_save (cr);
4384
4385 cairo_rectangle (cr, rx, ry, rwidth, rheight);
4386 cairo_clip (cr);
4387
4388 tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env);
4389 tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env);
4390 /* tile offset should not include x/y */
4391 tile_xoffset -= rect.x;
4392 tile_yoffset -= rect.y;
4393
4394 tile.width = parse_size_unchecked (op->data.tile.tile_width, env);
4395 tile.height = parse_size_unchecked (op->data.tile.tile_height, env);
4396
4397 tile.x = rx - tile_xoffset;
4398
4399 while (tile.x < (rx + rwidth))
4400 {
4401 tile.y = ry - tile_yoffset;
4402 while (tile.y < (ry + rheight))
4403 {
4404 meta_draw_op_list_draw_with_style (op->data.tile.op_list,
4405 style_gtk, cr, info,
4406 tile);
4407
4408 tile.y += tile.height;
4409 }
4410
4411 tile.x += tile.width;
4412 }
4413 cairo_restore (cr);
4414 }
4415 break;
4416 }
4417
4418 cairo_restore (cr);
4419 gtk_style_context_restore (style_gtk);
4420}
4421
4422void
4423meta_draw_op_draw_with_style (const MetaDrawOp *op,
4424 GtkStyleContext *style_gtk,
4425 cairo_t *cr,
4426 const MetaDrawInfo *info,
4427 MetaRectangle logical_region)
4428{
4429 MetaPositionExprEnv env;
4430
4431 fill_env (&env, info, logical_region);
4432
4433 meta_draw_op_draw_with_env (op,
4434 style_gtk,
4435 cr,
4436 info, logical_region,
4437 &env);
4438
4439}
4440
4441void
4442meta_draw_op_draw (const MetaDrawOp *op,
4443 GtkWidget *widget,
4444 cairo_t *cr,
4445 const MetaDrawInfo *info,
4446 MetaRectangle logical_region)
4447{
4448 meta_draw_op_draw_with_style (op,
4449 gtk_widget_get_style_context (widget),
4450 cr,
4451 info, logical_region);
4452}
4453
4454MetaDrawOpList*
4455meta_draw_op_list_new (int n_preallocs)
4456{
4457 MetaDrawOpList *op_list;
4458
4459 g_return_val_if_fail (n_preallocs >= 0, NULL)do { if ((n_preallocs >= 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "n_preallocs >= 0")
; return (((void*)0)); } } while (0)
;
4460
4461 op_list = g_new (MetaDrawOpList, 1)((MetaDrawOpList *) g_malloc_n ((1), sizeof (MetaDrawOpList))
)
;
4462
4463 op_list->refcount = 1;
4464 op_list->n_allocated = n_preallocs;
4465 op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated)((MetaDrawOp* *) g_malloc_n ((op_list->n_allocated), sizeof
(MetaDrawOp*)))
;
4466 op_list->n_ops = 0;
4467
4468 return op_list;
4469}
4470
4471void
4472meta_draw_op_list_ref (MetaDrawOpList *op_list)
4473{
4474 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4475
4476 op_list->refcount += 1;
4477}
4478
4479void
4480meta_draw_op_list_unref (MetaDrawOpList *op_list)
4481{
4482 g_return_if_fail (op_list != NULL)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
; } } while (0)
;
4483 g_return_if_fail (op_list->refcount > 0)do { if ((op_list->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list->refcount > 0"
); return; } } while (0)
;
4484
4485 op_list->refcount -= 1;
4486
4487 if (op_list->refcount == 0)
4488 {
4489 int i;
4490
4491 for (i = 0; i < op_list->n_ops; i++)
4492 meta_draw_op_free (op_list->ops[i]);
4493
4494 g_free (op_list->ops);
4495
4496 DEBUG_FILL_STRUCT (op_list)memset ((op_list), 0xef, sizeof (*(op_list)));
4497 g_free (op_list);
4498 }
4499}
4500
4501void
4502meta_draw_op_list_draw_with_style (const MetaDrawOpList *op_list,
4503 GtkStyleContext *style_gtk,
4504 cairo_t *cr,
4505 const MetaDrawInfo *info,
4506 MetaRectangle rect)
4507{
4508 /* BOOKMARK */
4509
4510 int i;
4511 MetaPositionExprEnv env;
4512
4513 if (op_list->n_ops == 0)
4514 return;
4515
4516 fill_env (&env, info, rect);
4517
4518 /* FIXME this can be optimized, potentially a lot, by
4519 * compressing multiple ops when possible. For example,
4520 * anything convertible to a pixbuf can be composited
4521 * client-side, and putting a color tint over a pixbuf
4522 * can be done without creating the solid-color pixbuf.
4523 *
4524 * To implement this my plan is to have the idea of a
4525 * compiled draw op (with the string expressions already
4526 * evaluated), we make an array of those, and then fold
4527 * adjacent items when possible.
4528 */
4529
4530 cairo_save (cr);
4531
4532 for (i = 0; i < op_list->n_ops; i++)
4533 {
4534 MetaDrawOp *op = op_list->ops[i];
4535
4536 if (op->type == META_DRAW_CLIP)
4537 {
4538 cairo_restore (cr);
4539
4540 cairo_rectangle (cr,
4541 parse_x_position_unchecked (op->data.clip.x, &env),
4542 parse_y_position_unchecked (op->data.clip.y, &env),
4543 parse_size_unchecked (op->data.clip.width, &env),
4544 parse_size_unchecked (op->data.clip.height, &env));
4545 cairo_clip (cr);
4546
4547 cairo_save (cr);
4548 }
4549 else if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
4550 {
4551 meta_draw_op_draw_with_env (op, style_gtk, cr, info, rect, &env);
4552 }
4553 }
4554
4555 cairo_restore (cr);
4556}
4557
4558void
4559meta_draw_op_list_draw (const MetaDrawOpList *op_list,
4560 GtkWidget *widget,
4561 cairo_t *cr,
4562 const MetaDrawInfo *info,
4563 MetaRectangle rect)
4564
4565{
4566 meta_draw_op_list_draw_with_style (op_list,
4567 gtk_widget_get_style_context (widget),
4568 cr,
4569 info, rect);
4570}
4571
4572void
4573meta_draw_op_list_append (MetaDrawOpList *op_list,
4574 MetaDrawOp *op)
4575{
4576 if (op_list->n_ops == op_list->n_allocated)
4577 {
4578 op_list->n_allocated *= 2;
4579 op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated)((MetaDrawOp* *) g_realloc_n (op_list->ops, (op_list->n_allocated
), sizeof (MetaDrawOp*)))
;
4580 }
4581
4582 op_list->ops[op_list->n_ops] = op;
4583 op_list->n_ops += 1;
4584}
4585
4586gboolean
4587meta_draw_op_list_validate (MetaDrawOpList *op_list,
4588 GError **error)
4589{
4590 g_return_val_if_fail (op_list != NULL, FALSE)do { if ((op_list != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "op_list != NULL"); return
((0)); } } while (0)
;
4591
4592 /* empty lists are OK, nothing else to check really */
4593
4594 return TRUE(!(0));
4595}
4596
4597/* This is not done in validate, since we wouldn't know the name
4598 * of the list to report the error. It might be nice to
4599 * store names inside the list sometime.
4600 */
4601gboolean
4602meta_draw_op_list_contains (MetaDrawOpList *op_list,
4603 MetaDrawOpList *child)
4604{
4605 int i;
4606
4607 /* mmm, huge tree recursion */
4608
4609 for (i = 0; i < op_list->n_ops; i++)
4610 {
4611 if (op_list->ops[i]->type == META_DRAW_OP_LIST)
4612 {
4613 if (op_list->ops[i]->data.op_list.op_list == child)
4614 return TRUE(!(0));
4615
4616 if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list,
4617 child))
4618 return TRUE(!(0));
4619 }
4620 else if (op_list->ops[i]->type == META_DRAW_TILE)
4621 {
4622 if (op_list->ops[i]->data.tile.op_list == child)
4623 return TRUE(!(0));
4624
4625 if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list,
4626 child))
4627 return TRUE(!(0));
4628 }
4629 }
4630
4631 return FALSE(0);
4632}
4633
4634/**
4635 * Constructor for a MetaFrameStyle.
4636 *
4637 * \param parent The parent style. Data not filled in here will be
4638 * looked for in the parent style, and in its parent
4639 * style, and so on.
4640 *
4641 * \return The newly-constructed style.
4642 */
4643MetaFrameStyle*
4644meta_frame_style_new (MetaFrameStyle *parent)
4645{
4646 MetaFrameStyle *style;
4647
4648 style = g_new0 (MetaFrameStyle, 1)((MetaFrameStyle *) g_malloc0_n ((1), sizeof (MetaFrameStyle)
))
;
4649
4650 style->refcount = 1;
4651
4652 /* Default alpha is fully opaque */
4653 style->window_background_alpha = 255;
4654
4655 style->parent = parent;
4656 if (parent)
4657 meta_frame_style_ref (parent);
4658
4659 return style;
4660}
4661
4662/**
4663 * Increases the reference count of a frame style.
4664 * If the style is NULL, this is a no-op.
4665 *
4666 * \param style The style.
4667 */
4668void
4669meta_frame_style_ref (MetaFrameStyle *style)
4670{
4671 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4672
4673 style->refcount += 1;
4674}
4675
4676static void
4677free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
4678{
4679 int i, j;
4680
4681 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4682 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4683 if (op_lists[i][j])
4684 meta_draw_op_list_unref (op_lists[i][j]);
4685}
4686
4687void
4688meta_frame_style_unref (MetaFrameStyle *style)
4689{
4690 g_return_if_fail (style != NULL)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
; } } while (0)
;
4691 g_return_if_fail (style->refcount > 0)do { if ((style->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->refcount > 0"
); return; } } while (0)
;
4692
4693 style->refcount -= 1;
4694
4695 if (style->refcount == 0)
4696 {
4697 int i;
4698
4699 free_button_ops (style->buttons);
4700
4701 for (i = 0; i < META_FRAME_PIECE_LAST; i++)
4702 if (style->pieces[i])
4703 meta_draw_op_list_unref (style->pieces[i]);
4704
4705 if (style->layout)
4706 meta_frame_layout_unref (style->layout);
4707
4708 if (style->window_background_color)
4709 meta_color_spec_free (style->window_background_color);
4710
4711 /* we hold a reference to any parent style */
4712 if (style->parent)
4713 meta_frame_style_unref (style->parent);
4714
4715 DEBUG_FILL_STRUCT (style)memset ((style), 0xef, sizeof (*(style)));
4716 g_free (style);
4717 }
4718}
4719
4720static MetaButtonState
4721map_button_state (MetaButtonType button_type,
4722 const MetaFrameGeometry *fgeom,
4723 int middle_bg_offset,
4724 MetaButtonState button_states[META_BUTTON_TYPE_LAST])
4725{
4726 MetaButtonFunction function = META_BUTTON_FUNCTION_LAST;
4727
4728 switch (button_type)
4729 {
4730 /* First handle functions, which map directly */
4731 case META_BUTTON_TYPE_SHADE:
4732 case META_BUTTON_TYPE_ABOVE:
4733 case META_BUTTON_TYPE_STICK:
4734 case META_BUTTON_TYPE_UNSHADE:
4735 case META_BUTTON_TYPE_UNABOVE:
4736 case META_BUTTON_TYPE_UNSTICK:
4737 case META_BUTTON_TYPE_MENU:
4738 case META_BUTTON_TYPE_APPMENU:
4739 case META_BUTTON_TYPE_MINIMIZE:
4740 case META_BUTTON_TYPE_MAXIMIZE:
4741 case META_BUTTON_TYPE_CLOSE:
4742 return button_states[button_type];
4743
4744 /* Map position buttons to the corresponding function */
4745 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4746 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4747 if (fgeom->n_right_buttons > 0)
4748 function = fgeom->button_layout.right_buttons[0];
4749 break;
4750 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4751 if (fgeom->n_right_buttons > 0)
4752 function = fgeom->button_layout.right_buttons[fgeom->n_right_buttons - 1];
4753 break;
4754 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4755 if (middle_bg_offset + 1 < fgeom->n_right_buttons)
4756 function = fgeom->button_layout.right_buttons[middle_bg_offset + 1];
4757 break;
4758 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4759 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4760 if (fgeom->n_left_buttons > 0)
4761 function = fgeom->button_layout.left_buttons[0];
4762 break;
4763 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4764 if (fgeom->n_left_buttons > 0)
4765 function = fgeom->button_layout.left_buttons[fgeom->n_left_buttons - 1];
4766 break;
4767 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4768 if (middle_bg_offset + 1 < fgeom->n_left_buttons)
4769 function = fgeom->button_layout.left_buttons[middle_bg_offset + 1];
4770 break;
4771 case META_BUTTON_TYPE_LAST:
4772 break;
4773 }
4774
4775 if (function != META_BUTTON_FUNCTION_LAST)
4776 return button_states[map_button_function_to_type (function)];
4777
4778 return META_BUTTON_STATE_LAST;
4779}
4780
4781static MetaDrawOpList*
4782get_button (MetaFrameStyle *style,
4783 MetaButtonType type,
4784 MetaButtonState state)
4785{
4786 MetaDrawOpList *op_list;
4787 MetaFrameStyle *parent;
4788
4789 parent = style;
4790 op_list = NULL((void*)0);
4791 while (parent && op_list == NULL((void*)0))
4792 {
4793 op_list = parent->buttons[type][state];
4794 parent = parent->parent;
4795 }
4796
4797 /* We fall back to the side buttons if we don't have
4798 * single button backgrounds, and to middle button
4799 * backgrounds if we don't have the ones on the sides
4800 */
4801
4802 if (op_list == NULL((void*)0) &&
4803 type == META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND)
4804 return get_button (style, META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND, state);
4805
4806 if (op_list == NULL((void*)0) &&
4807 type == META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND)
4808 return get_button (style, META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND, state);
4809
4810 if (op_list == NULL((void*)0) &&
4811 (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
4812 type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
4813 return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
4814 state);
4815
4816 if (op_list == NULL((void*)0) &&
4817 (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND ||
4818 type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND))
4819 return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
4820 state);
4821
4822 /* We fall back to normal if no prelight */
4823 if (op_list == NULL((void*)0) &&
4824 state == META_BUTTON_STATE_PRELIGHT)
4825 return get_button (style, type, META_BUTTON_STATE_NORMAL);
4826
4827 return op_list;
4828}
4829
4830gboolean
4831meta_frame_style_validate (MetaFrameStyle *style,
4832 guint current_theme_version,
4833 GError **error)
4834{
4835 int i, j;
4836
4837 g_return_val_if_fail (style != NULL, FALSE)do { if ((style != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style != NULL"); return
((0)); } } while (0)
;
4838 g_return_val_if_fail (style->layout != NULL, FALSE)do { if ((style->layout != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style->layout != NULL"
); return ((0)); } } while (0)
;
4839
4840 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
4841 {
4842 /* for now the "positional" buttons are optional */
4843 if (i >= META_BUTTON_TYPE_CLOSE)
4844 {
4845 for (j = 0; j < META_BUTTON_STATE_LAST; j++)
4846 {
4847 if (get_button (style, i, j) == NULL((void*)0) &&
4848 meta_theme_earliest_version_with_button (i) <= current_theme_version
4849 )
4850 {
4851 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
4852 META_THEME_ERROR_FAILED,
4853 _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style")((char *) g_dgettext ("marco", "<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"
))
,
4854 meta_button_type_to_string (i),
4855 meta_button_state_to_string (j));
4856 return FALSE(0);
4857 }
4858 }
4859 }
4860 }
4861
4862 return TRUE(!(0));
4863}
4864
4865static void
4866get_button_rect (MetaButtonType type,
4867 const MetaFrameGeometry *fgeom,
4868 int middle_background_offset,
4869 GdkRectangle *rect)
4870{
4871 switch (type)
4872 {
4873 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
4874 *rect = fgeom->left_left_background;
4875 break;
4876
4877 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
4878 *rect = fgeom->left_middle_backgrounds[middle_background_offset];
4879 break;
4880
4881 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
4882 *rect = fgeom->left_right_background;
4883 break;
4884
4885 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
4886 *rect = fgeom->left_single_background;
4887 break;
4888
4889 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
4890 *rect = fgeom->right_left_background;
4891 break;
4892
4893 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
4894 *rect = fgeom->right_middle_backgrounds[middle_background_offset];
4895 break;
4896
4897 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
4898 *rect = fgeom->right_right_background;
4899 break;
4900
4901 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
4902 *rect = fgeom->right_single_background;
4903 break;
4904
4905 case META_BUTTON_TYPE_CLOSE:
4906 *rect = fgeom->close_rect.visible;
4907 break;
4908
4909 case META_BUTTON_TYPE_SHADE:
4910 *rect = fgeom->shade_rect.visible;
4911 break;
4912
4913 case META_BUTTON_TYPE_UNSHADE:
4914 *rect = fgeom->unshade_rect.visible;
4915 break;
4916
4917 case META_BUTTON_TYPE_ABOVE:
4918 *rect = fgeom->above_rect.visible;
4919 break;
4920
4921 case META_BUTTON_TYPE_UNABOVE:
4922 *rect = fgeom->unabove_rect.visible;
4923 break;
4924
4925 case META_BUTTON_TYPE_STICK:
4926 *rect = fgeom->stick_rect.visible;
4927 break;
4928
4929 case META_BUTTON_TYPE_UNSTICK:
4930 *rect = fgeom->unstick_rect.visible;
4931 break;
4932
4933 case META_BUTTON_TYPE_MAXIMIZE:
4934 *rect = fgeom->max_rect.visible;
4935 break;
4936
4937 case META_BUTTON_TYPE_MINIMIZE:
4938 *rect = fgeom->min_rect.visible;
4939 break;
4940
4941 case META_BUTTON_TYPE_MENU:
4942 *rect = fgeom->menu_rect.visible;
4943 break;
4944
4945 case META_BUTTON_TYPE_APPMENU:
4946 *rect = fgeom->appmenu_rect.visible;
4947 break;
4948
4949 case META_BUTTON_TYPE_LAST:
4950 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 4950, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
4951 break;
4952 }
4953}
4954
4955void
4956meta_frame_style_draw_with_style (MetaFrameStyle *style,
4957 GtkStyleContext *style_gtk,
4958 cairo_t *cr,
4959 const MetaFrameGeometry *fgeom,
4960 int client_width,
4961 int client_height,
4962 PangoLayout *title_layout,
4963 int text_height,
4964 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
4965 GdkPixbuf *mini_icon,
4966 GdkPixbuf *icon)
4967{
4968 /* BOOKMARK */
4969 int i, j;
4970 GdkRectangle visible_rect;
4971 GdkRectangle titlebar_rect;
4972 GdkRectangle left_titlebar_edge;
4973 GdkRectangle right_titlebar_edge;
4974 GdkRectangle bottom_titlebar_edge;
4975 GdkRectangle top_titlebar_edge;
4976 GdkRectangle left_edge, right_edge, bottom_edge;
4977 PangoRectangle extents;
4978 MetaDrawInfo draw_info;
4979 const MetaFrameBorders *borders;
4980
4981 borders = &fgeom->borders;
4982
4983 visible_rect.x = borders->invisible.left;
4984 visible_rect.y = borders->invisible.top;
4985 visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right;
4986 visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom;
4987
4988 titlebar_rect.x = visible_rect.x;
4989 titlebar_rect.y = visible_rect.y;
4990 titlebar_rect.width = visible_rect.width;
4991 titlebar_rect.height = borders->visible.top;
4992
4993 left_titlebar_edge.x = titlebar_rect.x;
4994 left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
4995 left_titlebar_edge.width = fgeom->left_titlebar_edge;
4996 left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
4997
4998 right_titlebar_edge.y = left_titlebar_edge.y;
4999 right_titlebar_edge.height = left_titlebar_edge.height;
5000 right_titlebar_edge.width = fgeom->right_titlebar_edge;
5001 right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
5002
5003 top_titlebar_edge.x = titlebar_rect.x;
5004 top_titlebar_edge.y = titlebar_rect.y;
5005 top_titlebar_edge.width = titlebar_rect.width;
5006 top_titlebar_edge.height = fgeom->top_titlebar_edge;
5007
5008 bottom_titlebar_edge.x = titlebar_rect.x;
5009 bottom_titlebar_edge.width = titlebar_rect.width;
5010 bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
5011 bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
5012
5013 left_edge.x = visible_rect.x;
5014 left_edge.y = visible_rect.y + borders->visible.top;
5015 left_edge.width = borders->visible.left;
5016 left_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5017
5018 right_edge.x = visible_rect.x + visible_rect.width - borders->visible.right;
5019 right_edge.y = visible_rect.y + borders->visible.top;
5020 right_edge.width = borders->visible.right;
5021 right_edge.height = visible_rect.height - borders->visible.top - borders->visible.bottom;
5022
5023 bottom_edge.x = visible_rect.x;
5024 bottom_edge.y = visible_rect.y + visible_rect.height - borders->visible.bottom;
5025 bottom_edge.width = visible_rect.width;
5026 bottom_edge.height = borders->visible.bottom;
5027
5028 if (title_layout)
5029 pango_layout_get_pixel_extents (title_layout,
5030 NULL((void*)0), &extents);
5031
5032 draw_info.mini_icon = mini_icon;
5033 draw_info.icon = icon;
5034 draw_info.title_layout = title_layout;
5035 draw_info.title_layout_width = title_layout ? extents.width : 0;
5036 draw_info.title_layout_height = title_layout ? extents.height : 0;
5037 draw_info.fgeom = fgeom;
5038
5039 /* The enum is in the order the pieces should be rendered. */
5040 i = 0;
5041 while (i < META_FRAME_PIECE_LAST)
5042 {
5043 GdkRectangle rect;
5044
5045 switch ((MetaFramePiece) i)
5046 {
5047 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
5048 rect = visible_rect;
5049 break;
5050
5051 case META_FRAME_PIECE_TITLEBAR:
5052 rect = titlebar_rect;
5053 break;
5054
5055 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
5056 rect = left_titlebar_edge;
5057 break;
5058
5059 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
5060 rect = right_titlebar_edge;
5061 break;
5062
5063 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
5064 rect = top_titlebar_edge;
5065 break;
5066
5067 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
5068 rect = bottom_titlebar_edge;
5069 break;
5070
5071 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
5072 rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
5073 rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
5074 rect.width = titlebar_rect.width - left_titlebar_edge.width -
5075 right_titlebar_edge.width;
5076 rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
5077 break;
5078
5079 case META_FRAME_PIECE_TITLE:
5080 rect = fgeom->title_rect;
5081 break;
5082
5083 case META_FRAME_PIECE_LEFT_EDGE:
5084 rect = left_edge;
5085 break;
5086
5087 case META_FRAME_PIECE_RIGHT_EDGE:
5088 rect = right_edge;
5089 break;
5090
5091 case META_FRAME_PIECE_BOTTOM_EDGE:
5092 rect = bottom_edge;
5093 break;
5094
5095 case META_FRAME_PIECE_OVERLAY:
5096 rect = visible_rect;
5097 break;
5098
5099 case META_FRAME_PIECE_LAST:
5100 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5100, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5101 break;
5102 }
5103
5104 cairo_save (cr);
5105
5106 gdk_cairo_rectangle (cr, &rect);
5107 cairo_clip (cr);
5108
5109 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5110 {
5111 MetaDrawOpList *op_list;
5112 MetaFrameStyle *parent;
5113
5114 parent = style;
5115 op_list = NULL((void*)0);
5116 while (parent && op_list == NULL((void*)0))
5117 {
5118 op_list = parent->pieces[i];
5119 parent = parent->parent;
5120 }
5121
5122 if (op_list)
5123 {
5124 MetaRectangle m_rect;
5125 m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
5126 meta_draw_op_list_draw_with_style (op_list,
5127 style_gtk,
5128 cr,
5129 &draw_info,
5130 m_rect);
5131 }
5132 }
5133
5134 cairo_restore (cr);
5135
5136 /* Draw buttons just before overlay */
5137 if ((i + 1) == META_FRAME_PIECE_OVERLAY)
5138 {
5139 MetaDrawOpList *op_list;
5140 int middle_bg_offset;
5141
5142 middle_bg_offset = 0;
5143 j = 0;
5144 while (j < META_BUTTON_TYPE_LAST)
5145 {
5146 MetaButtonState button_state;
5147
5148 get_button_rect (j, fgeom, middle_bg_offset, &rect);
5149
5150 button_state = map_button_state (j, fgeom, middle_bg_offset, button_states);
5151 op_list = get_button (style, j, button_state);
5152
5153 if (op_list)
5154 {
5155 cairo_save (cr);
5156 gdk_cairo_rectangle (cr, &rect);
5157 cairo_clip (cr);
5158
5159 if (gdk_cairo_get_clip_rectangle (cr, NULL((void*)0)))
5160 {
5161 MetaRectangle m_rect;
5162
5163 m_rect = meta_rect (rect.x, rect.y,
5164 rect.width, rect.height);
5165
5166 meta_draw_op_list_draw_with_style (op_list,
5167 style_gtk,
5168 cr,
5169 &draw_info,
5170 m_rect);
5171 }
5172
5173 cairo_restore (cr);
5174 }
5175
5176 /* MIDDLE_BACKGROUND type may get drawn more than once */
5177 if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
5178 j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
5179 middle_bg_offset < MAX_MIDDLE_BACKGROUNDS(META_BUTTON_FUNCTION_LAST - 2))
5180 {
5181 ++middle_bg_offset;
5182 }
5183 else
5184 {
5185 middle_bg_offset = 0;
5186 ++j;
5187 }
5188 }
5189 }
5190
5191 ++i;
5192 }
5193}
5194
5195void
5196meta_frame_style_draw (MetaFrameStyle *style,
5197 GtkWidget *widget,
5198 cairo_t *cr,
5199 const MetaFrameGeometry *fgeom,
5200 int client_width,
5201 int client_height,
5202 PangoLayout *title_layout,
5203 int text_height,
5204 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5205 GdkPixbuf *mini_icon,
5206 GdkPixbuf *icon)
5207{
5208 meta_frame_style_draw_with_style (style,
5209 gtk_widget_get_style_context (widget),
5210 cr,
5211 fgeom, client_width, client_height,
5212 title_layout, text_height,
5213 button_states, mini_icon, icon);
5214}
5215
5216MetaFrameStyleSet*
5217meta_frame_style_set_new (MetaFrameStyleSet *parent)
5218{
5219 MetaFrameStyleSet *style_set;
5220
5221 style_set = g_new0 (MetaFrameStyleSet, 1)((MetaFrameStyleSet *) g_malloc0_n ((1), sizeof (MetaFrameStyleSet
)))
;
5222
5223 style_set->parent = parent;
5224 if (parent)
5225 meta_frame_style_set_ref (parent);
5226
5227 style_set->refcount = 1;
5228
5229 return style_set;
5230}
5231
5232static void
5233free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST])
5234{
5235 int i;
5236
5237 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5238 if (focus_styles[i])
5239 meta_frame_style_unref (focus_styles[i]);
5240}
5241
5242void
5243meta_frame_style_set_ref (MetaFrameStyleSet *style_set)
5244{
5245 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5246
5247 style_set->refcount += 1;
5248}
5249
5250void
5251meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
5252{
5253 g_return_if_fail (style_set != NULL)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
; } } while (0)
;
5254 g_return_if_fail (style_set->refcount > 0)do { if ((style_set->refcount > 0)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set->refcount > 0"
); return; } } while (0)
;
5255
5256 style_set->refcount -= 1;
5257
5258 if (style_set->refcount == 0)
5259 {
5260 int i;
5261
5262 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5263 {
5264 free_focus_styles (style_set->normal_styles[i]);
5265 free_focus_styles (style_set->shaded_styles[i]);
5266 }
5267
5268 free_focus_styles (style_set->maximized_styles);
5269 free_focus_styles (style_set->tiled_left_styles);
5270 free_focus_styles (style_set->tiled_right_styles);
5271 free_focus_styles (style_set->maximized_and_shaded_styles);
5272 free_focus_styles (style_set->tiled_left_and_shaded_styles);
5273 free_focus_styles (style_set->tiled_right_and_shaded_styles);
5274
5275 if (style_set->parent)
5276 meta_frame_style_set_unref (style_set->parent);
5277
5278 DEBUG_FILL_STRUCT (style_set)memset ((style_set), 0xef, sizeof (*(style_set)));
5279 g_free (style_set);
5280 }
5281}
5282
5283static MetaFrameStyle*
5284get_style (MetaFrameStyleSet *style_set,
5285 MetaFrameState state,
5286 MetaFrameResize resize,
5287 MetaFrameFocus focus)
5288{
5289 MetaFrameStyle *style;
5290
5291 style = NULL((void*)0);
5292
5293 switch (state)
5294 {
5295 case META_FRAME_STATE_NORMAL:
5296 case META_FRAME_STATE_SHADED:
5297 {
5298 if (state == META_FRAME_STATE_SHADED)
5299 style = style_set->shaded_styles[resize][focus];
5300 else
5301 style = style_set->normal_styles[resize][focus];
5302
5303 /* Try parent if we failed here */
5304 if (style == NULL((void*)0) && style_set->parent)
5305 style = get_style (style_set->parent, state, resize, focus);
5306
5307 /* Allow people to omit the vert/horz/none resize modes */
5308 if (style == NULL((void*)0) &&
5309 resize != META_FRAME_RESIZE_BOTH)
5310 style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
5311 }
5312 break;
5313 default:
5314 {
5315 MetaFrameStyle **styles;
5316
5317 styles = NULL((void*)0);
5318
5319 switch (state)
5320 {
5321 case META_FRAME_STATE_MAXIMIZED:
5322 styles = style_set->maximized_styles;
5323 break;
5324 case META_FRAME_STATE_TILED_LEFT:
5325 styles = style_set->tiled_left_styles;
5326 break;
5327 case META_FRAME_STATE_TILED_RIGHT:
5328 styles = style_set->tiled_right_styles;
5329 break;
5330 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
5331 styles = style_set->maximized_and_shaded_styles;
5332 break;
5333 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
5334 styles = style_set->tiled_left_and_shaded_styles;
5335 break;
5336 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
5337 styles = style_set->tiled_right_and_shaded_styles;
5338 break;
5339 case META_FRAME_STATE_NORMAL:
5340 case META_FRAME_STATE_SHADED:
5341 case META_FRAME_STATE_LAST:
5342 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5342, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5343 break;
5344 }
5345
5346 style = styles[focus];
5347
5348 /* Tiled states are optional, try falling back to non-tiled states */
5349 if (style == NULL((void*)0))
5350 {
5351 if (state == META_FRAME_STATE_TILED_LEFT ||
5352 state == META_FRAME_STATE_TILED_RIGHT)
5353 style = get_style (style_set, META_FRAME_STATE_NORMAL,
5354 resize, focus);
5355 else if (state == META_FRAME_STATE_TILED_LEFT_AND_SHADED ||
5356 state == META_FRAME_STATE_TILED_RIGHT_AND_SHADED)
5357 style = get_style (style_set, META_FRAME_STATE_SHADED,
5358 resize, focus);
5359 }
5360
5361 /* Try parent if we failed here */
5362 if (style == NULL((void*)0) && style_set->parent)
5363 style = get_style (style_set->parent, state, resize, focus);
5364 }
5365 }
5366
5367 return style;
5368}
5369
5370static gboolean
5371check_state (MetaFrameStyleSet *style_set,
5372 MetaFrameState state,
5373 GError **error)
5374{
5375 int i;
5376
5377 for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
5378 {
5379 if (get_style (style_set, state,
5380 META_FRAME_RESIZE_NONE, i) == NULL((void*)0))
5381 {
5382 /* Translators: This error occurs when a <frame> tag is missing
5383 * in theme XML. The "<frame ...>" is intended as a noun phrase,
5384 * and the "missing" qualifies it. You should translate "whatever".
5385 */
5386 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5387 META_THEME_ERROR_FAILED,
5388 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5389 meta_frame_state_to_string (state),
5390 meta_frame_resize_to_string (META_FRAME_RESIZE_NONE),
5391 meta_frame_focus_to_string (i));
5392 return FALSE(0);
5393 }
5394 }
5395
5396 return TRUE(!(0));
5397}
5398
5399gboolean
5400meta_frame_style_set_validate (MetaFrameStyleSet *style_set,
5401 GError **error)
5402{
5403 int i, j;
5404
5405 g_return_val_if_fail (style_set != NULL, FALSE)do { if ((style_set != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "style_set != NULL"); return
((0)); } } while (0)
;
5406
5407 for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
5408 for (j = 0; j < META_FRAME_FOCUS_LAST; j++)
5409 if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL((void*)0))
5410 {
5411 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")),
5412 META_THEME_ERROR_FAILED,
5413 _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>")((char *) g_dgettext ("marco", "Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
))
,
5414 meta_frame_state_to_string (META_FRAME_STATE_NORMAL),
5415 meta_frame_resize_to_string (i),
5416 meta_frame_focus_to_string (j));
5417 return FALSE(0);
5418 }
5419
5420 if (!check_state (style_set, META_FRAME_STATE_SHADED, error))
5421 return FALSE(0);
5422
5423 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error))
5424 return FALSE(0);
5425
5426 if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error))
5427 return FALSE(0);
5428
5429 return TRUE(!(0));
5430}
5431
5432MetaTheme*
5433meta_theme_get_current (void)
5434{
5435 return meta_current_theme;
5436}
5437
5438void
5439meta_theme_set_current (const char *name,
5440 gboolean force_reload)
5441{
5442 MetaTheme *new_theme;
5443 GError *err;
5444
5445 meta_topicmeta_topic_real (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name);
5446
5447 if (!force_reload &&
5448 meta_current_theme &&
5449 strcmp (name, meta_current_theme->name) == 0)
5450 return;
5451
5452 err = NULL((void*)0);
5453 new_theme = meta_theme_load (name, &err);
5454
5455 if (new_theme == NULL((void*)0))
5456 {
5457 meta_warning (_("Failed to load theme \"%s\": %s\n")((char *) g_dgettext ("marco", "Failed to load theme \"%s\": %s\n"
))
,
5458 name, err->message);
5459 g_error_free (err);
5460 }
5461 else
5462 {
5463 if (meta_current_theme)
5464 meta_theme_free (meta_current_theme);
5465
5466 meta_current_theme = new_theme;
5467
5468 meta_topicmeta_topic_real (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name);
5469 }
5470}
5471
5472MetaTheme*
5473meta_theme_new (void)
5474{
5475 MetaTheme *theme;
5476
5477 theme = g_new0 (MetaTheme, 1)((MetaTheme *) g_malloc0_n ((1), sizeof (MetaTheme)));
5478
5479 theme->images_by_filename =
5480 g_hash_table_new_full (g_str_hash,
5481 g_str_equal,
5482 g_free,
5483 g_object_unref);
5484
5485 theme->layouts_by_name =
5486 g_hash_table_new_full (g_str_hash,
5487 g_str_equal,
5488 g_free,
5489 (GDestroyNotify) meta_frame_layout_unref);
5490
5491 theme->draw_op_lists_by_name =
5492 g_hash_table_new_full (g_str_hash,
5493 g_str_equal,
5494 g_free,
5495 (GDestroyNotify) meta_draw_op_list_unref);
5496
5497 theme->styles_by_name =
5498 g_hash_table_new_full (g_str_hash,
5499 g_str_equal,
5500 g_free,
5501 (GDestroyNotify) meta_frame_style_unref);
5502
5503 theme->style_sets_by_name =
5504 g_hash_table_new_full (g_str_hash,
5505 g_str_equal,
5506 g_free,
5507 (GDestroyNotify) meta_frame_style_set_unref);
5508
5509 /* Create our variable quarks so we can look up variables without
5510 having to strcmp for the names */
5511 theme->quark_width = g_quark_from_static_string ("width");
5512 theme->quark_height = g_quark_from_static_string ("height");
5513 theme->quark_object_width = g_quark_from_static_string ("object_width");
5514 theme->quark_object_height = g_quark_from_static_string ("object_height");
5515 theme->quark_left_width = g_quark_from_static_string ("left_width");
5516 theme->quark_right_width = g_quark_from_static_string ("right_width");
5517 theme->quark_top_height = g_quark_from_static_string ("top_height");
5518 theme->quark_bottom_height = g_quark_from_static_string ("bottom_height");
5519 theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width");
5520 theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height");
5521 theme->quark_icon_width = g_quark_from_static_string ("icon_width");
5522 theme->quark_icon_height = g_quark_from_static_string ("icon_height");
5523 theme->quark_title_width = g_quark_from_static_string ("title_width");
5524 theme->quark_title_height = g_quark_from_static_string ("title_height");
5525 theme->quark_frame_x_center = g_quark_from_static_string ("frame_x_center");
5526 theme->quark_frame_y_center = g_quark_from_static_string ("frame_y_center");
5527 return theme;
5528}
5529
5530void
5531meta_theme_free (MetaTheme *theme)
5532{
5533 int i;
5534
5535 g_return_if_fail (theme != NULL)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
; } } while (0)
;
5536
5537 g_free (theme->name);
5538 g_free (theme->dirname);
5539 g_free (theme->filename);
5540 g_free (theme->readable_name);
5541 g_free (theme->date);
5542 g_free (theme->description);
5543 g_free (theme->author);
5544 g_free (theme->copyright);
5545
5546 /* be more careful when destroying the theme hash tables,
5547 since they are only constructed as needed, and may be NULL. */
5548 if (theme->integer_constants)
5549 g_hash_table_destroy (theme->integer_constants);
5550 if (theme->images_by_filename)
5551 g_hash_table_destroy (theme->images_by_filename);
5552 if (theme->layouts_by_name)
5553 g_hash_table_destroy (theme->layouts_by_name);
5554 if (theme->draw_op_lists_by_name)
5555 g_hash_table_destroy (theme->draw_op_lists_by_name);
5556 if (theme->styles_by_name)
5557 g_hash_table_destroy (theme->styles_by_name);
5558 if (theme->style_sets_by_name)
5559 g_hash_table_destroy (theme->style_sets_by_name);
5560
5561 for (i = 0; i < META_FRAME_TYPE_LAST; i++)
5562 if (theme->style_sets_by_type[i])
5563 meta_frame_style_set_unref (theme->style_sets_by_type[i]);
5564
5565 DEBUG_FILL_STRUCT (theme)memset ((theme), 0xef, sizeof (*(theme)));
5566 g_free (theme);
5567}
5568
5569gboolean
5570meta_theme_validate (MetaTheme *theme,
5571 GError **error)
5572{
5573 int i;
5574
5575 g_return_val_if_fail (theme != NULL, FALSE)do { if ((theme != ((void*)0))) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "theme != NULL"); return
((0)); } } while (0)
;
5576
5577 /* FIXME what else should be checked? */
5578
5579 g_assert (theme->name)do { if (theme->name) ; else g_assertion_message_expr ("marco"
, "ui/theme.c", 5579, ((const char*) (__func__)), "theme->name"
); } while (0)
;
5580
5581 if (theme->readable_name == NULL((void*)0))
5582 {
5583 /* Translators: This error means that a necessary XML tag (whose name
5584 * is given in angle brackets) was not found in a given theme (whose
5585 * name is given second, in quotation marks).
5586 */
5587 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5588 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "name", theme->name);
5589 return FALSE(0);
5590 }
5591
5592 if (theme->author == NULL((void*)0))
5593 {
5594 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5595 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "author", theme->name);
5596 return FALSE(0);
5597 }
5598
5599 if (theme->date == NULL((void*)0))
5600 {
5601 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5602 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "date", theme->name);
5603 return FALSE(0);
5604 }
5605
5606 if (theme->description == NULL((void*)0))
5607 {
5608 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5609 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "description", theme->name);
5610 return FALSE(0);
5611 }
5612
5613 if (theme->copyright == NULL((void*)0))
5614 {
5615 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5616 _("No <%s> set for theme \"%s\"")((char *) g_dgettext ("marco", "No <%s> set for theme \"%s\""
))
, "copyright", theme->name);
5617 return FALSE(0);
5618 }
5619
5620 for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
5621 if (i != (int)META_FRAME_TYPE_ATTACHED && theme->style_sets_by_type[i] == NULL((void*)0))
5622 {
5623 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
5624 _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element")((char *) g_dgettext ("marco", "No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"
))
,
5625 meta_frame_type_to_string (i),
5626 theme->name,
5627 meta_frame_type_to_string (i));
5628
5629 return FALSE(0);
5630 }
5631
5632 return TRUE(!(0));
5633}
5634
5635GdkPixbuf*
5636meta_theme_load_image (MetaTheme *theme,
5637 const char *filename,
5638 guint size_of_theme_icons,
5639 GError **error)
5640{
5641 GdkPixbuf *pixbuf;
5642 int scale;
5643
5644 pixbuf = g_hash_table_lookup (theme->images_by_filename,
5645 filename);
5646
5647 scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
5648
5649 if (pixbuf == NULL((void*)0))
5650 {
5651
5652 if (g_str_has_prefix (filename, "theme:")(__builtin_constant_p ("theme:")? __extension__ ({ const char
* const __str = (filename); const char * const __prefix = ("theme:"
); gboolean __result = (0); if (__str == ((void*)0) || __prefix
== ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix
))); if (__str_len >= __prefix_len) __result = memcmp (((__str
) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0
; } __result; }) : (g_str_has_prefix) (filename, "theme:") )
&&
5653 META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES)(theme->format_version >= 2))
5654 {
5655 pixbuf = gtk_icon_theme_load_icon_for_scale (
5656 gtk_icon_theme_get_default (),
5657 filename+6,
5658 size_of_theme_icons,
5659 scale,
5660 0,
5661 error);
5662 if (pixbuf == NULL((void*)0)) return NULL((void*)0);
5663 }
5664 else
5665 {
5666 char *full_path;
5667 full_path = g_build_filename (theme->dirname, filename, NULL((void*)0));
5668
5669 gint width, height;
5670
5671 if (gdk_pixbuf_get_file_info (full_path, &width, &height) == NULL((void*)0))
5672 {
5673 g_free (full_path);
5674 return NULL((void*)0);
5675 }
5676
5677 width *= scale;
5678 height *= scale;
5679
5680 pixbuf = gdk_pixbuf_new_from_file_at_size (full_path, width, height, error);
5681
5682 if (pixbuf == NULL((void*)0))
5683 {
5684 g_free (full_path);
5685 return NULL((void*)0);
5686 }
5687
5688 g_free (full_path);
5689 }
5690 g_hash_table_replace (theme->images_by_filename,
5691 g_strdup (filename)g_strdup_inline (filename),
5692 pixbuf);
5693 }
5694
5695 g_assert (pixbuf)do { if (pixbuf) ; else g_assertion_message_expr ("marco", "ui/theme.c"
, 5695, ((const char*) (__func__)), "pixbuf"); } while (0)
;
5696
5697 g_object_ref (G_OBJECT (pixbuf))((__typeof__ (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
))))))) (g_object_ref) (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((pixbuf)), (((GType) ((20) << (2)))
)))))))
;
5698
5699 return pixbuf;
5700}
5701
5702static MetaFrameStyle*
5703theme_get_style (MetaTheme *theme,
5704 MetaFrameType type,
5705 MetaFrameFlags flags)
5706{
5707 MetaFrameState state;
5708 MetaFrameResize resize;
5709 MetaFrameFocus focus;
5710 MetaFrameStyle *style;
5711 MetaFrameStyleSet *style_set;
5712
5713 style_set = theme->style_sets_by_type[type];
5714
5715 if (style_set == NULL((void*)0) && type == META_FRAME_TYPE_ATTACHED)
5716 style_set = theme->style_sets_by_type[META_FRAME_TYPE_BORDER];
5717
5718 /* Right now the parser forces a style set for all other types,
5719 * but this fallback code is here in case I take that out.
5720 */
5721 if (style_set == NULL((void*)0))
5722 style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL];
5723 if (style_set == NULL((void*)0))
5724 return NULL((void*)0);
5725
5726 switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED | META_FRAME_TILED_LEFT | META_FRAME_TILED_RIGHT))
5727 {
5728 case 0:
5729 state = META_FRAME_STATE_NORMAL;
5730 break;
5731 case META_FRAME_MAXIMIZED:
5732 state = META_FRAME_STATE_MAXIMIZED;
5733 break;
5734 case META_FRAME_TILED_LEFT:
5735 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_LEFT):
5736 state = META_FRAME_STATE_TILED_LEFT;
5737 break;
5738 case META_FRAME_TILED_RIGHT:
5739 case (META_FRAME_MAXIMIZED | META_FRAME_TILED_RIGHT):
5740 state = META_FRAME_STATE_TILED_RIGHT;
5741 break;
5742 case META_FRAME_SHADED:
5743 state = META_FRAME_STATE_SHADED;
5744 break;
5745 case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
5746 state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
5747 break;
5748 case (META_FRAME_TILED_LEFT | META_FRAME_SHADED):
5749 state = META_FRAME_STATE_TILED_LEFT_AND_SHADED;
5750 break;
5751 case (META_FRAME_TILED_RIGHT | META_FRAME_SHADED):
5752 state = META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
5753 break;
5754 default:
5755 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5755, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5756 state = META_FRAME_STATE_LAST; /* compiler */
5757 break;
5758 }
5759
5760 switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
5761 {
5762 case 0:
5763 resize = META_FRAME_RESIZE_NONE;
5764 break;
5765 case META_FRAME_ALLOWS_VERTICAL_RESIZE:
5766 resize = META_FRAME_RESIZE_VERTICAL;
5767 break;
5768 case META_FRAME_ALLOWS_HORIZONTAL_RESIZE:
5769 resize = META_FRAME_RESIZE_HORIZONTAL;
5770 break;
5771 case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE):
5772 resize = META_FRAME_RESIZE_BOTH;
5773 break;
5774 default:
5775 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 5775, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
5776 resize = META_FRAME_RESIZE_LAST; /* compiler */
5777 break;
5778 }
5779
5780 /* re invert the styles used for focus/unfocussed while flashing a frame */
5781 if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
5782 || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
5783 focus = META_FRAME_FOCUS_YES;
5784 else
5785 focus = META_FRAME_FOCUS_NO;
5786
5787 style = get_style (style_set, state, resize, focus);
5788
5789 return style;
5790}
5791
5792MetaFrameStyle*
5793meta_theme_get_frame_style (MetaTheme *theme,
5794 MetaFrameType type,
5795 MetaFrameFlags flags)
5796{
5797 MetaFrameStyle *style;
5798
5799 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (((void*)0)); } } while (0)
;
5800
5801 style = theme_get_style (theme, type, flags);
5802
5803 return style;
5804}
5805
5806double
5807meta_theme_get_title_scale (MetaTheme *theme,
5808 MetaFrameType type,
5809 MetaFrameFlags flags)
5810{
5811 MetaFrameStyle *style;
5812
5813 g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return (1.0); } } while (0)
;
5814
5815 style = theme_get_style (theme, type, flags);
5816
5817 /* Parser is not supposed to allow this currently */
5818 if (style == NULL((void*)0))
5819 return 1.0;
5820
5821 return style->layout->title_scale;
5822}
5823
5824void
5825meta_theme_draw_frame (MetaTheme *theme,
5826 GtkStyleContext *style_gtk,
5827 cairo_t *cr,
5828 MetaFrameType type,
5829 MetaFrameFlags flags,
5830 int client_width,
5831 int client_height,
5832 PangoLayout *title_layout,
5833 int text_height,
5834 const MetaButtonLayout *button_layout,
5835 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5836 GdkPixbuf *mini_icon,
5837 GdkPixbuf *icon)
5838{
5839 MetaFrameGeometry fgeom;
5840 MetaFrameStyle *style;
5841
5842 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5843
5844 style = theme_get_style (theme, type, flags);
5845
5846 /* Parser is not supposed to allow this currently */
5847 if (style == NULL((void*)0))
5848 return;
5849
5850 meta_frame_layout_calc_geometry (style->layout,
5851 text_height,
5852 flags,
5853 client_width, client_height,
5854 button_layout,
5855 &fgeom,
5856 theme);
5857
5858 meta_frame_style_draw_with_style (style,
5859 style_gtk,
5860 cr,
5861 &fgeom,
5862 client_width, client_height,
5863 title_layout,
5864 text_height,
5865 button_states,
5866 mini_icon, icon);
5867}
5868
5869void
5870meta_theme_draw_frame_by_name (MetaTheme *theme,
5871 GtkWidget *widget,
5872 cairo_t *cr,
5873 const gchar *style_name,
5874 MetaFrameFlags flags,
5875 int client_width,
5876 int client_height,
5877 PangoLayout *title_layout,
5878 int text_height,
5879 const MetaButtonLayout *button_layout,
5880 MetaButtonState button_states[META_BUTTON_TYPE_LAST],
5881 GdkPixbuf *mini_icon,
5882 GdkPixbuf *icon)
5883{
5884 MetaFrameGeometry fgeom;
5885 MetaFrameStyle *style;
5886
5887 style = meta_theme_lookup_style (theme, style_name);
5888
5889 /* Parser is not supposed to allow this currently */
5890 if (style == NULL((void*)0))
5891 return;
5892
5893 meta_frame_layout_calc_geometry (style->layout,
5894 text_height,
5895 flags,
5896 client_width, client_height,
5897 button_layout,
5898 &fgeom,
5899 theme);
5900
5901 meta_frame_style_draw (style,
5902 widget,
5903 cr,
5904 &fgeom,
5905 client_width, client_height,
5906 title_layout,
5907 text_height,
5908 button_states,
5909 mini_icon, icon);
5910}
5911
5912void
5913meta_theme_get_frame_borders (MetaTheme *theme,
5914 MetaFrameType type,
5915 int text_height,
5916 MetaFrameFlags flags,
5917 MetaFrameBorders *borders)
5918{
5919 MetaFrameStyle *style;
5920
5921 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5922
5923 style = theme_get_style (theme, type, flags);
5924
5925 meta_frame_borders_clear (borders);
5926
5927 /* Parser is not supposed to allow this currently */
5928 if (style == NULL((void*)0))
5929 return;
5930
5931 meta_frame_layout_get_borders (style->layout,
5932 text_height,
5933 flags,
5934 borders);
5935}
5936
5937void
5938meta_theme_calc_geometry (MetaTheme *theme,
5939 MetaFrameType type,
5940 int text_height,
5941 MetaFrameFlags flags,
5942 int client_width,
5943 int client_height,
5944 const MetaButtonLayout *button_layout,
5945 MetaFrameGeometry *fgeom)
5946{
5947 MetaFrameStyle *style;
5948
5949 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("marco", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
5950
5951 style = theme_get_style (theme, type, flags);
5952
5953 /* Parser is not supposed to allow this currently */
5954 if (style == NULL((void*)0))
5955 return;
5956
5957 meta_frame_layout_calc_geometry (style->layout,
5958 text_height,
5959 flags,
5960 client_width, client_height,
5961 button_layout,
5962 fgeom,
5963 theme);
5964}
5965
5966MetaFrameLayout*
5967meta_theme_lookup_layout (MetaTheme *theme,
5968 const char *name)
5969{
5970 return g_hash_table_lookup (theme->layouts_by_name, name);
5971}
5972
5973void
5974meta_theme_insert_layout (MetaTheme *theme,
5975 const char *name,
5976 MetaFrameLayout *layout)
5977{
5978 meta_frame_layout_ref (layout);
5979 g_hash_table_replace (theme->layouts_by_name, g_strdup (name)g_strdup_inline (name), layout);
5980}
5981
5982MetaDrawOpList*
5983meta_theme_lookup_draw_op_list (MetaTheme *theme,
5984 const char *name)
5985{
5986 return g_hash_table_lookup (theme->draw_op_lists_by_name, name);
5987}
5988
5989void
5990meta_theme_insert_draw_op_list (MetaTheme *theme,
5991 const char *name,
5992 MetaDrawOpList *op_list)
5993{
5994 meta_draw_op_list_ref (op_list);
5995 g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name)g_strdup_inline (name), op_list);
5996}
5997
5998MetaFrameStyle*
5999meta_theme_lookup_style (MetaTheme *theme,
6000 const char *name)
6001{
6002 return g_hash_table_lookup (theme->styles_by_name, name);
6003}
6004
6005void
6006meta_theme_insert_style (MetaTheme *theme,
6007 const char *name,
6008 MetaFrameStyle *style)
6009{
6010 meta_frame_style_ref (style);
6011 g_hash_table_replace (theme->styles_by_name, g_strdup (name)g_strdup_inline (name), style);
6012}
6013
6014MetaFrameStyleSet*
6015meta_theme_lookup_style_set (MetaTheme *theme,
6016 const char *name)
6017{
6018 return g_hash_table_lookup (theme->style_sets_by_name, name);
6019}
6020
6021void
6022meta_theme_insert_style_set (MetaTheme *theme,
6023 const char *name,
6024 MetaFrameStyleSet *style_set)
6025{
6026 meta_frame_style_set_ref (style_set);
6027 g_hash_table_replace (theme->style_sets_by_name, g_strdup (name)g_strdup_inline (name), style_set);
6028}
6029
6030static gboolean
6031first_uppercase (const char *str)
6032{
6033 return g_ascii_isupper (*str)((g_ascii_table[(guchar) (*str)] & G_ASCII_UPPER) != 0);
6034}
6035
6036gboolean
6037meta_theme_define_int_constant (MetaTheme *theme,
6038 const char *name,
6039 int value,
6040 GError **error)
6041{
6042 if (theme->integer_constants == NULL((void*)0))
6043 theme->integer_constants = g_hash_table_new_full (g_str_hash,
6044 g_str_equal,
6045 g_free,
6046 NULL((void*)0));
6047
6048 if (!first_uppercase (name))
6049 {
6050 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6051 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6052 name);
6053 return FALSE(0);
6054 }
6055
6056 if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL((void*)0), NULL((void*)0)))
6057 {
6058 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6059 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6060 name);
6061
6062 return FALSE(0);
6063 }
6064
6065 g_hash_table_insert (theme->integer_constants,
6066 g_strdup (name)g_strdup_inline (name),
6067 GINT_TO_POINTER (value)((gpointer) (glong) (value)));
6068
6069 return TRUE(!(0));
6070}
6071
6072gboolean
6073meta_theme_lookup_int_constant (MetaTheme *theme,
6074 const char *name,
6075 int *value)
6076{
6077 gpointer old_value;
6078
6079 *value = 0;
6080
6081 if (theme->integer_constants == NULL((void*)0))
6082 return FALSE(0);
6083
6084 if (g_hash_table_lookup_extended (theme->integer_constants,
6085 name, NULL((void*)0), &old_value))
6086 {
6087 *value = GPOINTER_TO_INT (old_value)((gint) (glong) (old_value));
6088 return TRUE(!(0));
6089 }
6090 else
6091 {
6092 return FALSE(0);
6093 }
6094}
6095
6096gboolean
6097meta_theme_define_float_constant (MetaTheme *theme,
6098 const char *name,
6099 double value,
6100 GError **error)
6101{
6102 double *d;
6103
6104 if (theme->float_constants == NULL((void*)0))
6105 theme->float_constants = g_hash_table_new_full (g_str_hash,
6106 g_str_equal,
6107 g_free,
6108 g_free);
6109
6110 if (!first_uppercase (name))
6111 {
6112 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6113 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6114 name);
6115 return FALSE(0);
6116 }
6117
6118 if (g_hash_table_lookup_extended (theme->float_constants, name, NULL((void*)0), NULL((void*)0)))
6119 {
6120 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6121 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6122 name);
6123
6124 return FALSE(0);
6125 }
6126
6127 d = g_new (double, 1)((double *) g_malloc_n ((1), sizeof (double)));
6128 *d = value;
6129
6130 g_hash_table_insert (theme->float_constants,
6131 g_strdup (name)g_strdup_inline (name), d);
6132
6133 return TRUE(!(0));
6134}
6135
6136gboolean
6137meta_theme_lookup_float_constant (MetaTheme *theme,
6138 const char *name,
6139 double *value)
6140{
6141 double *d;
6142
6143 *value = 0.0;
6144
6145 if (theme->float_constants == NULL((void*)0))
6146 return FALSE(0);
6147
6148 d = g_hash_table_lookup (theme->float_constants, name);
6149
6150 if (d)
6151 {
6152 *value = *d;
6153 return TRUE(!(0));
6154 }
6155 else
6156 {
6157 return FALSE(0);
6158 }
6159}
6160
6161gboolean
6162meta_theme_define_color_constant (MetaTheme *theme,
6163 const char *name,
6164 const char *value,
6165 GError **error)
6166{
6167 if (theme->color_constants == NULL((void*)0))
6168 theme->color_constants = g_hash_table_new_full (g_str_hash,
6169 g_str_equal,
6170 g_free,
6171 NULL((void*)0));
6172
6173 if (!first_uppercase (name))
6174 {
6175 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6176 _("User-defined constants must begin with a capital letter; \"%s\" does not")((char *) g_dgettext ("marco", "User-defined constants must begin with a capital letter; \"%s\" does not"
))
,
6177 name);
6178 return FALSE(0);
6179 }
6180
6181 if (g_hash_table_lookup_extended (theme->color_constants, name, NULL((void*)0), NULL((void*)0)))
6182 {
6183 g_set_error (error, META_THEME_ERROR(g_quark_from_static_string ("meta-theme-error")), META_THEME_ERROR_FAILED,
6184 _("Constant \"%s\" has already been defined")((char *) g_dgettext ("marco", "Constant \"%s\" has already been defined"
))
,
6185 name);
6186
6187 return FALSE(0);
6188 }
6189
6190 g_hash_table_insert (theme->color_constants,
6191 g_strdup (name)g_strdup_inline (name),
6192 g_strdup (value)g_strdup_inline (value));
6193
6194 return TRUE(!(0));
6195}
6196
6197/**
6198 * Looks up a colour constant.
6199 *
6200 * \param theme the theme containing the constant
6201 * \param name the name of the constant
6202 * \param value [out] the string representation of the colour, or NULL if it
6203 * doesn't exist
6204 * \return TRUE if it exists, FALSE otherwise
6205 */
6206gboolean
6207meta_theme_lookup_color_constant (MetaTheme *theme,
6208 const char *name,
6209 char **value)
6210{
6211 char *result;
6212
6213 *value = NULL((void*)0);
6214
6215 if (theme->color_constants == NULL((void*)0))
6216 return FALSE(0);
6217
6218 result = g_hash_table_lookup (theme->color_constants, name);
6219
6220 if (result)
6221 {
6222 *value = result;
6223 return TRUE(!(0));
6224 }
6225 else
6226 {
6227 return FALSE(0);
6228 }
6229}
6230
6231PangoFontDescription*
6232meta_gtk_widget_get_font_desc (GtkWidget *widget,
6233 double scale,
6234 const PangoFontDescription *override)
6235{
6236 PangoFontDescription *font_desc;
6237 gint font_size;
6238
6239 GtkStyleContext *style = gtk_widget_get_style_context (widget);
6240 GtkStateFlags state = gtk_widget_get_state_flags (widget);
6241 gtk_style_context_get(style, state, GTK_STYLE_PROPERTY_FONT"font", &font_desc, NULL((void*)0));
6242
6243 if (override)
6244 pango_font_description_merge (font_desc, override, TRUE(!(0)));
6245
6246 font_size = pango_font_description_get_size (font_desc);
6247 pango_font_description_set_size (font_desc,
6248 MAX ((gint) (scale * (double) font_size), 1)((((gint) (scale * (double) font_size)) > (1)) ? ((gint) (
scale * (double) font_size)) : (1))
);
6249
6250 return font_desc;
6251}
6252
6253/**
6254 * Returns the height of the letters in a particular font.
6255 *
6256 * \param font_desc the font
6257 * \param context the context of the font
6258 * \return the height of the letters
6259 */
6260int
6261meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
6262 PangoContext *context)
6263{
6264 PangoFontMetrics *metrics;
6265 PangoLanguage *lang;
6266 int retval;
6267
6268 lang = pango_context_get_language (context);
6269 metrics = pango_context_get_metrics (context, font_desc, lang);
6270
6271 retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
6272 pango_font_metrics_get_descent (metrics))(((int)(pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent
(metrics)) + 512) >> 10)
;
6273
6274 pango_font_metrics_unref (metrics);
6275
6276 return retval;
6277}
6278
6279MetaGtkColorComponent
6280meta_color_component_from_string (const char *str)
6281{
6282 if (strcmp ("fg", str) == 0)
6283 return META_GTK_COLOR_FG;
6284 else if (strcmp ("bg", str) == 0)
6285 return META_GTK_COLOR_BG;
6286 else if (strcmp ("light", str) == 0)
6287 return META_GTK_COLOR_LIGHT;
6288 else if (strcmp ("dark", str) == 0)
6289 return META_GTK_COLOR_DARK;
6290 else if (strcmp ("mid", str) == 0)
6291 return META_GTK_COLOR_MID;
6292 else if (strcmp ("text", str) == 0)
6293 return META_GTK_COLOR_TEXT;
6294 else if (strcmp ("base", str) == 0)
6295 return META_GTK_COLOR_BASE;
6296 else if (strcmp ("text_aa", str) == 0)
6297 return META_GTK_COLOR_TEXT_AA;
6298 else
6299 return META_GTK_COLOR_LAST;
6300}
6301
6302const char*
6303meta_color_component_to_string (MetaGtkColorComponent component)
6304{
6305 switch (component)
6306 {
6307 case META_GTK_COLOR_FG:
6308 return "fg";
6309 case META_GTK_COLOR_BG:
6310 return "bg";
6311 case META_GTK_COLOR_LIGHT:
6312 return "light";
6313 case META_GTK_COLOR_DARK:
6314 return "dark";
6315 case META_GTK_COLOR_MID:
6316 return "mid";
6317 case META_GTK_COLOR_TEXT:
6318 return "text";
6319 case META_GTK_COLOR_BASE:
6320 return "base";
6321 case META_GTK_COLOR_TEXT_AA:
6322 return "text_aa";
6323 case META_GTK_COLOR_LAST:
6324 break;
6325 }
6326
6327 return "<unknown>";
6328}
6329
6330MetaButtonState
6331meta_button_state_from_string (const char *str)
6332{
6333 if (strcmp ("normal", str) == 0)
6334 return META_BUTTON_STATE_NORMAL;
6335 else if (strcmp ("pressed", str) == 0)
6336 return META_BUTTON_STATE_PRESSED;
6337 else if (strcmp ("prelight", str) == 0)
6338 return META_BUTTON_STATE_PRELIGHT;
6339 else
6340 return META_BUTTON_STATE_LAST;
6341}
6342
6343const char*
6344meta_button_state_to_string (MetaButtonState state)
6345{
6346 switch (state)
6347 {
6348 case META_BUTTON_STATE_NORMAL:
6349 return "normal";
6350 case META_BUTTON_STATE_PRESSED:
6351 return "pressed";
6352 case META_BUTTON_STATE_PRELIGHT:
6353 return "prelight";
6354 case META_BUTTON_STATE_LAST:
6355 break;
6356 }
6357
6358 return "<unknown>";
6359}
6360
6361MetaButtonType
6362meta_button_type_from_string (const char *str, MetaTheme *theme)
6363{
6364 if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS)(theme->format_version >= 2))
6365 {
6366 if (strcmp ("shade", str) == 0)
6367 return META_BUTTON_TYPE_SHADE;
6368 else if (strcmp ("above", str) == 0)
6369 return META_BUTTON_TYPE_ABOVE;
6370 else if (strcmp ("stick", str) == 0)
6371 return META_BUTTON_TYPE_STICK;
6372 else if (strcmp ("unshade", str) == 0)
6373 return META_BUTTON_TYPE_UNSHADE;
6374 else if (strcmp ("unabove", str) == 0)
6375 return META_BUTTON_TYPE_UNABOVE;
6376 else if (strcmp ("unstick", str) == 0)
6377 return META_BUTTON_TYPE_UNSTICK;
6378 }
6379
6380 if (strcmp ("close", str) == 0)
6381 return META_BUTTON_TYPE_CLOSE;
6382 else if (strcmp ("maximize", str) == 0)
6383 return META_BUTTON_TYPE_MAXIMIZE;
6384 else if (strcmp ("minimize", str) == 0)
6385 return META_BUTTON_TYPE_MINIMIZE;
6386 else if (strcmp ("menu", str) == 0)
6387 return META_BUTTON_TYPE_MENU;
6388 else if (strcmp ("appmenu", str) == 0)
6389 return META_BUTTON_TYPE_APPMENU;
6390 else if (strcmp ("left_left_background", str) == 0)
6391 return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
6392 else if (strcmp ("left_middle_background", str) == 0)
6393 return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
6394 else if (strcmp ("left_right_background", str) == 0)
6395 return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
6396 else if (strcmp ("left_single_background", str) == 0)
6397 return META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND;
6398 else if (strcmp ("right_left_background", str) == 0)
6399 return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
6400 else if (strcmp ("right_middle_background", str) == 0)
6401 return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
6402 else if (strcmp ("right_right_background", str) == 0)
6403 return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
6404 else if (strcmp ("right_single_background", str) == 0)
6405 return META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND;
6406 else
6407 return META_BUTTON_TYPE_LAST;
6408}
6409
6410const char*
6411meta_button_type_to_string (MetaButtonType type)
6412{
6413 switch (type)
6414 {
6415 case META_BUTTON_TYPE_CLOSE:
6416 return "close";
6417 case META_BUTTON_TYPE_MAXIMIZE:
6418 return "maximize";
6419 case META_BUTTON_TYPE_MINIMIZE:
6420 return "minimize";
6421 case META_BUTTON_TYPE_SHADE:
6422 return "shade";
6423 case META_BUTTON_TYPE_ABOVE:
6424 return "above";
6425 case META_BUTTON_TYPE_STICK:
6426 return "stick";
6427 case META_BUTTON_TYPE_UNSHADE:
6428 return "unshade";
6429 case META_BUTTON_TYPE_UNABOVE:
6430 return "unabove";
6431 case META_BUTTON_TYPE_UNSTICK:
6432 return "unstick";
6433 case META_BUTTON_TYPE_MENU:
6434 return "menu";
6435 case META_BUTTON_TYPE_APPMENU:
6436 return "appmenu";
6437 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
6438 return "left_left_background";
6439 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
6440 return "left_middle_background";
6441 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
6442 return "left_right_background";
6443 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
6444 return "left_single_background";
6445 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
6446 return "right_left_background";
6447 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
6448 return "right_middle_background";
6449 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
6450 return "right_right_background";
6451 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
6452 return "right_single_background";
6453 case META_BUTTON_TYPE_LAST:
6454 break;
6455 }
6456
6457 return "<unknown>";
6458}
6459
6460MetaFramePiece
6461meta_frame_piece_from_string (const char *str)
6462{
6463 if (strcmp ("entire_background", str) == 0)
6464 return META_FRAME_PIECE_ENTIRE_BACKGROUND;
6465 else if (strcmp ("titlebar", str) == 0)
6466 return META_FRAME_PIECE_TITLEBAR;
6467 else if (strcmp ("titlebar_middle", str) == 0)
6468 return META_FRAME_PIECE_TITLEBAR_MIDDLE;
6469 else if (strcmp ("left_titlebar_edge", str) == 0)
6470 return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE;
6471 else if (strcmp ("right_titlebar_edge", str) == 0)
6472 return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE;
6473 else if (strcmp ("top_titlebar_edge", str) == 0)
6474 return META_FRAME_PIECE_TOP_TITLEBAR_EDGE;
6475 else if (strcmp ("bottom_titlebar_edge", str) == 0)
6476 return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE;
6477 else if (strcmp ("title", str) == 0)
6478 return META_FRAME_PIECE_TITLE;
6479 else if (strcmp ("left_edge", str) == 0)
6480 return META_FRAME_PIECE_LEFT_EDGE;
6481 else if (strcmp ("right_edge", str) == 0)
6482 return META_FRAME_PIECE_RIGHT_EDGE;
6483 else if (strcmp ("bottom_edge", str) == 0)
6484 return META_FRAME_PIECE_BOTTOM_EDGE;
6485 else if (strcmp ("overlay", str) == 0)
6486 return META_FRAME_PIECE_OVERLAY;
6487 else
6488 return META_FRAME_PIECE_LAST;
6489}
6490
6491const char*
6492meta_frame_piece_to_string (MetaFramePiece piece)
6493{
6494 switch (piece)
6495 {
6496 case META_FRAME_PIECE_ENTIRE_BACKGROUND:
6497 return "entire_background";
6498 case META_FRAME_PIECE_TITLEBAR:
6499 return "titlebar";
6500 case META_FRAME_PIECE_TITLEBAR_MIDDLE:
6501 return "titlebar_middle";
6502 case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
6503 return "left_titlebar_edge";
6504 case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
6505 return "right_titlebar_edge";
6506 case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
6507 return "top_titlebar_edge";
6508 case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
6509 return "bottom_titlebar_edge";
6510 case META_FRAME_PIECE_TITLE:
6511 return "title";
6512 case META_FRAME_PIECE_LEFT_EDGE:
6513 return "left_edge";
6514 case META_FRAME_PIECE_RIGHT_EDGE:
6515 return "right_edge";
6516 case META_FRAME_PIECE_BOTTOM_EDGE:
6517 return "bottom_edge";
6518 case META_FRAME_PIECE_OVERLAY:
6519 return "overlay";
6520 case META_FRAME_PIECE_LAST:
6521 break;
6522 }
6523
6524 return "<unknown>";
6525}
6526
6527MetaFrameState
6528meta_frame_state_from_string (const char *str)
6529{
6530 if (strcmp ("normal", str) == 0)
6531 return META_FRAME_STATE_NORMAL;
6532 else if (strcmp ("maximized", str) == 0)
6533 return META_FRAME_STATE_MAXIMIZED;
6534 else if (strcmp ("tiled_left", str) == 0)
6535 return META_FRAME_STATE_TILED_LEFT;
6536 else if (strcmp ("tiled_right", str) == 0)
6537 return META_FRAME_STATE_TILED_RIGHT;
6538 else if (strcmp ("shaded", str) == 0)
6539 return META_FRAME_STATE_SHADED;
6540 else if (strcmp ("maximized_and_shaded", str) == 0)
6541 return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
6542 else if (strcmp ("tiled_left_and_shaded", str) == 0)
6543 return META_FRAME_STATE_TILED_LEFT_AND_SHADED;
6544 else if (strcmp ("tiled_right_and_shaded", str) == 0)
6545 return META_FRAME_STATE_TILED_RIGHT_AND_SHADED;
6546 else
6547 return META_FRAME_STATE_LAST;
6548}
6549
6550const char*
6551meta_frame_state_to_string (MetaFrameState state)
6552{
6553 switch (state)
6554 {
6555 case META_FRAME_STATE_NORMAL:
6556 return "normal";
6557 case META_FRAME_STATE_MAXIMIZED:
6558 return "maximized";
6559 case META_FRAME_STATE_TILED_LEFT:
6560 return "tiled_left";
6561 case META_FRAME_STATE_TILED_RIGHT:
6562 return "tiled_right";
6563 case META_FRAME_STATE_SHADED:
6564 return "shaded";
6565 case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
6566 return "maximized_and_shaded";
6567 case META_FRAME_STATE_TILED_LEFT_AND_SHADED:
6568 return "tiled_left_and_shaded";
6569 case META_FRAME_STATE_TILED_RIGHT_AND_SHADED:
6570 return "tiled_right_and_shaded";
6571 case META_FRAME_STATE_LAST:
6572 break;
6573 }
6574
6575 return "<unknown>";
6576}
6577
6578MetaFrameResize
6579meta_frame_resize_from_string (const char *str)
6580{
6581 if (strcmp ("none", str) == 0)
6582 return META_FRAME_RESIZE_NONE;
6583 else if (strcmp ("vertical", str) == 0)
6584 return META_FRAME_RESIZE_VERTICAL;
6585 else if (strcmp ("horizontal", str) == 0)
6586 return META_FRAME_RESIZE_HORIZONTAL;
6587 else if (strcmp ("both", str) == 0)
6588 return META_FRAME_RESIZE_BOTH;
6589 else
6590 return META_FRAME_RESIZE_LAST;
6591}
6592
6593const char*
6594meta_frame_resize_to_string (MetaFrameResize resize)
6595{
6596 switch (resize)
6597 {
6598 case META_FRAME_RESIZE_NONE:
6599 return "none";
6600 case META_FRAME_RESIZE_VERTICAL:
6601 return "vertical";
6602 case META_FRAME_RESIZE_HORIZONTAL:
6603 return "horizontal";
6604 case META_FRAME_RESIZE_BOTH:
6605 return "both";
6606 case META_FRAME_RESIZE_LAST:
6607 break;
6608 }
6609
6610 return "<unknown>";
6611}
6612
6613MetaFrameFocus
6614meta_frame_focus_from_string (const char *str)
6615{
6616 if (strcmp ("no", str) == 0)
6617 return META_FRAME_FOCUS_NO;
6618 else if (strcmp ("yes", str) == 0)
6619 return META_FRAME_FOCUS_YES;
6620 else
6621 return META_FRAME_FOCUS_LAST;
6622}
6623
6624const char*
6625meta_frame_focus_to_string (MetaFrameFocus focus)
6626{
6627 switch (focus)
6628 {
6629 case META_FRAME_FOCUS_NO:
6630 return "no";
6631 case META_FRAME_FOCUS_YES:
6632 return "yes";
6633 case META_FRAME_FOCUS_LAST:
6634 break;
6635 }
6636
6637 return "<unknown>";
6638}
6639
6640MetaFrameType
6641meta_frame_type_from_string (const char *str)
6642{
6643 if (strcmp ("normal", str) == 0)
6644 return META_FRAME_TYPE_NORMAL;
6645 else if (strcmp ("dialog", str) == 0)
6646 return META_FRAME_TYPE_DIALOG;
6647 else if (strcmp ("modal_dialog", str) == 0)
6648 return META_FRAME_TYPE_MODAL_DIALOG;
6649 else if (strcmp ("utility", str) == 0)
6650 return META_FRAME_TYPE_UTILITY;
6651 else if (strcmp ("menu", str) == 0)
6652 return META_FRAME_TYPE_MENU;
6653 else if (strcmp ("border", str) == 0)
6654 return META_FRAME_TYPE_BORDER;
6655 else if (strcmp ("attached", str) == 0)
6656 return META_FRAME_TYPE_ATTACHED;
6657#if 0
6658 else if (strcmp ("toolbar", str) == 0)
6659 return META_FRAME_TYPE_TOOLBAR;
6660#endif
6661 else
6662 return META_FRAME_TYPE_LAST;
6663}
6664
6665const char*
6666meta_frame_type_to_string (MetaFrameType type)
6667{
6668 switch (type)
6669 {
6670 case META_FRAME_TYPE_NORMAL:
6671 return "normal";
6672 case META_FRAME_TYPE_DIALOG:
6673 return "dialog";
6674 case META_FRAME_TYPE_MODAL_DIALOG:
6675 return "modal_dialog";
6676 case META_FRAME_TYPE_UTILITY:
6677 return "utility";
6678 case META_FRAME_TYPE_MENU:
6679 return "menu";
6680 case META_FRAME_TYPE_BORDER:
6681 return "border";
6682 case META_FRAME_TYPE_ATTACHED:
6683 return "attached";
6684#if 0
6685 case META_FRAME_TYPE_TOOLBAR:
6686 return "toolbar";
6687#endif
6688 case META_FRAME_TYPE_LAST:
6689 break;
6690 }
6691
6692 return "<unknown>";
6693}
6694
6695MetaGradientType
6696meta_gradient_type_from_string (const char *str)
6697{
6698 if (strcmp ("vertical", str) == 0)
6699 return META_GRADIENT_VERTICAL;
6700 else if (strcmp ("horizontal", str) == 0)
6701 return META_GRADIENT_HORIZONTAL;
6702 else if (strcmp ("diagonal", str) == 0)
6703 return META_GRADIENT_DIAGONAL;
6704 else
6705 return META_GRADIENT_LAST;
6706}
6707
6708const char*
6709meta_gradient_type_to_string (MetaGradientType type)
6710{
6711 switch (type)
6712 {
6713 case META_GRADIENT_VERTICAL:
6714 return "vertical";
6715 case META_GRADIENT_HORIZONTAL:
6716 return "horizontal";
6717 case META_GRADIENT_DIAGONAL:
6718 return "diagonal";
6719 case META_GRADIENT_LAST:
6720 break;
6721 }
6722
6723 return "<unknown>";
6724}
6725
6726GtkStateFlags
6727meta_gtk_state_from_string (const char *str)
6728{
6729 if (g_ascii_strcasecmp ("normal", str) == 0)
6730 return GTK_STATE_FLAG_NORMAL;
6731 else if (g_ascii_strcasecmp ("prelight", str) == 0)
6732 return GTK_STATE_FLAG_PRELIGHT;
6733 else if (g_ascii_strcasecmp ("active", str) == 0)
6734 return GTK_STATE_FLAG_ACTIVE;
6735 else if (g_ascii_strcasecmp ("selected", str) == 0)
6736 return GTK_STATE_FLAG_SELECTED;
6737 else if (g_ascii_strcasecmp ("insensitive", str) == 0)
6738 return GTK_STATE_FLAG_INSENSITIVE;
6739 else if (g_ascii_strcasecmp ("inconsistent", str) == 0)
6740 return GTK_STATE_FLAG_INCONSISTENT;
6741 else if (g_ascii_strcasecmp ("focused", str) == 0)
6742 return GTK_STATE_FLAG_FOCUSED;
6743 else if (g_ascii_strcasecmp ("backdrop", str) == 0)
6744 return GTK_STATE_FLAG_BACKDROP;
6745 else
6746 return -1; /* hack */
6747}
6748
6749GtkShadowType
6750meta_gtk_shadow_from_string (const char *str)
6751{
6752 if (strcmp ("none", str) == 0)
6753 return GTK_SHADOW_NONE;
6754 else if (strcmp ("in", str) == 0)
6755 return GTK_SHADOW_IN;
6756 else if (strcmp ("out", str) == 0)
6757 return GTK_SHADOW_OUT;
6758 else if (strcmp ("etched_in", str) == 0)
6759 return GTK_SHADOW_ETCHED_IN;
6760 else if (strcmp ("etched_out", str) == 0)
6761 return GTK_SHADOW_ETCHED_OUT;
6762 else
6763 return -1;
6764}
6765
6766const char*
6767meta_gtk_shadow_to_string (GtkShadowType shadow)
6768{
6769 switch (shadow)
6770 {
6771 case GTK_SHADOW_NONE:
6772 return "none";
6773 case GTK_SHADOW_IN:
6774 return "in";
6775 case GTK_SHADOW_OUT:
6776 return "out";
6777 case GTK_SHADOW_ETCHED_IN:
6778 return "etched_in";
6779 case GTK_SHADOW_ETCHED_OUT:
6780 return "etched_out";
6781 }
6782
6783 return "<unknown>";
6784}
6785
6786GtkArrowType
6787meta_gtk_arrow_from_string (const char *str)
6788{
6789 if (strcmp ("up", str) == 0)
6790 return GTK_ARROW_UP;
6791 else if (strcmp ("down", str) == 0)
6792 return GTK_ARROW_DOWN;
6793 else if (strcmp ("left", str) == 0)
6794 return GTK_ARROW_LEFT;
6795 else if (strcmp ("right", str) == 0)
6796 return GTK_ARROW_RIGHT;
6797 else if (strcmp ("none", str) == 0)
6798 return GTK_ARROW_NONE;
6799 else
6800 return -1;
6801}
6802
6803const char*
6804meta_gtk_arrow_to_string (GtkArrowType arrow)
6805{
6806 switch (arrow)
6807 {
6808 case GTK_ARROW_UP:
6809 return "up";
6810 case GTK_ARROW_DOWN:
6811 return "down";
6812 case GTK_ARROW_LEFT:
6813 return "left";
6814 case GTK_ARROW_RIGHT:
6815 return "right";
6816 case GTK_ARROW_NONE:
6817 return "none";
6818 }
6819
6820 return "<unknown>";
This statement is never executed
6821}
6822
6823/**
6824 * Returns a fill_type from a string. The inverse of
6825 * meta_image_fill_type_to_string().
6826 *
6827 * \param str a string representing a fill_type
6828 * \result the fill_type, or -1 if it represents no fill_type.
6829 */
6830MetaImageFillType
6831meta_image_fill_type_from_string (const char *str)
6832{
6833 if (strcmp ("tile", str) == 0)
6834 return META_IMAGE_FILL_TILE;
6835 else if (strcmp ("scale", str) == 0)
6836 return META_IMAGE_FILL_SCALE;
6837 else
6838 return -1;
6839}
6840
6841/**
6842 * Returns a string representation of a fill_type. The inverse of
6843 * meta_image_fill_type_from_string().
6844 *
6845 * \param fill_type the fill type
6846 * \result a string representing that type
6847 */
6848const char*
6849meta_image_fill_type_to_string (MetaImageFillType fill_type)
6850{
6851 switch (fill_type)
6852 {
6853 case META_IMAGE_FILL_TILE:
6854 return "tile";
6855 case META_IMAGE_FILL_SCALE:
6856 return "scale";
6857 }
6858
6859 return "<unknown>";
6860}
6861
6862/**
6863 * Takes a colour "a", scales the lightness and saturation by a certain amount,
6864 * and sets "b" to the resulting colour.
6865 * gtkstyle.c cut-and-pastage.
6866 *
6867 * \param a the starting colour
6868 * \param b [out] the resulting colour
6869 * \param k amount to scale lightness and saturation by
6870 */
6871static void
6872gtk_style_shade (GdkRGBA *a,
6873 GdkRGBA *b,
6874 gdouble k)
6875{
6876 gdouble red;
6877 gdouble green;
6878 gdouble blue;
6879
6880 red = a->red;
6881 green = a->green;
6882 blue = a->blue;
6883
6884 rgb_to_hls (&red, &green, &blue);
6885
6886 green *= k;
6887 if (green > 1.0)
6888 green = 1.0;
6889 else if (green < 0.0)
6890 green = 0.0;
6891
6892 blue *= k;
6893 if (blue > 1.0)
6894 blue = 1.0;
6895 else if (blue < 0.0)
6896 blue = 0.0;
6897
6898 hls_to_rgb (&red, &green, &blue);
6899
6900 b->red = red;
6901 b->green = green;
6902 b->blue = blue;
6903}
6904
6905/**
6906 * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
6907 *
6908 * \param r on input, red; on output, hue
6909 * \param g on input, green; on output, lightness
6910 * \param b on input, blue; on output, saturation
6911 */
6912static void
6913rgb_to_hls (gdouble *r,
6914 gdouble *g,
6915 gdouble *b)
6916{
6917 gdouble min;
6918 gdouble max;
6919 gdouble red;
6920 gdouble green;
6921 gdouble blue;
6922 gdouble h, l, s;
6923 gdouble delta;
6924
6925 red = *r;
6926 green = *g;
6927 blue = *b;
6928
6929 if (red > green)
6930 {
6931 if (red > blue)
6932 max = red;
6933 else
6934 max = blue;
6935
6936 if (green < blue)
6937 min = green;
6938 else
6939 min = blue;
6940 }
6941 else
6942 {
6943 if (green > blue)
6944 max = green;
6945 else
6946 max = blue;
6947
6948 if (red < blue)
6949 min = red;
6950 else
6951 min = blue;
6952 }
6953
6954 l = (max + min) / 2;
6955 s = 0;
6956 h = 0;
6957
6958 if (max != min)
6959 {
6960 if (l <= 0.5)
6961 s = (max - min) / (max + min);
6962 else
6963 s = (max - min) / (2 - max - min);
6964
6965 delta = max -min;
6966 if (red == max)
6967 h = (green - blue) / delta;
6968 else if (green == max)
6969 h = 2 + (blue - red) / delta;
6970 else if (blue == max)
6971 h = 4 + (red - green) / delta;
6972
6973 h *= 60;
6974 if (h < 0.0)
6975 h += 360;
6976 }
6977
6978 *r = h;
6979 *g = l;
6980 *b = s;
6981}
6982
6983/**
6984 * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
6985 *
6986 * \param h on input, hue; on output, red
6987 * \param l on input, lightness; on output, green
6988 * \param s on input, saturation; on output, blue
6989 */
6990static void
6991hls_to_rgb (gdouble *h,
6992 gdouble *l,
6993 gdouble *s)
6994{
6995 gdouble hue;
6996 gdouble lightness;
6997 gdouble saturation;
6998 gdouble m1, m2;
6999 gdouble r, g, b;
7000
7001 lightness = *l;
7002 saturation = *s;
7003
7004 if (lightness <= 0.5)
7005 m2 = lightness * (1 + saturation);
7006 else
7007 m2 = lightness + saturation - lightness * saturation;
7008 m1 = 2 * lightness - m2;
7009
7010 if (saturation == 0)
7011 {
7012 *h = lightness;
7013 *l = lightness;
7014 *s = lightness;
7015 }
7016 else
7017 {
7018 hue = *h + 120;
7019 while (hue > 360)
7020 hue -= 360;
7021 while (hue < 0)
7022 hue += 360;
7023
7024 if (hue < 60)
7025 r = m1 + (m2 - m1) * hue / 60;
7026 else if (hue < 180)
7027 r = m2;
7028 else if (hue < 240)
7029 r = m1 + (m2 - m1) * (240 - hue) / 60;
7030 else
7031 r = m1;
7032
7033 hue = *h;
7034 while (hue > 360)
7035 hue -= 360;
7036 while (hue < 0)
7037 hue += 360;
7038
7039 if (hue < 60)
7040 g = m1 + (m2 - m1) * hue / 60;
7041 else if (hue < 180)
7042 g = m2;
7043 else if (hue < 240)
7044 g = m1 + (m2 - m1) * (240 - hue) / 60;
7045 else
7046 g = m1;
7047
7048 hue = *h - 120;
7049 while (hue > 360)
7050 hue -= 360;
7051 while (hue < 0)
7052 hue += 360;
7053
7054 if (hue < 60)
7055 b = m1 + (m2 - m1) * hue / 60;
7056 else if (hue < 180)
7057 b = m2;
7058 else if (hue < 240)
7059 b = m1 + (m2 - m1) * (240 - hue) / 60;
7060 else
7061 b = m1;
7062
7063 *h = r;
7064 *l = g;
7065 *s = b;
7066 }
7067}
7068
7069#if 0
7070/* These are some functions I'm saving to use in optimizing
7071 * MetaDrawOpList, namely to pre-composite pixbufs on client side
7072 * prior to rendering to the server
7073 */
7074static void
7075draw_bg_solid_composite (const MetaTextureSpec *bg,
7076 const MetaTextureSpec *fg,
7077 double alpha,
7078 GtkWidget *widget,
7079 GdkDrawable *drawable,
7080 const GdkRectangle *clip,
7081 MetaTextureDrawMode mode,
7082 double xalign,
7083 double yalign,
7084 int x,
7085 int y,
7086 int width,
7087 int height)
7088{
7089 GdkColor bg_color;
7090
7091 g_assert (bg->type == META_TEXTURE_SOLID)do { if (bg->type == META_TEXTURE_SOLID) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7091, ((const char*) (__func__)), "bg->type == META_TEXTURE_SOLID"
); } while (0)
;
7092 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7092, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7093 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7093, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7094
7095 meta_color_spec_render (bg->data.solid.color_spec,
7096 widget,
7097 &bg_color);
7098
7099 switch (fg->type)
7100 {
7101 case META_TEXTURE_SOLID:
7102 {
7103 GdkColor fg_color;
7104
7105 meta_color_spec_render (fg->data.solid.color_spec,
7106 widget,
7107 &fg_color);
7108
7109 color_composite (&bg_color, &fg_color,
7110 alpha, &fg_color);
7111
7112 draw_color_rectangle (widget, drawable, &fg_color, clip,
7113 x, y, width, height);
7114 }
7115 break;
7116
7117 case META_TEXTURE_GRADIENT:
7118 /* FIXME I think we could just composite all the colors in
7119 * the gradient prior to generating the gradient?
7120 */
7121 /* FALL THRU */
7122 case META_TEXTURE_IMAGE:
7123 {
7124 GdkPixbuf *pixbuf;
7125 GdkPixbuf *composited;
7126
7127 pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7128 width, height);
7129
7130 if (pixbuf == NULL((void*)0))
7131 return;
7132
7133 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7134 gdk_pixbuf_get_has_alpha (pixbuf), 8,
7135 gdk_pixbuf_get_width (pixbuf),
7136 gdk_pixbuf_get_height (pixbuf));
7137
7138 if (composited == NULL((void*)0))
7139 {
7140 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7141 return;
7142 }
7143
7144 gdk_pixbuf_composite_color (pixbuf,
7145 composited,
7146 0, 0,
7147 gdk_pixbuf_get_width (pixbuf),
7148 gdk_pixbuf_get_height (pixbuf),
7149 0.0, 0.0, /* offsets */
7150 1.0, 1.0, /* scale */
7151 GDK_INTERP_BILINEAR,
7152 255 * alpha,
7153 0, 0, /* check offsets */
7154 0, /* check size */
7155 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
,
7156 GDK_COLOR_RGB (bg_color)((guint32) (((int)((bg_color).red * 255) << 16) | ((int
)((bg_color).green * 255) << 8) | ((int)((bg_color).blue
* 255))))
);
7157
7158 /* Need to draw background since pixbuf is not
7159 * necessarily covering the whole thing
7160 */
7161 draw_color_rectangle (widget, drawable, &bg_color, clip,
7162 x, y, width, height);
7163
7164 render_pixbuf_aligned (drawable, clip, composited,
7165 xalign, yalign,
7166 x, y, width, height);
7167
7168 g_object_unref (G_OBJECT (pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pixbuf)), (((GType) ((20) << (2))))))))
);
7169 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7170 }
7171 break;
7172
7173 case META_TEXTURE_BLANK:
7174 case META_TEXTURE_COMPOSITE:
7175 case META_TEXTURE_SHAPE_LIST:
7176 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7176, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7177 break;
7178 }
7179}
7180
7181static void
7182draw_bg_gradient_composite (const MetaTextureSpec *bg,
7183 const MetaTextureSpec *fg,
7184 double alpha,
7185 GtkWidget *widget,
7186 GdkDrawable *drawable,
7187 const GdkRectangle *clip,
7188 MetaTextureDrawMode mode,
7189 double xalign,
7190 double yalign,
7191 int x,
7192 int y,
7193 int width,
7194 int height)
7195{
7196 g_assert (bg->type == META_TEXTURE_GRADIENT)do { if (bg->type == META_TEXTURE_GRADIENT) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7196, ((const char*) (__func__)), "bg->type == META_TEXTURE_GRADIENT"
); } while (0)
;
7197 g_assert (fg->type != META_TEXTURE_COMPOSITE)do { if (fg->type != META_TEXTURE_COMPOSITE) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7197, ((const char*) (__func__)), "fg->type != META_TEXTURE_COMPOSITE"
); } while (0)
;
7198 g_assert (fg->type != META_TEXTURE_SHAPE_LIST)do { if (fg->type != META_TEXTURE_SHAPE_LIST) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7198, ((const char*) (__func__)), "fg->type != META_TEXTURE_SHAPE_LIST"
); } while (0)
;
7199
7200 switch (fg->type)
7201 {
7202 case META_TEXTURE_SOLID:
7203 case META_TEXTURE_GRADIENT:
7204 case META_TEXTURE_IMAGE:
7205 {
7206 GdkPixbuf *bg_pixbuf;
7207 GdkPixbuf *fg_pixbuf;
7208 GdkPixbuf *composited;
7209 int fg_width, fg_height;
7210
7211 bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255,
7212 width, height);
7213
7214 if (bg_pixbuf == NULL((void*)0))
7215 return;
7216
7217 fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
7218 width, height);
7219
7220 if (fg_pixbuf == NULL((void*)0))
7221 {
7222 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7223 return;
7224 }
7225
7226 /* gradients always fill the entire target area */
7227 g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width)do { if (gdk_pixbuf_get_width (bg_pixbuf) == width) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7227, ((const char*) (__func__)), "gdk_pixbuf_get_width (bg_pixbuf) == width"
); } while (0)
;
7228 g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height)do { if (gdk_pixbuf_get_height (bg_pixbuf) == height) ; else g_assertion_message_expr
("marco", "ui/theme.c", 7228, ((const char*) (__func__)), "gdk_pixbuf_get_height (bg_pixbuf) == height"
); } while (0)
;
7229
7230 composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
7231 gdk_pixbuf_get_has_alpha (bg_pixbuf), 8,
7232 gdk_pixbuf_get_width (bg_pixbuf),
7233 gdk_pixbuf_get_height (bg_pixbuf));
7234
7235 if (composited == NULL((void*)0))
7236 {
7237 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7238 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7239 return;
7240 }
7241
7242 fg_width = gdk_pixbuf_get_width (fg_pixbuf);
7243 fg_height = gdk_pixbuf_get_height (fg_pixbuf);
7244
7245 /* If we wanted to be all cool we could deal with the
7246 * offsets and try to composite only in the clip rectangle,
7247 * but I just don't care enough to figure it out.
7248 */
7249
7250 gdk_pixbuf_composite (fg_pixbuf,
7251 composited,
7252 x + (width - fg_width) * xalign,
7253 y + (height - fg_height) * yalign,
7254 gdk_pixbuf_get_width (fg_pixbuf),
7255 gdk_pixbuf_get_height (fg_pixbuf),
7256 0.0, 0.0, /* offsets */
7257 1.0, 1.0, /* scale */
7258 GDK_INTERP_BILINEAR,
7259 255 * alpha);
7260
7261 gdk_cairo_set_source_pixbuf (cr, composited, x, y);
7262 cairo_paint (cr);
7263
7264 g_object_unref (G_OBJECT (bg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg_pixbuf)), (((GType) ((20) << (2))))))))
);
7265 g_object_unref (G_OBJECT (fg_pixbuf)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((fg_pixbuf)), (((GType) ((20) << (2))))))))
);
7266 g_object_unref (G_OBJECT (composited)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((composited)), (((GType) ((20) << (2))))))))
);
7267 }
7268 break;
7269
7270 case META_TEXTURE_BLANK:
7271 case META_TEXTURE_SHAPE_LIST:
7272 case META_TEXTURE_COMPOSITE:
7273 g_assert_not_reached ()do { g_assertion_message_expr ("marco", "ui/theme.c", 7273, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
7274 break;
7275 }
7276}
7277#endif
7278
7279/**
7280 * Returns the earliest version of the theme format which required support
7281 * for a particular button. (For example, "shade" first appeared in v2, and
7282 * "close" in v1.)
7283 *
7284 * \param type the button type
7285 * \return the number of the theme format
7286 */
7287guint
7288meta_theme_earliest_version_with_button (MetaButtonType type)
7289{
7290 switch (type)
7291 {
7292 case META_BUTTON_TYPE_CLOSE:
7293 case META_BUTTON_TYPE_MAXIMIZE:
7294 case META_BUTTON_TYPE_MINIMIZE:
7295 case META_BUTTON_TYPE_MENU:
7296 case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
7297 case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
7298 case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
7299 case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
7300 case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
7301 case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
7302 return 1000;
7303
7304 case META_BUTTON_TYPE_SHADE:
7305 case META_BUTTON_TYPE_ABOVE:
7306 case META_BUTTON_TYPE_STICK:
7307 case META_BUTTON_TYPE_UNSHADE:
7308 case META_BUTTON_TYPE_UNABOVE:
7309 case META_BUTTON_TYPE_UNSTICK:
7310 return 2000;
7311
7312 case META_BUTTON_TYPE_LEFT_SINGLE_BACKGROUND:
7313 case META_BUTTON_TYPE_RIGHT_SINGLE_BACKGROUND:
7314 return 3003;
7315
7316 case META_BUTTON_TYPE_APPMENU:
7317 return 3005;
7318
7319 default:
7320 meta_warning("Unknown button %d\n", type);
7321 return 1000;
7322 }
7323}
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-f74df1.html b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-f74df1.html new file mode 100644 index 00000000..5f784baa --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/report-f74df1.html @@ -0,0 +1,816 @@ + + + +test-size-hints.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:wm-tester/test-size-hints.c
Warning:line 91, column 11
Value stored to 'x' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name test-size-hints.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src/wm-tester -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/libgtop-2.0 -I /usr/include/mate-desktop-2.0 -I /usr/include/pango-1.0 -D _REENTRANT -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/gtk-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/dconf -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libmount -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/src/wm-tester -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-08-164013-12711-1 -x c test-size-hints.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1#include <X11/Xlib.h>
2#include <X11/Xutil.h>
3#include <stdlib.h>
4#include <glib.h>
5
6static Boolint
7all_events (Display *display,
8 XEvent *event,
9 XPointer arg)
10{
11 return True1;
12}
13
14#if 0
15static void
16get_size (Display *d, Drawable draw,
17 int *xp, int *yp, int *widthp, int *heightp)
18{
19 int x, y;
20 unsigned int width, height, border, depth;
21 Window root;
22
23 XGetGeometry (d, draw, &root, &x, &y, &width, &height, &border, &depth);
24
25 if (xp)
26 *xp = x;
27 if (yp)
28 *yp = y;
29 if (widthp)
30 *widthp = width;
31 if (*heightp)
32 *heightp = height;
33}
34#endif
35
36int
37main (int argc, char **argv)
38{
39 Display *d;
40 Window zero_min_size;
41 XSizeHints hints;
42 int screen;
43 XEvent ev;
44 int x, y, width, height;
45 Pixmap pix;
46 GC gc;
47 XGCValues gc_vals;
48 gboolean redraw_pending;
49
50 d = XOpenDisplay (NULL((void*)0));
51
52 screen = DefaultScreen (d)(((_XPrivDisplay)(d))->default_screen);
53
54 x = 0;
55 y = 0;
56 width = 100;
57 height = 100;
58
59 zero_min_size = XCreateSimpleWindow (d, RootWindow (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root),
60 x, y, width, height, 0,
61 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
,
62 WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
);
63
64 XSelectInput (d, zero_min_size,
65 ButtonPressMask(1L<<2) | ExposureMask(1L<<15) | StructureNotifyMask(1L<<17));
66
67 hints.flags = PMinSize(1L << 4);
68
69 hints.min_width = 0;
70 hints.min_height = 0;
71
72 XSetWMNormalHints (d, zero_min_size, &hints);
73 XMapWindow (d, zero_min_size);
74
75 redraw_pending = FALSE(0);
76 while (1)
77 {
78 XNextEvent (d, &ev);
79
80 switch (ev.xany.type)
81 {
82 case ButtonPress4:
83 if (ev.xbutton.button == 1)
84 {
85 g_print ("Exiting on button 1 press\n");
86 exit (0);
87 }
88 break;
89
90 case ConfigureNotify22:
91 x = ev.xconfigure.x;
Value stored to 'x' is never read
92 y = ev.xconfigure.y;
93 width = ev.xconfigure.width;
94 height = ev.xconfigure.height;
95
96 redraw_pending = TRUE(!(0));
97 break;
98
99 case Expose12:
100 redraw_pending = TRUE(!(0));
101 break;
102
103 default:
104 break;
105 }
106
107 /* Primitive event compression */
108 if (XCheckIfEvent (d, &ev, all_events, NULL((void*)0)))
109 {
110 XPutBackEvent (d, &ev);
111 }
112 else if (redraw_pending)
113 {
114 pix = XCreatePixmap (d, zero_min_size, width, height,
115 DefaultDepth (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->root_depth
)
);
116
117 gc_vals.foreground = WhitePixel (d, screen)((&((_XPrivDisplay)(d))->screens[screen])->white_pixel
)
;
118
119 gc = XCreateGC (d, pix, GCForeground(1L<<2), &gc_vals);
120
121 XFillRectangle (d, pix, gc, 0, 0, width, height);
122
123 XCopyArea (d, pix, zero_min_size, gc, 0, 0, width, height, 0, 0);
124
125 XFreePixmap (d, pix);
126 XFreeGC (d, gc);
127
128 redraw_pending = FALSE(0);
129 }
130 }
131
132 /* This program has an infinite loop above so a return statement would
133 * just cause compiler warnings.
134 */
135}
136
diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/scanview.css b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/scanview.css new file mode 100644 index 00000000..cf8a5a6a --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/sorttable.js b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/sorttable.js new file mode 100644 index 00000000..32faa078 --- /dev/null +++ b/2024-04-08-164013-12711-1@0b5bca12661c_iconcache-use-gdesktopapp@96a4b36b9fec_iconcache-use-gdesktopapp/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write("