[Xfce4-commits] [xfce/xfce4-settings] 01/01: Introduction of a new drag-and-drop display settings dialog. This new dialog works more reliably and is significantly easier to use with multiple monitors. It is based on the MATE Display Settings dialog, while maintaining the Xfce flair.
noreply at xfce.org
noreply at xfce.org
Thu Jul 10 03:34:42 CEST 2014
This is an automated email from the git hooks/post-receive script.
bluesabre pushed a commit to branch master
in repository xfce/xfce4-settings.
commit 3903d0ab91b3840eccf9c52f4000b4808c13aec6
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Wed Jul 9 21:28:16 2014 -0400
Introduction of a new drag-and-drop display settings dialog.
This new dialog works more reliably and is significantly easier to use with multiple monitors. It is based on the MATE Display Settings dialog, while maintaining the Xfce flair.
Squashed commit of the following:
commit 02a6e2204a5f91aed09b21a0851d53a607674fe4
Merge: 3518045 0b289d2
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Wed Jul 9 21:25:26 2014 -0400
Merge branch 'master' of github.com:bluesabre/xfce4-settings into display-settings
commit 0b289d2ffba38bff01b1275fc7effd03b055ab5c
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Wed Jul 9 21:04:28 2014 -0400
Do not automatically show popups on screen event
commit b2c34610d8655c9c97cc17520336b41541db739a
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Wed Jul 9 20:56:45 2014 -0400
Drop the icon from the combobox
commit 08caa14626f5541c71688167aae58c4c145e4422
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Wed Jul 9 20:47:58 2014 -0400
Better numbering
commit 25178c8bef12d54ca3ee13ca4f9fd7f3fb0f3f65
Author: Simon Steinbeiss <simon.steinbeiss at elfenbeinturm.at>
Date: Wed Jul 9 19:56:09 2014 -0400
Fix radial gradient on non-primary displays
commit 3db18859788f1aff7da469797aa7e150db13bf99
Author: Simon Steinbeiss <simon.steinbeiss at elfenbeinturm.at>
Date: Tue Jul 8 02:03:39 2014 +0200
Ellipsize the labels in the display-widgets
commit 3202b8d93704d69f98bd455f1e095f635dd67d5a
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Sun Jul 6 19:42:43 2014 -0400
Store only output ids
commit 1c828cc780b6742e0e19a002392f6f6ae8a337ee
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Sun Jul 6 17:06:35 2014 -0400
Fix Display settings mix up monitor EDID names (bug 10717)
commit 97801953fc69349220442631bc3ff0f44eff40cb
Author: Victor Yap <victor.yap at alumni.concordia.ca>
Date: Sun Jul 6 15:21:05 2014 -0400
Add display output numerical identifier prefix
commit cb5c36049a9cb7b1b4ae7d25c8a8c44ad69b47ce
Author: Simon Steinbeiss <simon.steinbeiss at elfenbeinturm.at>
Date: Tue Jun 10 15:46:56 2014 +0200
Create a more complex reflection and improve sharpness
commit b26d92f8aeccebee3038e555bf86075c8da8f63f
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Thu Jun 5 22:02:51 2014 -0400
Reflect resolution, rotation, and mirror settings in gui immediately
commit ccbd17d896856db0cf1c53b2939b1add75ad901c
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Thu Jun 5 21:33:14 2014 -0400
Prevent disabled outputs from overlapping each other.
commit 8843f45c6ea64278f8507a38d5c696a327f45db0
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Thu Jun 5 20:24:16 2014 -0400
Snap displayed edges for better appearance.
commit d05001e8de155dcf73addcbbba07ac94358a9038
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Thu Jun 5 00:11:22 2014 -0400
Drop Position comboboxes, make DND fully operational with addition of Apply button.
commit 55b88cf951970cadcf6fa0a3b49f7f1346f28b41
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue Jun 3 21:20:26 2014 -0400
Correctly represent position as coordinates
commit b6cdf5f1a01cffc7b177ae9c94c8e1d7e1f4c3e5
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue Jun 3 21:09:45 2014 -0400
Fix segfault on cairo_pattern_t
commit e8160fddd75ef5bb591c78be0f634bc21d502a60
Author: Simon Steinbeiss <simon.steinbeiss at elfenbeinturm.at>
Date: Tue Jun 3 16:00:30 2014 +0200
Migrate to fixed colors, add more fancy cairo drawing and add a label for the disabled output
Try to make sure that the outlines are all sharp by rounding
FIXME: displays are actually overlapping on the border pixels
commit 98f620670ea1eea235a188e4a4e24dca8bd37a2a
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Sat May 31 06:37:09 2014 -0400
Use the tooltip to display position
commit 599506a4037b07c9f296d6fe298516e72b80f55a
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Fri May 30 23:50:55 2014 -0400
Cleanup remaining debug strings and mate names
commit 7c99c8b1c48cfaa2c5d88bc970cdea5176a7dc99
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Fri May 30 23:40:49 2014 -0400
Center displays again.
commit bf1766f794eac4fe26eaa24dd6fe79aaebdd26f9
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Fri May 30 23:28:48 2014 -0400
Fix alignment by not zeroing positions until mouse release
commit 1669eab8aaa2f7ab64e8a1f3889ba6907493b641
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Fri May 30 22:47:43 2014 -0400
Improved scaling
commit dd15e1bfa69ea847321181f8cf5f79fb231b099e
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Wed May 28 07:06:53 2014 -0400
Change selected display on click in gui
commit 4265acd7d52901d7352322e10baba576ad8cf3e5
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue May 27 22:53:36 2014 -0400
Additional cleanup, fix debug builds.
commit 8f81f62dbe8f779c93b09e165b43926507e19b14
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue May 27 21:37:52 2014 -0400
Consistent spacing.
commit b53ff618f1456babf40f8e59859d937f42d3707e
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue May 27 20:39:00 2014 -0400
Further code cleanup
commit 8fcc5e99b2a76751933c6f99083a5afe95757f04
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue May 27 07:26:48 2014 -0400
Fix initial layouts
commit 02c5c8be0b7a726082aec146120bc59ac32e4e08
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Tue May 27 06:35:12 2014 -0400
Functional DND that does not yet commit changes
commit 9b8eede7a90345cea0363306b3bfc1b5c12f5d0e
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Mon May 26 21:27:53 2014 -0400
Smarter color selection
commit 496dd7a4a5da7e210c2657b2fb54e4c00b7a4366
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Mon May 26 19:13:19 2014 -0400
Fix active color
commit 86be121c7be606393c2d7c0c7e981ae2a5dcaa4c
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Mon May 26 10:14:16 2014 -0400
Cleanup 1
commit 66f97ff7239491c92e395fbccfdbc3de509028fa
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Mon May 26 00:47:44 2014 -0400
Initial import of display-settings dialog from mate-control-center. At this point, the appearance is starting to take shape, but the drag-n-drop is still not working correctly. There is still a signficant amount of cleanup work and optimization that needs to be included as well.
commit f3b80bf7f311f267f31e37085b9412b0f4c1cfae
Author: Sean Davis <smd.seandavis at gmail.com>
Date: Sat May 24 20:38:25 2014 -0400
Replace treeview with combobox
---
dialogs/display-settings/Makefile.am | 9 +-
dialogs/display-settings/display-dialog.glade | 113 +-
dialogs/display-settings/display-name.c | 36 +-
dialogs/display-settings/edid-parse.c | 444 +++---
dialogs/display-settings/edid.h | 206 +--
dialogs/display-settings/foo-marshal.c | 280 ++++
dialogs/display-settings/foo-marshal.h | 67 +
dialogs/display-settings/main.c | 1832 +++++++++++++++++++------
dialogs/display-settings/scrollarea.c | 1433 +++++++++++++++++++
dialogs/display-settings/scrollarea.h | 137 ++
dialogs/display-settings/xfce-randr.c | 168 +--
dialogs/display-settings/xfce-randr.h | 54 +-
xfsettingsd/debug.c | 2 +-
13 files changed, 3793 insertions(+), 988 deletions(-)
diff --git a/dialogs/display-settings/Makefile.am b/dialogs/display-settings/Makefile.am
index 4536033..b96d582 100644
--- a/dialogs/display-settings/Makefile.am
+++ b/dialogs/display-settings/Makefile.am
@@ -22,7 +22,11 @@ xfce4_display_settings_SOURCES = \
identity-popup_ui.h \
display-name.c \
edid-parse.c \
- edid.h
+ edid.h \
+ scrollarea.c \
+ scrollarea.h \
+ foo-marshal.c \
+ foo-marshal.h
xfce4_display_settings_CFLAGS = \
$(GTK_CFLAGS) \
@@ -43,7 +47,8 @@ xfce4_display_settings_LDADD = \
$(XFCONF_LIBS) \
$(EXO_LIBS) \
$(LIBX11_LIBS) -lm \
- $(XRANDR_LIBS)
+ $(XRANDR_LIBS) \
+ $(GLIB_LIBS)
if MAINTAINER_MODE
diff --git a/dialogs/display-settings/display-dialog.glade b/dialogs/display-settings/display-dialog.glade
index db7fcef..555e7c0 100644
--- a/dialogs/display-settings/display-dialog.glade
+++ b/dialogs/display-settings/display-dialog.glade
@@ -29,21 +29,12 @@
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
- <object class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="width_request">200</property>
+ <object class="GtkAlignment" id="randr-dnd">
+ <property name="width_request">300</property>
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">etched-in</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkTreeView" id="randr-outputs">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="headers_visible">False</property>
- <property name="enable_search">False</property>
- <property name="show_expanders">False</property>
- </object>
+ <placeholder/>
</child>
</object>
<packing>
@@ -54,6 +45,7 @@
</child>
<child>
<object class="GtkTable" id="table1">
+ <property name="width_request">280</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">7</property>
@@ -171,21 +163,6 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="label-position">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">P_osition:</property>
- <property name="use_underline">True</property>
- </object>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
<object class="GtkCheckButton" id="output-on">
<property name="label" translatable="yes">_Use this output</property>
<property name="visible">True</property>
@@ -197,6 +174,8 @@
</object>
<packing>
<property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
@@ -213,50 +192,25 @@
</object>
<packing>
<property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
- <object class="GtkHBox" id="hbox1">
+ <object class="GtkComboBox" id="randr-outputs">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <child>
- <object class="GtkComboBox" id="randr-position">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBox" id="randr-active-displays">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
</object>
<packing>
- <property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</object>
<packing>
- <property name="expand">True</property>
+ <property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
@@ -273,7 +227,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkHBox" id="hbox2">
+ <object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
@@ -293,17 +247,46 @@
</packing>
</child>
<child>
- <object class="GtkToggleButton" id="identify-displays">
- <property name="label" translatable="yes">Identify Displays</property>
+ <object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_action_appearance">False</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkToggleButton" id="identify-displays">
+ <property name="label" translatable="yes">Identify Displays</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="apply">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
+ <property name="expand">True</property>
<property name="fill">True</property>
- <property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
diff --git a/dialogs/display-settings/display-name.c b/dialogs/display-settings/display-name.c
index 5e8f8b1..2742566 100644
--- a/dialogs/display-settings/display-name.c
+++ b/dialogs/display-settings/display-name.c
@@ -61,7 +61,7 @@ static const struct Vendor vendors[] =
{ "SEC", "Epson" },
{ "WAC", "Wacom" },
{ "NEC", "NEC" },
- { "CMO", "CMO" }, /* Chi Mei */
+ { "CMO", "CMO" }, /* Chi Mei */
{ "BNQ", "BenQ" },
{ "ABP", "Advansys" },
@@ -242,62 +242,62 @@ find_vendor (const char *code)
for (i = 0; i < sizeof (vendors) / sizeof (vendors[0]); ++i)
{
- const Vendor *v = &(vendors[i]);
+ const Vendor *v = &(vendors[i]);
- if (strcmp (v->vendor_id, code) == 0)
- return v->vendor_name;
+ if (strcmp (v->vendor_id, code) == 0)
+ return v->vendor_name;
}
return code;
};
char *
-make_display_name (const MonitorInfo *info)
+make_display_name (const MonitorInfo *info, guint output)
{
const char *vendor;
int width_mm, height_mm, inches;
if (info)
{
- vendor = find_vendor (info->manufacturer_code);
+ vendor = find_vendor (info->manufacturer_code);
}
else
{
/* Translators: "Unknown" here is used to identify a monitor for which
* we don't know the vendor. When a vendor is known, the name of the
* vendor is used. */
- vendor = C_("Monitor vendor", "Unknown");
+ vendor = C_("Monitor vendor", "Unknown");
}
if (info && info->width_mm != -1 && info->height_mm)
{
- width_mm = info->width_mm;
- height_mm = info->height_mm;
+ width_mm = info->width_mm;
+ height_mm = info->height_mm;
}
else if (info && info->n_detailed_timings)
{
- width_mm = info->detailed_timings[0].width_mm;
- height_mm = info->detailed_timings[0].height_mm;
+ width_mm = info->detailed_timings[0].width_mm;
+ height_mm = info->detailed_timings[0].height_mm;
}
else
{
- width_mm = -1;
- height_mm = -1;
+ width_mm = -1;
+ height_mm = -1;
}
if (width_mm != -1 && height_mm != -1)
{
- double d = sqrt (width_mm * width_mm + height_mm * height_mm);
+ double d = sqrt (width_mm * width_mm + height_mm * height_mm);
- inches = (int)(d / 25.4 + 0.5);
+ inches = (int)(d / 25.4 + 0.5);
}
else
{
- inches = -1;
+ inches = -1;
}
if (inches > 0)
- return g_strdup_printf ("%s %d\"", vendor, inches);
+ return g_strdup_printf ("%i. %s %d\"", output+1, vendor, inches);
else
- return g_strdup (vendor);
+ return g_strdup_printf ("%i. %s ", output+1, vendor);
}
diff --git a/dialogs/display-settings/edid-parse.c b/dialogs/display-settings/edid-parse.c
index 3b02c37..7c35733 100644
--- a/dialogs/display-settings/edid-parse.c
+++ b/dialogs/display-settings/edid-parse.c
@@ -50,7 +50,7 @@ static int
decode_header (const uchar *edid)
{
if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
- return TRUE;
+ return TRUE;
return FALSE;
}
@@ -75,35 +75,35 @@ decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
/* Serial Number */
info->serial_number =
- edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
+ edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
/* Week and Year */
is_model_year = FALSE;
switch (edid[0x10])
{
- case 0x00:
- info->production_week = -1;
- break;
-
- case 0xff:
- info->production_week = -1;
- is_model_year = TRUE;
- break;
-
- default:
- info->production_week = edid[0x10];
- break;
+ case 0x00:
+ info->production_week = -1;
+ break;
+
+ case 0xff:
+ info->production_week = -1;
+ is_model_year = TRUE;
+ break;
+
+ default:
+ info->production_week = edid[0x10];
+ break;
}
if (is_model_year)
{
- info->production_year = -1;
- info->model_year = 1990 + edid[0x11];
+ info->production_year = -1;
+ info->model_year = 1990 + edid[0x11];
}
else
{
- info->production_year = 1990 + edid[0x11];
- info->model_year = -1;
+ info->production_year = 1990 + edid[0x11];
+ info->model_year = -1;
}
return TRUE;
@@ -126,84 +126,84 @@ decode_display_parameters (const uchar *edid, MonitorInfo *info)
if (info->is_digital)
{
- int bits;
+ int bits;
- static const int bit_depth[8] =
- {
- -1, 6, 8, 10, 12, 14, 16, -1
- };
+ static const int bit_depth[8] =
+ {
+ -1, 6, 8, 10, 12, 14, 16, -1
+ };
- static const Interface interfaces[6] =
- {
- UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
- };
+ static const Interface interfaces[6] =
+ {
+ UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
+ };
- bits = get_bits (edid[0x14], 4, 6);
- info->connector.digital.bits_per_primary = bit_depth[bits];
+ bits = get_bits (edid[0x14], 4, 6);
+ info->connector.digital.bits_per_primary = bit_depth[bits];
- bits = get_bits (edid[0x14], 0, 3);
+ bits = get_bits (edid[0x14], 0, 3);
- if (bits <= 5)
- info->connector.digital.interface = interfaces[bits];
- else
- info->connector.digital.interface = UNDEFINED;
+ if (bits <= 5)
+ info->connector.digital.interface = interfaces[bits];
+ else
+ info->connector.digital.interface = UNDEFINED;
}
else
{
- int bits = get_bits (edid[0x14], 5, 6);
+ int bits = get_bits (edid[0x14], 5, 6);
- static const double levels[][3] =
- {
- { 0.7, 0.3, 1.0 },
- { 0.714, 0.286, 1.0 },
- { 1.0, 0.4, 1.4 },
- { 0.7, 0.0, 0.7 },
- };
+ static const double levels[][3] =
+ {
+ { 0.7, 0.3, 1.0 },
+ { 0.714, 0.286, 1.0 },
+ { 1.0, 0.4, 1.4 },
+ { 0.7, 0.0, 0.7 },
+ };
- info->connector.analog.video_signal_level = levels[bits][0];
- info->connector.analog.sync_signal_level = levels[bits][1];
- info->connector.analog.total_signal_level = levels[bits][2];
+ info->connector.analog.video_signal_level = levels[bits][0];
+ info->connector.analog.sync_signal_level = levels[bits][1];
+ info->connector.analog.total_signal_level = levels[bits][2];
- info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
+ info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
- info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
- info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
- info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
+ info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
+ info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
+ info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
- info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
+ info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
}
/* Screen Size / Aspect Ratio */
if (edid[0x15] == 0 && edid[0x16] == 0)
{
- info->width_mm = -1;
- info->height_mm = -1;
- info->aspect_ratio = -1.0;
+ info->width_mm = -1;
+ info->height_mm = -1;
+ info->aspect_ratio = -1.0;
}
else if (edid[0x16] == 0)
{
- info->width_mm = -1;
- info->height_mm = -1;
- info->aspect_ratio = 100.0 / (edid[0x15] + 99);
+ info->width_mm = -1;
+ info->height_mm = -1;
+ info->aspect_ratio = 100.0 / (edid[0x15] + 99);
}
else if (edid[0x15] == 0)
{
- info->width_mm = -1;
- info->height_mm = -1;
- info->aspect_ratio = 100.0 / (edid[0x16] + 99);
- info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
+ info->width_mm = -1;
+ info->height_mm = -1;
+ info->aspect_ratio = 100.0 / (edid[0x16] + 99);
+ info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
}
else
{
- info->width_mm = 10 * edid[0x15];
- info->height_mm = 10 * edid[0x16];
+ info->width_mm = 10 * edid[0x15];
+ info->height_mm = 10 * edid[0x16];
}
/* Gamma */
if (edid[0x17] == 0xFF)
- info->gamma = -1.0;
+ info->gamma = -1.0;
else
- info->gamma = (edid[0x17] + 100.0) / 100.0;
+ info->gamma = (edid[0x17] + 100.0) / 100.0;
/* Features */
info->standby = get_bit (edid[0x18], 7);
@@ -212,21 +212,21 @@ decode_display_parameters (const uchar *edid, MonitorInfo *info)
if (info->is_digital)
{
- info->connector.digital.rgb444 = TRUE;
- if (get_bit (edid[0x18], 3))
- info->connector.digital.ycrcb444 = 1;
- if (get_bit (edid[0x18], 4))
- info->connector.digital.ycrcb422 = 1;
+ info->connector.digital.rgb444 = TRUE;
+ if (get_bit (edid[0x18], 3))
+ info->connector.digital.ycrcb444 = 1;
+ if (get_bit (edid[0x18], 4))
+ info->connector.digital.ycrcb422 = 1;
}
else
{
- int bits = get_bits (edid[0x18], 3, 4);
- ColorType color_type[4] =
- {
- MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
- };
+ int bits = get_bits (edid[0x18], 3, 4);
+ ColorType color_type[4] =
+ {
+ MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
+ };
- info->connector.analog.color_type = color_type[bits];
+ info->connector.analog.color_type = color_type[bits];
}
info->srgb_is_standard = get_bit (edid[0x18], 2);
@@ -248,7 +248,7 @@ decode_fraction (int high, int low)
high = (high << 2) | low;
for (i = 0; i < 10; ++i)
- result += get_bit (high, i) * pow (2, i - 10);
+ result += get_bit (high, i) * pow (2, i - 10);
return result;
}
@@ -273,36 +273,36 @@ decode_established_timings (const uchar *edid, MonitorInfo *info)
{
static const Timing established[][8] =
{
- {
- { 800, 600, 60 },
- { 800, 600, 56 },
- { 640, 480, 75 },
- { 640, 480, 72 },
- { 640, 480, 67 },
- { 640, 480, 60 },
- { 720, 400, 88 },
- { 720, 400, 70 }
- },
- {
- { 1280, 1024, 75 },
- { 1024, 768, 75 },
- { 1024, 768, 70 },
- { 1024, 768, 60 },
- { 1024, 768, 87 },
- { 832, 624, 75 },
- { 800, 600, 75 },
- { 800, 600, 72 }
- },
- {
- { 0, 0, 0 },
- { 0, 0, 0 },
- { 0, 0, 0 },
- { 0, 0, 0 },
- { 0, 0, 0 },
- { 0, 0, 0 },
- { 0, 0, 0 },
- { 1152, 870, 75 }
- },
+ {
+ { 800, 600, 60 },
+ { 800, 600, 56 },
+ { 640, 480, 75 },
+ { 640, 480, 72 },
+ { 640, 480, 67 },
+ { 640, 480, 60 },
+ { 720, 400, 88 },
+ { 720, 400, 70 }
+ },
+ {
+ { 1280, 1024, 75 },
+ { 1024, 768, 75 },
+ { 1024, 768, 70 },
+ { 1024, 768, 60 },
+ { 1024, 768, 87 },
+ { 832, 624, 75 },
+ { 800, 600, 75 },
+ { 800, 600, 72 }
+ },
+ {
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 1152, 870, 75 }
+ },
};
int i, j, idx;
@@ -310,13 +310,13 @@ decode_established_timings (const uchar *edid, MonitorInfo *info)
idx = 0;
for (i = 0; i < 3; ++i)
{
- for (j = 0; j < 8; ++j)
- {
- int byte = edid[0x23 + i];
+ for (j = 0; j < 8; ++j)
+ {
+ int byte = edid[0x23 + i];
- if (get_bit (byte, j) && established[i][j].frequency != 0)
- info->established[idx++] = established[i][j];
- }
+ if (get_bit (byte, j) && established[i][j].frequency != 0)
+ info->established[idx++] = established[i][j];
+ }
}
return TRUE;
}
@@ -328,26 +328,26 @@ decode_standard_timings (const uchar *edid, MonitorInfo *info)
for (i = 0; i < 8; i++)
{
- int first = edid[0x26 + 2 * i];
- int second = edid[0x27 + 2 * i];
-
- if (first != 0x01 && second != 0x01)
- {
- int w = 8 * (first + 31);
- int h;
-
- switch (get_bits (second, 6, 7))
- {
- case 0x00: h = (w / 16) * 10; break;
- case 0x01: h = (w / 4) * 3; break;
- case 0x02: h = (w / 5) * 4; break;
- case 0x03: h = (w / 16) * 9; break;
- }
-
- info->standard[i].width = w;
- info->standard[i].height = h;
- info->standard[i].frequency = get_bits (second, 0, 5) + 60;
- }
+ int first = edid[0x26 + 2 * i];
+ int second = edid[0x27 + 2 * i];
+
+ if (first != 0x01 && second != 0x01)
+ {
+ int w = 8 * (first + 31);
+ int h;
+
+ switch (get_bits (second, 6, 7))
+ {
+ case 0x00: h = (w / 16) * 10; break;
+ case 0x01: h = (w / 4) * 3; break;
+ case 0x02: h = (w / 5) * 4; break;
+ case 0x03: h = (w / 16) * 9; break;
+ }
+
+ info->standard[i].width = w;
+ info->standard[i].height = h;
+ info->standard[i].frequency = get_bits (second, 0, 5) + 60;
+ }
}
return TRUE;
@@ -359,71 +359,71 @@ decode_lf_string (const uchar *s, int n_chars, char *result)
int i;
for (i = 0; i < n_chars; ++i)
{
- if (s[i] == 0x0a)
- {
- *result++ = '\0';
- break;
- }
- else if (s[i] == 0x00)
- {
- /* Convert embedded 0's to spaces */
- *result++ = ' ';
- }
- else
- {
- *result++ = s[i];
- }
+ if (s[i] == 0x0a)
+ {
+ *result++ = '\0';
+ break;
+ }
+ else if (s[i] == 0x00)
+ {
+ /* Convert embedded 0's to spaces */
+ *result++ = ' ';
+ }
+ else
+ {
+ *result++ = s[i];
+ }
}
}
static void
decode_display_descriptor (const uchar *desc,
- MonitorInfo *info)
+ MonitorInfo *info)
{
switch (desc[0x03])
{
- case 0xFC:
- decode_lf_string (desc + 5, 13, info->dsc_product_name);
- break;
- case 0xFF:
- decode_lf_string (desc + 5, 13, info->dsc_serial_number);
- break;
- case 0xFE:
- decode_lf_string (desc + 5, 13, info->dsc_string);
- break;
- case 0xFD:
- /* Range Limits */
- break;
- case 0xFB:
- /* Color Point */
- break;
- case 0xFA:
- /* Timing Identifications */
- break;
- case 0xF9:
- /* Color Management */
- break;
- case 0xF8:
- /* Timing Codes */
- break;
- case 0xF7:
- /* Established Timings */
- break;
- case 0x10:
- break;
+ case 0xFC:
+ decode_lf_string (desc + 5, 13, info->dsc_product_name);
+ break;
+ case 0xFF:
+ decode_lf_string (desc + 5, 13, info->dsc_serial_number);
+ break;
+ case 0xFE:
+ decode_lf_string (desc + 5, 13, info->dsc_string);
+ break;
+ case 0xFD:
+ /* Range Limits */
+ break;
+ case 0xFB:
+ /* Color Point */
+ break;
+ case 0xFA:
+ /* Timing Identifications */
+ break;
+ case 0xF9:
+ /* Color Management */
+ break;
+ case 0xF8:
+ /* Timing Codes */
+ break;
+ case 0xF7:
+ /* Established Timings */
+ break;
+ case 0x10:
+ break;
}
}
static void
decode_detailed_timing (const uchar *timing,
- DetailedTiming *detailed)
+ DetailedTiming *detailed)
{
int bits;
StereoType stereo[] =
{
- NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
- TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
- FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
+ NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
+ TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
+ FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
};
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
@@ -434,9 +434,9 @@ decode_detailed_timing (const uchar *timing,
detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
detailed->v_front_porch =
- get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
+ get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
detailed->v_sync =
- get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
+ get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
detailed->right_border = timing[0x0f];
@@ -454,26 +454,26 @@ decode_detailed_timing (const uchar *timing,
detailed->digital_sync = get_bit (bits, 4);
if (detailed->digital_sync)
{
- detailed->connector.digital.composite = !get_bit (bits, 3);
-
- if (detailed->connector.digital.composite)
- {
- detailed->connector.digital.serrations = get_bit (bits, 2);
- detailed->connector.digital.negative_vsync = FALSE;
- }
- else
- {
- detailed->connector.digital.serrations = FALSE;
- detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
- }
-
- detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
+ detailed->connector.digital.composite = !get_bit (bits, 3);
+
+ if (detailed->connector.digital.composite)
+ {
+ detailed->connector.digital.serrations = get_bit (bits, 2);
+ detailed->connector.digital.negative_vsync = FALSE;
+ }
+ else
+ {
+ detailed->connector.digital.serrations = FALSE;
+ detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
+ }
+
+ detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
}
else
{
- detailed->connector.analog.bipolar = get_bit (bits, 3);
- detailed->connector.analog.serrations = get_bit (bits, 2);
- detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
+ detailed->connector.analog.bipolar = get_bit (bits, 3);
+ detailed->connector.analog.serrations = get_bit (bits, 2);
+ detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
}
}
@@ -487,17 +487,17 @@ decode_descriptors (const uchar *edid, MonitorInfo *info)
for (i = 0; i < 4; ++i)
{
- int idx = 0x36 + i * 18;
-
- if (edid[idx + 0] == 0x00 && edid[idx + 1] == 0x00)
- {
- decode_display_descriptor (edid + idx, info);
- }
- else
- {
- decode_detailed_timing (
- edid + idx, &(info->detailed_timings[timing_idx++]));
- }
+ int idx = 0x36 + i * 18;
+
+ if (edid[idx + 0] == 0x00 && edid[idx + 1] == 0x00)
+ {
+ decode_display_descriptor (edid + idx, info);
+ }
+ else
+ {
+ decode_detailed_timing (
+ edid + idx, &(info->detailed_timings[timing_idx++]));
+ }
}
info->n_detailed_timings = timing_idx;
@@ -507,13 +507,13 @@ decode_descriptors (const uchar *edid, MonitorInfo *info)
static void
decode_check_sum (const uchar *edid,
- MonitorInfo *info)
+ MonitorInfo *info)
{
int i;
uchar check = 0;
for (i = 0; i < 128; ++i)
- check += edid[i];
+ check += edid[i];
info->checksum = check;
}
@@ -526,19 +526,19 @@ decode_edid (const uchar *edid)
decode_check_sum (edid, info);
if (decode_header (edid)
- && decode_vendor_and_product_identification (edid, info)
- && decode_edid_version (edid, info)
- && decode_display_parameters (edid, info)
- && decode_color_characteristics (edid, info)
- && decode_established_timings (edid, info)
- && decode_standard_timings (edid, info)
- && decode_descriptors (edid, info))
+ && decode_vendor_and_product_identification (edid, info)
+ && decode_edid_version (edid, info)
+ && decode_display_parameters (edid, info)
+ && decode_color_characteristics (edid, info)
+ && decode_established_timings (edid, info)
+ && decode_standard_timings (edid, info)
+ && decode_descriptors (edid, info))
{
- return info;
+ return info;
}
else
{
- g_free (info);
- return NULL;
+ g_free (info);
+ return NULL;
}
}
diff --git a/dialogs/display-settings/edid.h b/dialogs/display-settings/edid.h
index 952254f..9084a7d 100644
--- a/dialogs/display-settings/edid.h
+++ b/dialogs/display-settings/edid.h
@@ -24,6 +24,8 @@
/* Downloaded from <http://git.gnome.org/browse/gnome-desktop/tree/libgnome-desktop>
(git commit 42452cada8cf1c4d7a81aded0a3ddbb5e97441de) */
+#include <glib.h>
+
#ifndef EDID_H
#define EDID_H
@@ -70,127 +72,127 @@ struct Timing
struct DetailedTiming
{
- int pixel_clock;
- int h_addr;
- int h_blank;
- int h_sync;
- int h_front_porch;
- int v_addr;
- int v_blank;
- int v_sync;
- int v_front_porch;
- int width_mm;
- int height_mm;
- int right_border;
- int top_border;
- int interlaced;
- StereoType stereo;
-
- int digital_sync;
+ int pixel_clock;
+ int h_addr;
+ int h_blank;
+ int h_sync;
+ int h_front_porch;
+ int v_addr;
+ int v_blank;
+ int v_sync;
+ int v_front_porch;
+ int width_mm;
+ int height_mm;
+ int right_border;
+ int top_border;
+ int interlaced;
+ StereoType stereo;
+
+ int digital_sync;
union
{
- struct
- {
- int bipolar;
- int serrations;
- int sync_on_green;
- } analog;
-
- struct
- {
- int composite;
- int serrations;
- int negative_vsync;
- int negative_hsync;
- } digital;
+ struct
+ {
+ int bipolar;
+ int serrations;
+ int sync_on_green;
+ } analog;
+
+ struct
+ {
+ int composite;
+ int serrations;
+ int negative_vsync;
+ int negative_hsync;
+ } digital;
} connector;
};
struct MonitorInfo
{
- int checksum;
- char manufacturer_code[4];
- int product_code;
- unsigned int serial_number;
+ int checksum;
+ char manufacturer_code[4];
+ int product_code;
+ unsigned int serial_number;
- int production_week; /* -1 if not specified */
- int production_year; /* -1 if not specified */
- int model_year; /* -1 if not specified */
+ int production_week; /* -1 if not specified */
+ int production_year; /* -1 if not specified */
+ int model_year; /* -1 if not specified */
- int major_version;
- int minor_version;
+ int major_version;
+ int minor_version;
- int is_digital;
+ int is_digital;
union
{
- struct
- {
- int bits_per_primary;
- Interface interface;
- int rgb444;
- int ycrcb444;
- int ycrcb422;
- } digital;
-
- struct
- {
- double video_signal_level;
- double sync_signal_level;
- double total_signal_level;
-
- int blank_to_black;
-
- int separate_hv_sync;
- int composite_sync_on_h;
- int composite_sync_on_green;
- int serration_on_vsync;
- ColorType color_type;
- } analog;
+ struct
+ {
+ int bits_per_primary;
+ Interface interface;
+ int rgb444;
+ int ycrcb444;
+ int ycrcb422;
+ } digital;
+
+ struct
+ {
+ double video_signal_level;
+ double sync_signal_level;
+ double total_signal_level;
+
+ int blank_to_black;
+
+ int separate_hv_sync;
+ int composite_sync_on_h;
+ int composite_sync_on_green;
+ int serration_on_vsync;
+ ColorType color_type;
+ } analog;
} connector;
- int width_mm; /* -1 if not specified */
- int height_mm; /* -1 if not specified */
- double aspect_ratio; /* -1.0 if not specififed */
-
- double gamma; /* -1.0 if not specified */
-
- int standby;
- int suspend;
- int active_off;
-
- int srgb_is_standard;
- int preferred_timing_includes_native;
- int continuous_frequency;
-
- double red_x;
- double red_y;
- double green_x;
- double green_y;
- double blue_x;
- double blue_y;
- double white_x;
- double white_y;
-
- Timing established[24]; /* Terminated by 0x0x0 */
- Timing standard[8];
-
- int n_detailed_timings;
- DetailedTiming detailed_timings[4]; /* If monitor has a preferred
- * mode, it is the first one
- * (whether it has, is
- * determined by the
- * preferred_timing_includes
- * bit.
- */
+ int width_mm; /* -1 if not specified */
+ int height_mm; /* -1 if not specified */
+ double aspect_ratio; /* -1.0 if not specififed */
+
+ double gamma; /* -1.0 if not specified */
+
+ int standby;
+ int suspend;
+ int active_off;
+
+ int srgb_is_standard;
+ int preferred_timing_includes_native;
+ int continuous_frequency;
+
+ double red_x;
+ double red_y;
+ double green_x;
+ double green_y;
+ double blue_x;
+ double blue_y;
+ double white_x;
+ double white_y;
+
+ Timing established[24]; /* Terminated by 0x0x0 */
+ Timing standard[8];
+
+ int n_detailed_timings;
+ DetailedTiming detailed_timings[4]; /* If monitor has a preferred
+ * mode, it is the first one
+ * (whether it has, is
+ * determined by the
+ * preferred_timing_includes
+ * bit.
+ */
/* Optional product description */
- char dsc_serial_number[14];
- char dsc_product_name[14];
- char dsc_string[14]; /* Unspecified ASCII data */
+ char dsc_serial_number[14];
+ char dsc_product_name[14];
+ char dsc_string[14]; /* Unspecified ASCII data */
};
MonitorInfo *decode_edid (const uchar *data);
-char *make_display_name (const MonitorInfo *info);
+char *make_display_name (const MonitorInfo *info, guint output);
#endif
diff --git a/dialogs/display-settings/foo-marshal.c b/dialogs/display-settings/foo-marshal.c
new file mode 100644
index 0000000..0f4ff8f
--- /dev/null
+++ b/dialogs/display-settings/foo-marshal.c
@@ -0,0 +1,280 @@
+
+#include <glib-object.h>
+#include "foo-marshal.h"
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:OBJECT,OBJECT (marshal.list:1) */
+void
+foo_marshal_VOID__OBJECT_OBJECT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__OBJECT_OBJECT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_object (param_values + 1),
+ g_marshal_value_peek_object (param_values + 2),
+ data2);
+}
+
+/* VOID:UINT,UINT,UINT,UINT (marshal.list:2) */
+void
+foo_marshal_VOID__UINT_UINT_UINT_UINT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__UINT_UINT_UINT_UINT) (gpointer data1,
+ guint arg_1,
+ guint arg_2,
+ guint arg_3,
+ guint arg_4,
+ gpointer data2);
+ register GMarshalFunc_VOID__UINT_UINT_UINT_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 5);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__UINT_UINT_UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ g_marshal_value_peek_uint (param_values + 3),
+ g_marshal_value_peek_uint (param_values + 4),
+ data2);
+}
+
+/* VOID:UINT,UINT (marshal.list:3) */
+void
+foo_marshal_VOID__UINT_UINT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
+ guint arg_1,
+ guint arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__UINT_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ data2);
+}
+
+/* VOID:BOXED (marshal.list:4) */
+
+/* VOID:BOXED,BOXED (marshal.list:5) */
+void
+foo_marshal_VOID__BOXED_BOXED (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__BOXED_BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__BOXED_BOXED callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__BOXED_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ data2);
+}
+
+/* VOID:POINTER,BOXED,POINTER (marshal.list:6) */
+void
+foo_marshal_VOID__POINTER_BOXED_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_BOXED_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer arg_3,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_BOXED_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 4);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_BOXED_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ g_marshal_value_peek_pointer (param_values + 3),
+ data2);
+}
+
+/* VOID:POINTER,POINTER (marshal.list:7) */
+void
+foo_marshal_VOID__POINTER_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_pointer (param_values + 2),
+ data2);
+}
+
diff --git a/dialogs/display-settings/foo-marshal.h b/dialogs/display-settings/foo-marshal.h
new file mode 100644
index 0000000..cc91707
--- /dev/null
+++ b/dialogs/display-settings/foo-marshal.h
@@ -0,0 +1,67 @@
+
+#ifndef __foo_marshal_MARSHAL_H__
+#define __foo_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* VOID:OBJECT,OBJECT (marshal.list:1) */
+extern void foo_marshal_VOID__OBJECT_OBJECT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:UINT,UINT,UINT,UINT (marshal.list:2) */
+extern void foo_marshal_VOID__UINT_UINT_UINT_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:UINT,UINT (marshal.list:3) */
+extern void foo_marshal_VOID__UINT_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:BOXED (marshal.list:4) */
+#define foo_marshal_VOID__BOXED g_cclosure_marshal_VOID__BOXED
+
+/* VOID:BOXED,BOXED (marshal.list:5) */
+extern void foo_marshal_VOID__BOXED_BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:POINTER,BOXED,POINTER (marshal.list:6) */
+extern void foo_marshal_VOID__POINTER_BOXED_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:POINTER,POINTER (marshal.list:7) */
+extern void foo_marshal_VOID__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __foo_marshal_MARSHAL_H__ */
+
diff --git a/dialogs/display-settings/main.c b/dialogs/display-settings/main.c
index a6f90a2..b904213 100644
--- a/dialogs/display-settings/main.c
+++ b/dialogs/display-settings/main.c
@@ -28,6 +28,8 @@
#include <string.h>
#endif
+#include <math.h>
+
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
@@ -47,10 +49,13 @@
#include "minimal-display-dialog_ui.h"
#include "identity-popup_ui.h"
+#include "scrollarea.h"
+
+#define MARGIN 16
+
enum
{
COLUMN_OUTPUT_NAME,
- COLUMN_OUTPUT_ICON,
COLUMN_OUTPUT_ID,
N_OUTPUT_COLUMNS
};
@@ -64,19 +69,10 @@ enum
-typedef struct _XfceRelation XfceRelation;
typedef struct _XfceRotation XfceRotation;
-struct _XfceRelation
-{
- XfceOutputRelation relation;
- const gchar *name;
-};
-
-
-
struct _XfceRotation
{
Rotation rotation;
@@ -85,18 +81,6 @@ struct _XfceRotation
-/* Xrandr relation name conversion */
-static const XfceRelation relation_names[] =
-{
- { XFCE_RANDR_PLACEMENT_MIRROR, N_("Same as") },
- { XFCE_RANDR_PLACEMENT_UP, N_("Above") },
- { XFCE_RANDR_PLACEMENT_DOWN, N_("Below") },
- { XFCE_RANDR_PLACEMENT_RIGHT, N_("Right of") },
- { XFCE_RANDR_PLACEMENT_LEFT, N_("Left of") }
-};
-
-
-
/* Xrandr rotation name conversion */
static const XfceRotation rotation_names[] =
{
@@ -127,7 +111,6 @@ typedef struct
} ConfirmationDialog;
-
/* Option entries */
static GdkNativeWindow opt_socket_id = 0;
static gboolean opt_version = FALSE;
@@ -143,7 +126,7 @@ static GOptionEntry option_entries[] =
/* Global xfconf channel */
static XfconfChannel *display_channel;
-/* output currently selected in the treeview */
+/* output currently selected in the combobox */
static guint active_output;
/* Pointer to the used randr structure */
@@ -158,6 +141,14 @@ gboolean show_popups = FALSE;
gboolean supports_alpha = FALSE;
+/* Graphical randr */
+GtkWidget *randr_gui_area = NULL;
+GList *current_outputs = NULL;
+
+/* Outputs Combobox TODO Use App() to store constant widgets once the cruft is cleaned */
+GtkWidget *randr_outputs_combobox = NULL;
+GtkWidget *apply_button = NULL;
+
static void display_settings_minimal_only_display1_toggled (GtkToggleButton *button,
@@ -172,6 +163,34 @@ static void display_settings_minimal_extend_right_toggled (GtkToggleButton *b
static void display_settings_minimal_only_display2_toggled (GtkToggleButton *button,
GtkBuilder *builder);
+static void
+display_settings_changed (void)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(apply_button), TRUE);
+}
+
+static XfceOutputInfo*
+get_nth_xfce_output_info(gint id)
+{
+ XfceOutputInfo *output;
+ if (current_outputs)
+ output = g_list_nth (current_outputs, id)->data;
+
+ if (output)
+ return output;
+
+ return NULL;
+}
+
+static void
+initialize_connected_outputs (void)
+{
+ if (current_outputs)
+ {
+ g_list_free(current_outputs);
+ current_outputs = NULL;
+ }
+}
static guint
display_settings_get_n_active_outputs (void)
@@ -239,7 +258,6 @@ display_settings_update_time_label (ConfirmationDialog *confirmation_dialog)
return TRUE;
}
-
/* Returns true if the configuration is to be kept or false if it is to
* be reverted */
static gboolean
@@ -292,209 +310,15 @@ display_setting_timed_confirmation (GtkBuilder *main_builder)
return ((response_id == 2) ? TRUE : FALSE);
}
-
-
-static void
-display_setting_positions_changed (GtkComboBox *combobox,
- GtkBuilder *builder)
-{
- GObject *display_combobox;
- XfceOutputRelation previous_relation;
- gint value, selected_display, previous_related_to;
-
- display_combobox = gtk_builder_get_object (builder, "randr-active-displays");
-
- if (!display_setting_combo_box_get_value (combobox, &value))
- return;
-
- if (!display_setting_combo_box_get_value (GTK_COMBO_BOX (display_combobox),
- &selected_display))
- return;
-
- /* Skip if the display combobox hasn't made a selection yet */
- if (selected_display == -1) return;
-
- /* back up */
- previous_relation = xfce_randr->relation[active_output];
- previous_related_to = xfce_randr->related_to[active_output];
-
- /* Save changes to currently active display */
- xfce_randr->relation[active_output] = value;
- xfce_randr->related_to[active_output] = selected_display;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, TRUE);
-
- /* Save changes to selected display */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- selected_display, FALSE);
-
- /* Apply all changes */
- xfce_randr_apply (xfce_randr, "Default", display_channel);
-
- /* Ask user confirmation */
- if (!display_setting_timed_confirmation (builder))
- {
- /* Restore the currently active display */
- xfce_randr->relation[active_output] = previous_relation;
- xfce_randr->related_to[active_output] = previous_related_to;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, TRUE);
- /* Restore the selected display */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- selected_display, FALSE);
-
- xfce_randr_apply (xfce_randr, "Default", display_channel);
- }
-}
-
-
-
-static void
-display_setting_positions_populate (GtkBuilder *builder)
-{
- GtkTreeModel *model;
- GObject *combobox, *label, *mirror_displays;
- GtkTreeIter iter;
- guint n;
-
- /* Get the positions combo box store and clear it */
- combobox = gtk_builder_get_object (builder, "randr-position");
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combobox));
- gtk_list_store_clear (GTK_LIST_STORE (model));
-
- label = gtk_builder_get_object (builder, "label-position");
- if (xfce_randr->noutput > 1)
- {
- gtk_widget_show (GTK_WIDGET (label));
- gtk_widget_show (GTK_WIDGET (combobox));
- }
- else
- {
- gtk_widget_hide (GTK_WIDGET (label));
- gtk_widget_hide (GTK_WIDGET (combobox));
- return;
- }
-
- /* Only make the combobox interactive if there is more than one output,
- and if they are not in mirror mode */
- mirror_displays = gtk_builder_get_object (builder, "mirror-displays");
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (mirror_displays)) ||
- display_settings_get_n_active_outputs () <= 1)
- {
- gtk_widget_set_sensitive (GTK_WIDGET (combobox), FALSE);
- return;
- }
- gtk_widget_set_sensitive (GTK_WIDGET (combobox), TRUE);
-
- /* Block the "changed" signal to avoid triggering the confirmation dialog */
- g_signal_handlers_block_by_func (combobox, display_setting_positions_changed,
- builder);
-
- /* Try to insert the relations */
- for (n = 0; n < G_N_ELEMENTS (relation_names); n++)
- {
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- gtk_list_store_set (GTK_LIST_STORE (model), &iter,
- COLUMN_COMBO_NAME, _(relation_names[n].name),
- COLUMN_COMBO_VALUE, relation_names[n].relation, -1);
-
- /* Select the active relation */
- if (relation_names[n].relation == xfce_randr->relation[active_output])
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox), &iter);
- }
-
- /* Unblock the signal */
- g_signal_handlers_unblock_by_func (combobox, display_setting_positions_changed,
- builder);
-}
-
-static void
-display_setting_active_displays_changed (GtkComboBox *combobox,
- GtkBuilder *builder)
-{
- GObject *position_combobox;
- gint value;
-
- if (!display_setting_combo_box_get_value (combobox, &value))
- return;
-
- position_combobox = gtk_builder_get_object (builder, "randr-position");
-
- display_setting_positions_changed (GTK_COMBO_BOX (position_combobox), builder);
-}
-
-static void
-display_setting_active_displays_populate (GtkBuilder *builder)
-{
- GtkTreeModel *model;
- GObject *combobox, *mirror_displays;
- guint n;
- GtkTreeIter iter;
-
- /* Get the active-displays combo box store and clear it */
- combobox = gtk_builder_get_object (builder, "randr-active-displays");
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combobox));
- gtk_list_store_clear (GTK_LIST_STORE (model));
-
- if (xfce_randr->noutput > 1)
- gtk_widget_show (GTK_WIDGET (combobox));
- else
- {
- gtk_widget_hide (GTK_WIDGET (combobox));
- return;
- }
-
- /* Only make the combobox interactive if there is more than one output,
- and if they are not in mirror mode */
- mirror_displays = gtk_builder_get_object (builder, "mirror-displays");
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (mirror_displays)) ||
- display_settings_get_n_active_outputs () <= 1)
- {
- gtk_widget_set_sensitive (GTK_WIDGET (combobox), FALSE);
- return;
- }
- gtk_widget_set_sensitive (GTK_WIDGET (combobox), TRUE);
-
- /* Block the "changed" signal to avoid triggering the confirmation dialog */
- g_signal_handlers_block_by_func (combobox, display_setting_active_displays_changed,
- builder);
-
- /* Insert all active displays */
- for (n = 0; n < xfce_randr->noutput; ++n)
- {
- if (xfce_randr->mode[n] == None || n == active_output)
- continue;
-
- /* Insert display name */
- gtk_list_store_append (GTK_LIST_STORE (model), &iter);
- gtk_list_store_set (GTK_LIST_STORE (model), &iter,
- COLUMN_COMBO_NAME, xfce_randr->friendly_name[n],
- COLUMN_COMBO_VALUE, n, -1);
-
- /* Select the active related output */
- if (n == xfce_randr->related_to[active_output])
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combobox), &iter);
- }
-
- /* Unblock the signal */
- g_signal_handlers_unblock_by_func (combobox, display_setting_active_displays_changed,
- builder);
-}
-
-
-
static void
display_setting_reflections_changed (GtkComboBox *combobox,
GtkBuilder *builder)
{
gint value;
- Rotation old_rotation;
if (!display_setting_combo_box_get_value (combobox, &value))
return;
- old_rotation = xfce_randr->rotation[active_output];
-
/* Remove existing reflection */
xfce_randr->rotation[active_output] &= ~XFCE_RANDR_REFLECTIONS_MASK;
@@ -502,21 +326,10 @@ display_setting_reflections_changed (GtkComboBox *combobox,
xfce_randr->rotation[active_output] |= value;
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, FALSE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
-
- /* Ask user confirmation */
- if (!display_setting_timed_confirmation (builder))
- {
- xfce_randr->rotation[active_output] = old_rotation;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, FALSE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
- }
+ display_settings_changed ();
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
}
-
static void
display_setting_reflections_populate (GtkBuilder *builder)
{
@@ -576,40 +389,27 @@ display_setting_reflections_populate (GtkBuilder *builder)
builder);
}
-
-
static void
display_setting_rotations_changed (GtkComboBox *combobox,
GtkBuilder *builder)
{
- Rotation old_rotation;
+ XfceOutputInfo *output;
gint value;
if (!display_setting_combo_box_get_value (combobox, &value))
return;
/* Set new rotation */
- old_rotation = xfce_randr->rotation[active_output];
xfce_randr->rotation[active_output] &= ~XFCE_RANDR_ROTATIONS_MASK;
xfce_randr->rotation[active_output] |= value;
+ output = get_nth_xfce_output_info(active_output);
+ output->rotation = xfce_randr->rotation[active_output];
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, TRUE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
-
- /* Ask user confirmation */
- if (!display_setting_timed_confirmation (builder))
- {
- xfce_randr->rotation[active_output] = old_rotation;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, TRUE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
- }
+ display_settings_changed ();
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
}
-
-
static void
display_setting_rotations_populate (GtkBuilder *builder)
{
@@ -666,39 +466,22 @@ display_setting_rotations_populate (GtkBuilder *builder)
builder);
}
-
-
static void
display_setting_refresh_rates_changed (GtkComboBox *combobox,
GtkBuilder *builder)
{
- RRMode old_mode;
gint value;
if (!display_setting_combo_box_get_value (combobox, &value))
return;
/* Set new mode */
- old_mode = xfce_randr->mode[active_output];
xfce_randr->mode[active_output] = value;
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, FALSE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
-
- /* Ask user confirmation */
- if (!display_setting_timed_confirmation (builder))
- {
- xfce_randr->mode[active_output] = old_mode;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, FALSE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
- }
+ display_settings_changed ();
}
-
-
static void
display_setting_refresh_rates_populate (GtkBuilder *builder)
{
@@ -771,36 +554,30 @@ static void
display_setting_resolutions_changed (GtkComboBox *combobox,
GtkBuilder *builder)
{
- RRMode old_mode;
+ XfceOutputInfo *output;
+ const XfceRRMode *mode;
gint value;
if (!display_setting_combo_box_get_value (combobox, &value))
return;
/* Set new resolution */
- old_mode = xfce_randr->mode[active_output];
xfce_randr->mode[active_output] = value;
+ /* Apply resolution to gui */
+ output = get_nth_xfce_output_info (active_output);
+ mode = xfce_randr_find_mode_by_id (xfce_randr, active_output, value);
+ output->width = mode->width;
+ output->height = mode->height;
+
/* Update refresh rates */
display_setting_refresh_rates_populate (builder);
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, TRUE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
-
- /* Ask user confirmation */
- if (!display_setting_timed_confirmation (builder))
- {
- xfce_randr->mode[active_output] = old_mode;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, TRUE);
- xfce_randr_apply (xfce_randr, "Default", display_channel);
- }
+ display_settings_changed ();
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
}
-
-
static void
display_setting_resolutions_populate (GtkBuilder *builder)
{
@@ -991,7 +768,6 @@ display_setting_identity_popup_expose (GtkWidget *popup,
return FALSE;
}
-
static GtkWidget *
display_setting_identity_display (gint display_id)
{
@@ -1090,23 +866,13 @@ static void
display_setting_mirror_displays_toggled (GtkToggleButton *togglebutton,
GtkBuilder *builder)
{
- GObject *positions, *active_displays;
- guint n;
+ XfceOutputInfo *output;
+ guint n, pos = 0;
RRMode mode;
if (!xfce_randr)
return;
- positions = gtk_builder_get_object (builder, "randr-position");
- active_displays = gtk_builder_get_object (builder, "randr-active-displays");
-
- if (display_settings_get_n_active_outputs () <= 1)
- {
- gtk_widget_set_sensitive (GTK_WIDGET (positions), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (active_displays), FALSE);
- return;
- }
-
if (gtk_toggle_button_get_active (togglebutton))
{
/* Activate mirror-mode with a single mode for all of them */
@@ -1119,18 +885,11 @@ display_setting_mirror_displays_toggled (GtkToggleButton *togglebutton,
if (mode != None)
xfce_randr->mode[n] = mode;
- xfce_randr->relation[n] = XFCE_RANDR_PLACEMENT_MIRROR;
- xfce_randr->related_to[n] = active_output;
xfce_randr->rotation[n] = RR_Rotate_0;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- n, TRUE);
+ xfce_randr->mirrored[n] = TRUE;
+ xfce_randr->position[n].x = 0;
+ xfce_randr->position[n].y = 0;
}
-
- xfce_randr_apply (xfce_randr, "Default", display_channel);
-
- /* Disable the position comboboxes */
- gtk_widget_set_sensitive (GTK_WIDGET (positions), FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (active_displays), FALSE);
}
else
{
@@ -1138,18 +897,30 @@ display_setting_mirror_displays_toggled (GtkToggleButton *togglebutton,
for (n = 0; n < xfce_randr->noutput; n++)
{
xfce_randr->mode[n] = xfce_randr_preferred_mode (xfce_randr, n);
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- n, TRUE);
- }
+ xfce_randr->mirrored[n] = FALSE;
+ xfce_randr->position[n].x = pos;
+ xfce_randr->position[n].y = 0;
- xfce_randr_apply (xfce_randr, "Default", display_channel);
+ pos = xfce_randr_mode_width (xfce_randr_find_mode_by_id (xfce_randr, n, xfce_randr->mode[n]), 0);
+ }
+ }
- /* Re-enable the position comboboxes */
- gtk_widget_set_sensitive (GTK_WIDGET (positions), TRUE);
- gtk_widget_set_sensitive (GTK_WIDGET (active_displays), TRUE);
+ /* Apply resolution to gui */
+ for (n = 0; n < xfce_randr->noutput; n++)
+ {
+ output = get_nth_xfce_output_info (n);
+ output->rotation = xfce_randr->rotation[n];
+ output->x = xfce_randr->position[n].x;
+ output->y = xfce_randr->position[n].y;
+ output->mirrored = xfce_randr->mirrored[n];
+ output->width = xfce_randr_mode_width (xfce_randr_find_mode_by_id (xfce_randr, n, xfce_randr->mode[n]), 0);
+ output->height = xfce_randr_mode_height (xfce_randr_find_mode_by_id (xfce_randr, n, xfce_randr->mode[n]), 0);
}
-}
+ /* Apply the changes */
+ display_settings_changed ();
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
+}
static void
display_setting_mirror_displays_populate (GtkBuilder *builder)
@@ -1194,7 +965,7 @@ display_setting_mirror_displays_populate (GtkBuilder *builder)
continue;
cloned &= (xfce_randr->mode[n] == mode &&
- xfce_randr->relation[n] == XFCE_RANDR_PLACEMENT_MIRROR);
+ xfce_randr->mirrored[n]);
if (!cloned)
break;
@@ -1207,8 +978,6 @@ display_setting_mirror_displays_populate (GtkBuilder *builder)
builder);
}
-
-
static void
display_setting_output_toggled (GtkToggleButton *togglebutton,
GtkBuilder *builder)
@@ -1247,21 +1016,22 @@ display_setting_output_toggled (GtkToggleButton *togglebutton,
}
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, FALSE);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, active_output);
xfce_randr_apply (xfce_randr, "Default", display_channel);
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
+
/* Ask user confirmation */
if (!display_setting_timed_confirmation (builder))
{
xfce_randr->mode[active_output] = old_mode;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- active_output, FALSE);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, active_output);
xfce_randr_apply (xfce_randr, "Default", display_channel);
+
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
}
}
-
static void
display_setting_output_status_populate (GtkBuilder *builder)
{
@@ -1290,23 +1060,19 @@ display_setting_output_status_populate (GtkBuilder *builder)
builder);
}
-
-
static void
-display_settings_treeview_selection_changed (GtkTreeSelection *selection,
- GtkBuilder *builder)
+display_settings_combobox_selection_changed (GtkComboBox *combobox,
+ GtkBuilder *builder)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *popup;
- gboolean has_selection;
gint active_id, previous_id;
- /* Get the selection */
- has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
- if (G_LIKELY (has_selection))
+ if (gtk_combo_box_get_active_iter (combobox, &iter))
{
/* Get the output info */
+ model = gtk_combo_box_get_model (combobox);
gtk_tree_model_get (model, &iter, COLUMN_OUTPUT_ID, &active_id, -1);
/* Get the new active screen or output */
@@ -1314,8 +1080,6 @@ display_settings_treeview_selection_changed (GtkTreeSelection *selection,
active_output = active_id;
/* Update the combo boxes */
- display_setting_positions_populate (builder);
- display_setting_active_displays_populate (builder);
display_setting_output_status_populate (builder);
display_setting_mirror_displays_populate (builder);
display_setting_resolutions_populate (builder);
@@ -1330,66 +1094,48 @@ display_settings_treeview_selection_changed (GtkTreeSelection *selection,
popup = g_hash_table_lookup (display_popups, GINT_TO_POINTER (active_id));
if (popup)
gtk_widget_queue_draw (popup);
+
+ if (randr_gui_area)
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
}
}
-
-
static void
-display_settings_treeview_populate (GtkBuilder *builder)
+display_settings_combobox_populate (GtkBuilder *builder)
{
guint m;
GtkListStore *store;
- GObject *treeview;
+ GObject *combobox;
GtkTreeIter iter;
- GdkPixbuf *display_icon, *lucent_display_icon;
- GtkTreeSelection *selection;
gboolean selected = FALSE;
/* Create a new list store */
store = gtk_list_store_new (N_OUTPUT_COLUMNS,
G_TYPE_STRING, /* COLUMN_OUTPUT_NAME */
- GDK_TYPE_PIXBUF, /* COLUMN_OUTPUT_ICON */
G_TYPE_INT); /* COLUMN_OUTPUT_ID */
- /* Set the treeview model */
- treeview = gtk_builder_get_object (builder, "randr-outputs");
- gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
-
- /* Get the display icon */
- display_icon =
- gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "display-icon",
- 32,
- GTK_ICON_LOOKUP_GENERIC_FALLBACK,
- NULL);
-
- lucent_display_icon = NULL;
+ /* Set up the new combobox which will replace the above combobox */
+ combobox = gtk_builder_get_object (builder, "randr-outputs");
+ gtk_combo_box_set_model (GTK_COMBO_BOX (combobox), GTK_TREE_MODEL (store));
/* Walk all the connected outputs */
for (m = 0; m < xfce_randr->noutput; ++m)
{
- if (xfce_randr->mode[m] == None && lucent_display_icon == NULL)
- lucent_display_icon =
- exo_gdk_pixbuf_lucent (display_icon, 50);
-
/* Insert the output in the store */
gtk_list_store_append (store, &iter);
if (xfce_randr->mode[m] == None)
gtk_list_store_set (store, &iter,
COLUMN_OUTPUT_NAME, xfce_randr->friendly_name[m],
- COLUMN_OUTPUT_ICON, lucent_display_icon,
COLUMN_OUTPUT_ID, m, -1);
else
gtk_list_store_set (store, &iter,
COLUMN_OUTPUT_NAME, xfce_randr->friendly_name[m],
- COLUMN_OUTPUT_ICON, display_icon,
COLUMN_OUTPUT_ID, m, -1);
/* Select active output */
if (m == active_output)
{
- gtk_tree_selection_select_iter (selection, &iter);
+ gtk_combo_box_set_active (GTK_COMBO_BOX(combobox), m);
selected = TRUE;
}
}
@@ -1397,19 +1143,12 @@ display_settings_treeview_populate (GtkBuilder *builder)
/* If nothing was selected the active output is no longer valid,
* select the last display in the list. */
if (!selected)
- gtk_tree_selection_select_iter (selection, &iter);
+ gtk_combo_box_set_active (GTK_COMBO_BOX(combobox), m);
/* Release the store */
g_object_unref (G_OBJECT (store));
-
- /* Release the icons */
- g_object_unref (display_icon);
- if (lucent_display_icon != NULL)
- g_object_unref (lucent_display_icon);
}
-
-
static void
display_settings_combo_box_create (GtkComboBox *combobox)
{
@@ -1428,8 +1167,6 @@ display_settings_combo_box_create (GtkComboBox *combobox)
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combobox), renderer, "text", COLUMN_COMBO_NAME);
}
-
-
static void
display_settings_dialog_response (GtkDialog *dialog,
gint response_id,
@@ -1477,29 +1214,33 @@ on_identify_displays_toggled (GtkWidget *widget, GtkBuilder *builder)
set_display_popups_visible (show_popups);
}
+static void
+display_setting_apply (GtkWidget *widget, GtkBuilder *builder)
+{
+ guint i = 0;
+
+ for (i=0; i < xfce_randr->noutput; i++)
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, i);
+ xfce_randr_apply (xfce_randr, "Default", display_channel);
+ /* TODO: Restore Confirmation Dialog */
+ gtk_widget_set_sensitive(widget, FALSE);
+}
static GtkWidget *
display_settings_dialog_new (GtkBuilder *builder)
{
- GObject *treeview;
- GtkCellRenderer *renderer;
- GtkTreeSelection *selection;
GObject *combobox;
+ GtkCellRenderer *renderer;
GObject *label, *check, *mirror, *identify;
- /* Get the treeview */
- treeview = gtk_builder_get_object (builder, "randr-outputs");
- gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), COLUMN_OUTPUT_NAME);
-
- /* Icon renderer */
- renderer = gtk_cell_renderer_pixbuf_new ();
- gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), 0, "", renderer, "pixbuf", COLUMN_OUTPUT_ICON, NULL);
- g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_DND, NULL);
+ /* Get the combobox */
+ combobox = gtk_builder_get_object (builder, "randr-outputs");
/* Text renderer */
renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), 1, "", renderer, "text", COLUMN_OUTPUT_NAME, NULL);
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
+ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), renderer, "text", COLUMN_OUTPUT_NAME, NULL);
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
/* Identification popups */
@@ -1508,10 +1249,8 @@ display_settings_dialog_new (GtkBuilder *builder)
g_signal_connect (G_OBJECT (identify), "toggled", G_CALLBACK (on_identify_displays_toggled), builder);
set_display_popups_visible (show_popups);
- /* Treeview selection */
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
- g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (display_settings_treeview_selection_changed), builder);
+ /* Display selection combobox */
+ g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (display_settings_combobox_selection_changed), builder);
/* Setup the combo boxes */
check = gtk_builder_get_object (builder, "output-on");
@@ -1537,14 +1276,6 @@ display_settings_dialog_new (GtkBuilder *builder)
gtk_widget_show (GTK_WIDGET (combobox));
g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (display_setting_reflections_changed), builder);
- combobox = gtk_builder_get_object (builder, "randr-position");
- display_settings_combo_box_create (GTK_COMBO_BOX (combobox));
- g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (display_setting_positions_changed), builder);
-
- combobox = gtk_builder_get_object (builder, "randr-active-displays");
- display_settings_combo_box_create (GTK_COMBO_BOX (combobox));
- g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (display_setting_active_displays_changed), builder);
-
combobox = gtk_builder_get_object (builder, "randr-resolution");
display_settings_combo_box_create (GTK_COMBO_BOX (combobox));
g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (display_setting_resolutions_changed), builder);
@@ -1561,8 +1292,12 @@ display_settings_dialog_new (GtkBuilder *builder)
xfconf_g_property_bind (display_channel, "/Notify", G_TYPE_BOOLEAN, check,
"active");
- /* Populate the treeview */
- display_settings_treeview_populate (builder);
+ apply_button = GTK_WIDGET(gtk_builder_get_object (builder, "apply"));
+ g_signal_connect (G_OBJECT (apply_button), "clicked", G_CALLBACK (display_setting_apply), builder);
+ gtk_widget_set_sensitive(apply_button, FALSE);
+
+ /* Populate the combobox */
+ display_settings_combobox_populate (builder);
return GTK_WIDGET (gtk_builder_get_object (builder, "display-dialog"));
}
@@ -1590,8 +1325,8 @@ display_settings_minimal_only_display1_toggled (GtkToggleButton *button,
xfce_randr->mode[1] = None;
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel, 0, FALSE);
- xfce_randr_save_output (xfce_randr, "Default", display_channel, 1, FALSE);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, 0);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, 1);
xfce_randr_apply (xfce_randr, "Default", display_channel);
gtk_widget_set_sensitive (GTK_WIDGET(buttons), TRUE);
@@ -1620,8 +1355,8 @@ display_settings_minimal_only_display2_toggled (GtkToggleButton *button,
xfce_randr->mode[0] = None;
/* Apply the changes */
- xfce_randr_save_output (xfce_randr, "Default", display_channel, 0, FALSE);
- xfce_randr_save_output (xfce_randr, "Default", display_channel, 1, FALSE);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, 0);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, 1);
xfce_randr_apply (xfce_randr, "Default", display_channel);
gtk_widget_set_sensitive (GTK_WIDGET(buttons), TRUE);
@@ -1646,7 +1381,7 @@ display_settings_minimal_mirror_displays_toggled (GtkToggleButton *button,
buttons = gtk_builder_get_object (builder, "buttons");
gtk_widget_set_sensitive (GTK_WIDGET(buttons), FALSE);
-
+
/* Activate mirror-mode with a single mode for all of them */
mode = xfce_randr_clonable_mode (xfce_randr);
/* Configure each available display for mirroring */
@@ -1657,11 +1392,11 @@ display_settings_minimal_mirror_displays_toggled (GtkToggleButton *button,
if (mode != None)
xfce_randr->mode[n] = mode;
- xfce_randr->relation[n] = XFCE_RANDR_PLACEMENT_MIRROR;
- xfce_randr->related_to[n] = 0;
+ xfce_randr->mirrored[n] = TRUE;
xfce_randr->rotation[n] = RR_Rotate_0;
- xfce_randr_save_output (xfce_randr, "Default", display_channel,
- n, TRUE);
+ xfce_randr->position[n].x = 0;
+ xfce_randr->position[n].y = 0;
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, n);
}
/* Apply all changes */
@@ -1674,6 +1409,7 @@ static void
display_settings_minimal_extend_right_toggled (GtkToggleButton *button,
GtkBuilder *builder)
{
+ const XfceRRMode *mode;
GObject *buttons;
guint n;
@@ -1699,16 +1435,17 @@ display_settings_minimal_extend_right_toggled (GtkToggleButton *button,
}
/* (Re)set Display1 to 0x0 */
- xfce_randr->relation[0] = 0;
- xfce_randr->related_to[0] = 0;
+ xfce_randr->position[0].x = 0;
+ xfce_randr->position[0].y = 0;
/* Move Display2 right of Display1 */
- xfce_randr->relation[1] = XFCE_RANDR_PLACEMENT_RIGHT;
- xfce_randr->related_to[1] = 0;
+ mode = xfce_randr_find_mode_by_id (xfce_randr, 0, xfce_randr->mode[0]);
+ xfce_randr->position[1].x = mode->width;
+ xfce_randr->position[1].y = 0;
/* Save changes to both displays */
- xfce_randr_save_output (xfce_randr, "Default", display_channel, 0, FALSE);
- xfce_randr_save_output (xfce_randr, "Default", display_channel, 1, TRUE);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, 0);
+ xfce_randr_save_output (xfce_randr, "Default", display_channel, 1);
/* Apply all changes */
xfce_randr_apply (xfce_randr, "Default", display_channel);
@@ -1716,8 +1453,6 @@ display_settings_minimal_extend_right_toggled (GtkToggleButton *button,
gtk_widget_set_sensitive (GTK_WIDGET (buttons), TRUE);
}
-
-
static GdkFilterReturn
screen_on_event (GdkXEvent *xevent,
GdkEvent *event,
@@ -1735,24 +1470,1207 @@ screen_on_event (GdkXEvent *xevent,
if (event_num == RRScreenChangeNotify)
{
xfce_randr_reload (xfce_randr);
- display_settings_treeview_populate (builder);
+ display_settings_combobox_populate (builder);
/* recreate the identify display popups */
g_hash_table_destroy (display_popups);
display_setting_identity_popups_populate ();
+ set_display_popups_visible(show_popups);
}
+ initialize_connected_outputs();
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area));
+
/* Pass the event on to GTK+ */
return GDK_FILTER_CONTINUE;
}
-static void
-display_settings_show_main_dialog (GdkDisplay *display)
+/* Xfce RANDR GUI **TODO** Place these functions in a sensible location */
+static gboolean
+get_mirrored_configuration (void)
{
- GtkBuilder *builder;
- GtkWidget *dialog, *plug;
- GObject *plug_child;
+ gboolean cloned = FALSE;
+ RRMode mode = None;
+ guint n;
+
+ if (!xfce_randr)
+ return FALSE;
+
+ if (!xfce_randr->noutput > 1)
+ return FALSE;
+
+ /* Can outputs be cloned? */
+ if (display_settings_get_n_active_outputs () > 1)
+ mode = xfce_randr_clonable_mode (xfce_randr);
+
+ if (mode == None)
+ return FALSE;
+
+ /* Check if mirror settings are on */
+ for (n = 0; n < xfce_randr->noutput; n++)
+ {
+ if (xfce_randr->mode[n] == None)
+ continue;
+
+ cloned = xfce_randr->mirrored[n];
+
+ if (!cloned)
+ break;
+ }
+
+ return cloned;
+}
+
+static XfceOutputInfo *convert_xfce_output_info (gint output_id)
+{
+ XfceOutputInfo *output;
+ const XfceRRMode *mode, *preferred;
+ RRMode preferred_mode;
+ gint x, y;
+
+ xfce_randr_get_positions(xfce_randr, output_id, &x, &y);
+ mode = xfce_randr_find_mode_by_id (xfce_randr, output_id, xfce_randr->mode[output_id]);
+ preferred_mode = xfce_randr_preferred_mode(xfce_randr, output_id);
+ preferred = xfce_randr_find_mode_by_id (xfce_randr, output_id, preferred_mode);
+ output = g_new0 (XfceOutputInfo, 1);
+ output->id = output_id;
+ output->x = x;
+ output->y = y;
+ output->user_data = NULL;
+ output->display_name = xfce_randr->friendly_name[output_id];
+ output->connected = TRUE;
+ output->on = xfce_randr->mode[output_id] != None;
+ output->pref_width = preferred->width;
+ output->pref_height = preferred->height;
+ if (output->on)
+ {
+ output->rotation = xfce_randr->rotation[output_id];
+ output->width = mode->width;
+ output->height = mode->height;
+ output->rate = mode->rate;
+ }
+ else
+ {
+ output->rotation = 0;
+ output->width = output->pref_width;
+ output->height = output->pref_height;
+ output->rate = 0.0;
+ }
+
+ return output;
+}
+
+typedef struct App App;
+typedef struct GrabInfo GrabInfo;
+
+struct App
+{
+ XfceOutputInfo *current_output;
+
+ GtkWidget *dialog;
+};
+
+static gboolean output_overlaps (XfceOutputInfo *output);
+static void get_geometry (XfceOutputInfo *output, int *w, int *h);
+
+static void
+lay_out_outputs_horizontally (void)
+{
+ gint x, y;
+ GList *list;
+
+ /* Lay out all the monitors horizontally when "mirror screens" is turned
+ * off, to avoid having all of them overlapped initially. We put the
+ * outputs turned off on the right-hand side.
+ */
+
+ x = 0;
+ y = 0;
+
+ /* First pass, all "on" outputs */
+ for (list = current_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *output;
+
+ output = list->data;
+ if (output->connected && output->on)
+ {
+ if ((gint)output->x + (gint)output->width > x || output->y > y)
+ {
+ y = output->y;
+ x = output->x + output->width;
+ }
+ }
+ }
+
+ /* Second pass, all the black screens */
+ for (list = current_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *output;
+
+ output = list->data;
+ if (!(output->connected && output->on))
+ {
+ output->x = x;
+ output->y = y;
+ x += output->width;
+ }
+ }
+}
+
+static void
+on_viewport_changed (FooScrollArea *scroll_area,
+ GdkRectangle *old_viewport,
+ GdkRectangle *new_viewport)
+{
+ foo_scroll_area_set_size (scroll_area,
+ new_viewport->width,
+ new_viewport->height);
+
+ foo_scroll_area_invalidate (scroll_area);
+}
+
+static void
+layout_set_font (PangoLayout *layout, const char *font)
+{
+ PangoFontDescription *desc =
+ pango_font_description_from_string (font);
+
+ if (desc)
+ {
+ pango_layout_set_font_description (layout, desc);
+
+ pango_font_description_free (desc);
+ }
+}
+
+static void
+get_geometry (XfceOutputInfo *output, int *w, int *h)
+{
+ if (output->on)
+ {
+ *h = output->height;
+ *w = output->width;
+ }
+ else
+ {
+ *h = output->pref_height;
+ *w = output->pref_width;
+ }
+ if ((output->rotation == RR_Rotate_90) || (output->rotation == RR_Rotate_270))
+ {
+ int tmp;
+ tmp = *h;
+ *h = *w;
+ *w = tmp;
+ }
+}
+
+static void
+initialize_connected_outputs_at_zero(void)
+{
+ GList *list = NULL;
+ gint start_x, start_y;
+
+ start_x = G_MAXINT;
+ start_y = G_MAXINT;
+
+ /* Get the left-most and top-most coordinates */
+ for (list = current_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *output = list->data;
+
+ start_x = MIN(start_x, output->x);
+ start_y = MIN(start_y, output->y);
+ }
+
+ /* Realign at zero */
+ for (list = current_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *output = list->data;
+
+ output->y = output->y - start_y;
+ output->x = output->x - start_x;
+
+ /* Update the Xfce Randr */
+ xfce_randr->position[output->id].x = output->x;
+ xfce_randr->position[output->id].y = output->y;
+ }
+}
+
+static GList *
+list_connected_outputs (gint *total_w, gint *total_h)
+{
+ gint dummy;
+ guint m;
+ GList *list = NULL;
+
+ if (!total_w)
+ total_w = &dummy;
+ if (!total_h)
+ total_h = &dummy;
+
+ /* Do we need to initialize the current outputs? */
+ if (!current_outputs)
+ {
+ for (m = 0; m < xfce_randr->noutput; ++m)
+ {
+ XfceOutputInfo *output = convert_xfce_output_info(m);
+
+ current_outputs = g_list_prepend (current_outputs, output);
+ }
+ current_outputs = g_list_reverse (current_outputs);
+
+ lay_out_outputs_horizontally();
+ }
+
+ *total_w = 0;
+ *total_h = 0;
+
+ for (list = current_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *output = list->data;
+
+ int w, h;
+
+ get_geometry (output, &w, &h);
+
+ *total_w = MAX(*total_w, w + output->x);
+ *total_h = MAX(*total_h, h + output->y);
+ }
+
+ return current_outputs;
+}
+
+static int
+get_n_connected (void)
+{
+ return xfce_randr->noutput;
+}
+
+static double
+compute_scale (void)
+{
+ int available_w, available_h;
+ gint total_w, total_h;
+ GdkRectangle viewport;
+
+ foo_scroll_area_get_viewport (FOO_SCROLL_AREA (randr_gui_area), &viewport);
+
+ list_connected_outputs (&total_w, &total_h);
+
+ available_w = viewport.width - 2 * MARGIN;
+ available_h = viewport.height - 2 * MARGIN;
+
+ return MIN ((double)available_w / (double)total_w, (double)available_h / (double)total_h);
+}
+
+typedef struct Edge
+{
+ XfceOutputInfo *output;
+ int x1, y1;
+ int x2, y2;
+} Edge;
+
+typedef struct Snap
+{
+ Edge *snapper; /* Edge that should be snapped */
+ Edge *snappee;
+ int dy, dx;
+} Snap;
+
+static void
+add_edge (XfceOutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges)
+{
+ Edge e;
+
+ e.x1 = x1;
+ e.x2 = x2;
+ e.y1 = y1;
+ e.y2 = y2;
+ e.output = output;
+
+ g_array_append_val (edges, e);
+}
+
+static void
+list_edges_for_output (XfceOutputInfo *output, GArray *edges)
+{
+ int x, y, w, h;
+
+ x = output->x;
+ y = output->y;
+ get_geometry (output, &w, &h);
+
+ /* Top, Bottom, Left, Right */
+ add_edge (output, x, y, x + w, y, edges);
+ add_edge (output, x, y + h, x + w, y + h, edges);
+ add_edge (output, x, y, x, y + h, edges);
+ add_edge (output, x + w, y, x + w, y + h, edges);
+}
+
+static void
+list_edges (GArray *edges)
+{
+ GList *connected_outputs = NULL;
+ GList *list;
+
+ connected_outputs = list_connected_outputs (NULL, NULL);
+
+ for (list = connected_outputs; list != NULL; list = list->next)
+ {
+ list_edges_for_output (list->data, edges);
+ }
+}
+
+static gboolean
+overlap (int s1, int e1, int s2, int e2)
+{
+ return (!(e1 < s2 || s1 >= e2));
+}
+
+static gboolean
+horizontal_overlap (Edge *snapper, Edge *snappee)
+{
+ if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2)
+ return FALSE;
+
+ return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2);
+}
+
+static gboolean
+vertical_overlap (Edge *snapper, Edge *snappee)
+{
+ if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2)
+ return FALSE;
+
+ return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2);
+}
+
+static void
+add_snap (GArray *snaps, Snap snap)
+{
+ if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200)
+ g_array_append_val (snaps, snap);
+}
+
+static void
+add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps)
+{
+ Snap snap;
+
+ snap.snapper = snapper;
+ snap.snappee = snappee;
+
+ if (horizontal_overlap (snapper, snappee))
+ {
+ snap.dx = 0;
+ snap.dy = snappee->y1 - snapper->y1;
+
+ add_snap (snaps, snap);
+ }
+ else if (vertical_overlap (snapper, snappee))
+ {
+ snap.dy = 0;
+ snap.dx = snappee->x1 - snapper->x1;
+
+ add_snap (snaps, snap);
+ }
+
+ /* Corner snaps */
+ /* 1->1 */
+ snap.dx = snappee->x1 - snapper->x1;
+ snap.dy = snappee->y1 - snapper->y1;
+
+ add_snap (snaps, snap);
+
+ /* 1->2 */
+ snap.dx = snappee->x2 - snapper->x1;
+ snap.dy = snappee->y2 - snapper->y1;
+
+ add_snap (snaps, snap);
+
+ /* 2->2 */
+ snap.dx = snappee->x2 - snapper->x2;
+ snap.dy = snappee->y2 - snapper->y2;
+
+ add_snap (snaps, snap);
+
+ /* 2->1 */
+ snap.dx = snappee->x1 - snapper->x2;
+ snap.dy = snappee->y1 - snapper->y2;
+
+ add_snap (snaps, snap);
+}
+
+static void
+list_snaps (XfceOutputInfo *output, GArray *edges, GArray *snaps)
+{
+ guint i;
+
+ for (i = 0; i < edges->len; ++i)
+ {
+ Edge *output_edge = &(g_array_index (edges, Edge, i));
+
+ if (output_edge->output == output)
+ {
+ guint j;
+
+ for (j = 0; j < edges->len; ++j)
+ {
+ Edge *edge = &(g_array_index (edges, Edge, j));
+
+ if (edge->output != output)
+ add_edge_snaps (output_edge, edge, snaps);
+ }
+ }
+ }
+}
+
+static gboolean
+corner_on_edge (int x, int y, Edge *e)
+{
+ if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2)
+ return TRUE;
+
+ if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+edges_align (Edge *e1, Edge *e2)
+{
+ if (corner_on_edge (e1->x1, e1->y1, e2))
+ return TRUE;
+
+ if (corner_on_edge (e2->x1, e2->y1, e1))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+output_is_aligned (XfceOutputInfo *output, GArray *edges)
+{
+ gboolean result = FALSE;
+ guint i;
+
+ for (i = 0; i < edges->len; ++i)
+ {
+ Edge *output_edge = &(g_array_index (edges, Edge, i));
+
+ if (output_edge->output == output)
+ {
+ guint j;
+
+ for (j = 0; j < edges->len; ++j)
+ {
+ Edge *edge = &(g_array_index (edges, Edge, j));
+
+ /* We are aligned if an output edge matches
+ * an edge of another output
+ */
+ if (edge->output != output_edge->output)
+ {
+ if (edges_align (output_edge, edge))
+ {
+ result = TRUE;
+ goto done;
+ }
+ }
+ }
+ }
+ }
+done:
+ return result;
+}
+
+static void
+get_output_rect (XfceOutputInfo *output, GdkRectangle *rect)
+{
+ int w, h;
+
+ get_geometry (output, &w, &h);
+
+ rect->width = w;
+ rect->height = h;
+ rect->x = output->x;
+ rect->y = output->y;
+}
+
+static gboolean
+output_overlaps (XfceOutputInfo *output)
+{
+ GList *connected_outputs = NULL;
+ GList *list;
+ gboolean overlap = FALSE;
+ GdkRectangle output_rect;
+
+ get_output_rect (output, &output_rect);
+
+ connected_outputs = list_connected_outputs (NULL, NULL);
+
+ for (list = connected_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *other = list->data;
+ if (other != output)
+ {
+ GdkRectangle other_rect;
+
+ get_output_rect (other, &other_rect);
+ if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL))
+ {
+ overlap = TRUE;
+ break;
+ }
+ }
+ }
+
+ return overlap;
+}
+
+static gboolean
+xfce_rr_config_is_aligned (GArray *edges)
+{
+ GList *connected_outputs = NULL;
+ GList *list;
+ gboolean aligned = TRUE;
+
+ connected_outputs = list_connected_outputs (NULL, NULL);
+
+ for (list = connected_outputs; list != NULL; list = list->next)
+ {
+ XfceOutputInfo *output = list->data;
+ if (!output_is_aligned (output, edges) || output_overlaps (output))
+ {
+ aligned = FALSE;
+ break;
+ }
+ }
+
+ return aligned;
+}
+
+struct GrabInfo
+{
+ int grab_x;
+ int grab_y;
+ int output_x;
+ int output_y;
+};
+
+static gboolean
+is_corner_snap (const Snap *s)
+{
+ return s->dx != 0 && s->dy != 0;
+}
+
+static int
+compare_snaps (gconstpointer v1, gconstpointer v2)
+{
+ const Snap *s1 = v1;
+ const Snap *s2 = v2;
+ int sv1 = MAX (ABS (s1->dx), ABS (s1->dy));
+ int sv2 = MAX (ABS (s2->dx), ABS (s2->dy));
+ int d;
+
+ d = sv1 - sv2;
+
+ /* This snapping algorithm is good enough for rock'n'roll, but
+ * this is probably a better:
+ *
+ * First do a horizontal/vertical snap, then
+ * with the new coordinates from that snap,
+ * do a corner snap.
+ *
+ * Right now, it's confusing that corner snapping
+ * depends on the distance in an axis that you can't actually see.
+ *
+ */
+ if (d == 0)
+ {
+ if (is_corner_snap (s1) && !is_corner_snap (s2))
+ return -1;
+ else if (is_corner_snap (s2) && !is_corner_snap (s1))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ return d;
+ }
+}
+
+/* Sets a mouse cursor for a widget's window. As a hack, you can pass
+ * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's
+ * window's cursor to its default).
+ */
+static void
+set_cursor (GtkWidget *widget, GdkCursorType type)
+{
+ GdkCursor *cursor;
+ GdkWindow *window;
+
+ if (type == GDK_BLANK_CURSOR)
+ cursor = NULL;
+ else
+ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type);
+
+ window = gtk_widget_get_window (widget);
+
+ if (window)
+ gdk_window_set_cursor (window, cursor);
+
+ if (cursor)
+ gdk_cursor_unref (cursor);
+}
+
+static void
+set_monitors_tooltip (gchar *tooltip_text)
+{
+ const char *text;
+
+ if (tooltip_text)
+ text = g_strdup(tooltip_text);
+
+ else
+ text = _("Select a monitor to change its properties; drag it to rearrange its placement.");
+
+ gtk_widget_set_tooltip_text (randr_gui_area, text);
+}
+
+static void
+on_output_event (FooScrollArea *area,
+ FooScrollAreaEvent *event,
+ gpointer data)
+{
+ XfceOutputInfo *output = data;
+
+ //App *app = g_object_get_data (G_OBJECT (area), "app");
+
+ /* If the mouse is inside the outputs, set the cursor to "you can move me". See
+ * on_canvas_event() for where we reset the cursor to the default if it
+ * exits the outputs' area.
+ */
+ if (!get_mirrored_configuration() && get_n_connected() > 1)
+ set_cursor (GTK_WIDGET (area), GDK_FLEUR);
+
+ if (event->type == FOO_BUTTON_PRESS)
+ {
+ GrabInfo *info;
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX(randr_outputs_combobox), output->id);
+
+ if (!get_mirrored_configuration() && get_n_connected() > 1)
+ {
+ foo_scroll_area_begin_grab (area, on_output_event, data);
+
+ info = g_new0 (GrabInfo, 1);
+ info->grab_x = event->x;
+ info->grab_y = event->y;
+ info->output_x = output->x;
+ info->output_y = output->y;
+
+ set_monitors_tooltip (g_strdup_printf(_("(%i, %i)"), output->x, output->y) );
+
+ output->user_data = info;
+ }
+
+ foo_scroll_area_invalidate (area);
+ }
+ else
+ {
+ if (foo_scroll_area_is_grabbed (area))
+ {
+ GrabInfo *info = output->user_data;
+ double scale = compute_scale();
+ int new_x, new_y;
+ guint i;
+ GArray *edges, *snaps;
+
+ new_x = info->output_x + (event->x - info->grab_x) / scale;
+ new_y = info->output_y + (event->y - info->grab_y) / scale;
+
+ output->x = new_x;
+ output->y = new_y;
+
+ edges = g_array_new (TRUE, TRUE, sizeof (Edge));
+ snaps = g_array_new (TRUE, TRUE, sizeof (Snap));
+
+ list_edges (edges);
+ list_snaps (output, edges, snaps);
+
+ g_array_sort (snaps, compare_snaps);
+
+ output->x = info->output_x;
+ output->y = info->output_y;
+
+ for (i = 0; i < snaps->len; ++i)
+ {
+ Snap *snap = &(g_array_index (snaps, Snap, i));
+ GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge));
+
+ output->x = new_x + snap->dx;
+ output->y = new_y + snap->dy;
+
+ g_array_set_size (new_edges, 0);
+ list_edges (new_edges);
+
+ if (xfce_rr_config_is_aligned (new_edges))
+ {
+ g_array_free (new_edges, TRUE);
+ break;
+ }
+ else
+ {
+ output->x = info->output_x;
+ output->y = info->output_y;
+ g_array_free (new_edges, TRUE);
+ }
+ }
+
+ g_array_free (snaps, TRUE);
+ g_array_free (edges, TRUE);
+
+ if (event->type == FOO_BUTTON_RELEASE)
+ {
+ foo_scroll_area_end_grab (area);
+ set_monitors_tooltip (NULL);
+
+ g_free (output->user_data);
+ output->user_data = NULL;
+
+ initialize_connected_outputs_at_zero();
+ display_settings_changed ();
+ }
+ else
+ {
+ set_monitors_tooltip (g_strdup_printf(_("(%i, %i)"), output->x, output->y) );
+ }
+
+ foo_scroll_area_invalidate (area);
+ }
+ }
+}
+
+static void
+on_canvas_event (FooScrollArea *area,
+ FooScrollAreaEvent *event,
+ gpointer data)
+{
+ /* If the mouse exits the outputs, reset the cursor to the default. See
+ * on_output_event() for where we set the cursor to the movement cursor if
+ * it is over one of the outputs.
+ */
+ set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR);
+}
+
+static PangoLayout *
+get_display_name (XfceOutputInfo *output)
+{
+ const char *text;
+
+ if (get_mirrored_configuration())
+ {
+ /* Translators: this is the feature where what you see on your laptop's
+ * screen is the same as your external monitor. Here, "Mirror" is being
+ * used as an adjective, not as a verb. For example, the Spanish
+ * translation could be "Pantallas en Espejo", *not* "Espejar Pantallas".
+ */
+ text = _("Mirror Screens");
+ }
+ else
+ {
+ text = output->display_name;
+ }
+
+ return gtk_widget_create_pango_layout (
+ GTK_WIDGET (randr_gui_area), text);
+}
+
+static void
+paint_background (FooScrollArea *area,
+ cairo_t *cr)
+{
+ GdkRectangle viewport;
+ GtkWidget *widget;
+ GtkStyle *widget_style;
+
+ widget = GTK_WIDGET (area);
+
+ foo_scroll_area_get_viewport (area, &viewport);
+ widget_style = gtk_widget_get_style (widget);
+
+ cairo_set_source_rgb (cr,
+ widget_style->base[GTK_STATE_NORMAL].red / 65535.0,
+ widget_style->base[GTK_STATE_NORMAL].green / 65535.0,
+ widget_style->base[GTK_STATE_NORMAL].blue / 65535.0);
+
+ cairo_rectangle (cr,
+ viewport.x, viewport.y,
+ viewport.width, viewport.height);
+
+ cairo_fill_preserve (cr);
+
+ foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL);
+
+ cairo_set_source_rgb (cr,
+ widget_style->dark[GTK_STATE_NORMAL].red / 65535.0,
+ widget_style->dark[GTK_STATE_NORMAL].green / 65535.0,
+ widget_style->dark[GTK_STATE_NORMAL].blue / 65535.0);
+
+ cairo_stroke (cr);
+}
+
+static void
+paint_output (cairo_t *cr, int i, double *snap_x, double *snap_y)
+{
+ int w, h;
+ double scale = compute_scale();
+ double x, y, end_x, end_y;
+ gint total_w, total_h;
+ GList *connected_outputs = list_connected_outputs (&total_w, &total_h);
+ XfceOutputInfo *output = g_list_nth (connected_outputs, i)->data;
+ PangoLayout *layout = get_display_name (output);
+ PangoRectangle ink_extent, log_extent;
+ GdkRectangle viewport;
+ cairo_pattern_t *pat_lin = NULL, *pat_radial = NULL;
+ double alpha = 1.0;
+ double available_w;
+ double factor = 1.0;
+
+ cairo_save (cr);
+
+ foo_scroll_area_get_viewport (FOO_SCROLL_AREA (randr_gui_area), &viewport);
+
+ get_geometry (output, &w, &h);
+
+ viewport.height -= 2 * MARGIN;
+ viewport.width -= 2 * MARGIN;
+
+ /* Center the displayed outputs in the viewport */
+ x = ceil (output->x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0);
+ y = ceil (output->y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0);
+
+ /* Align endpoints */
+ end_x = x + ceil (w * scale);
+ end_y = y + ceil (h * scale);
+ if ( abs((int)end_x-(int)*snap_x) <= 1 )
+ {
+ end_x = *snap_x;
+ }
+ if ( abs((int)end_y-(int)*snap_y) <= 1 )
+ {
+ end_y = *snap_y;
+ }
+ *snap_x = end_x;
+ *snap_y = end_y;
+
+ cairo_translate (cr,
+ x + (w * scale) / 2,
+ y + (h * scale) / 2);
+
+ /* rotation is already applied in get_geometry */
+
+ if (output->rotation == RR_Reflect_X)
+ cairo_scale (cr, -1, 1);
+
+ if (output->rotation == RR_Reflect_Y)
+ cairo_scale (cr, 1, -1);
+
+ cairo_translate (cr,
+ - x - (w * scale) / 2,
+ - y - (h * scale) / 2);
+
+ cairo_rectangle (cr, x, y, end_x - x, end_y - y);
+ cairo_clip_preserve (cr);
+
+ foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (randr_gui_area),
+ cr, on_output_event, output);
+
+ cairo_set_line_width (cr, 1.0);
+
+ if (output->id != active_output)
+ alpha = 0.8;
+
+ if (output->on)
+ {
+ /* Background gradient for active display */
+ pat_lin = cairo_pattern_create_linear(x, y, x, y + (h * scale));
+ cairo_pattern_add_color_stop_rgba(pat_lin, 0.0, 0.56, 0.85, 0.92, alpha);
+ cairo_pattern_add_color_stop_rgba(pat_lin, 0.2, 0.33, 0.75, 0.92, alpha);
+ cairo_pattern_add_color_stop_rgba(pat_lin, 0.7, 0.25, 0.57, 0.77, alpha);
+ cairo_pattern_add_color_stop_rgba(pat_lin, 1.0, 0.17, 0.39, 0.63, alpha);
+ cairo_set_source (cr, pat_lin);
+ cairo_fill_preserve (cr);
+
+ cairo_set_source_rgba (cr, 0.11, 0.26, 0.52, alpha);
+ cairo_stroke (cr);
+ }
+ else
+ {
+ /* Background gradient for disabled display */
+ pat_lin = cairo_pattern_create_linear(x, y, x, y + (h * scale));
+ cairo_pattern_add_color_stop_rgba(pat_lin, 0.0, 0.24, 0.3, 0.31, alpha);
+ cairo_pattern_add_color_stop_rgba(pat_lin, 0.2, 0.17, 0.20, 0.22, alpha);
+ cairo_pattern_add_color_stop_rgba(pat_lin, 0.7, 0.14, 0.16, 0.18, alpha);
+ cairo_pattern_add_color_stop_rgba(pat_lin, 1.0, 0.07, 0.07, 0.07, alpha);
+ cairo_set_source (cr, pat_lin);
+ cairo_fill_preserve (cr);
+
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, alpha);
+ cairo_stroke (cr);
+ }
+
+ /* Draw inner stroke */
+ cairo_rectangle (cr, x + 1.5, y + 1.5, end_x - x - 3, end_y - y - 3);
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha - 0.75);
+ cairo_stroke (cr);
+
+ /* Draw reflection as radial gradient on a polygon */
+ pat_radial = cairo_pattern_create_radial ((end_x -x) /2 + x, y, 1, (end_x -x) /2 + x, y, h * scale);
+ cairo_pattern_add_color_stop_rgba(pat_radial, 0.0, 1.0, 1.0, 1.0, 0.4);
+ cairo_pattern_add_color_stop_rgba(pat_radial, 0.5, 1.0, 1.0, 1.0, 0.15);
+ cairo_pattern_add_color_stop_rgba(pat_radial, 0.8, 1.0, 1.0, 1.0, 0.0);
+
+ cairo_move_to (cr, x + 1.5, y + 1.5);
+ cairo_line_to (cr, end_x - 1.5, y + 1.5);
+ cairo_line_to (cr, end_x - 1.5, y + (end_y - y) / 3);
+ cairo_line_to (cr, x + 1.5, y + (end_y - y) / 1.5);
+ cairo_close_path (cr);
+ cairo_set_source (cr, pat_radial);
+ cairo_fill (cr);
+
+ /* Display name label*/
+ layout_set_font (layout, "Sans Bold 12");
+ pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent);
+
+ available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */
+
+ cairo_scale (cr, factor, factor);
+
+ if (available_w < ink_extent.width)
+ {
+ pango_layout_set_width (layout, available_w * PANGO_SCALE);
+ pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
+ log_extent.width = available_w;
+ }
+
+ cairo_move_to (cr,
+ x + ((w * scale + 0.5) - factor * log_extent.width) / 2,
+ y + ((h * scale + 0.5) - factor * log_extent.height) / 2 - 1);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, alpha - 0.6);
+
+ pango_cairo_show_layout (cr, layout);
+
+ cairo_move_to (cr,
+ x + ((w * scale + 0.5) - factor * log_extent.width) / 2,
+ y + ((h * scale + 0.5) - factor * log_extent.height) / 2);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha);
+
+ pango_cairo_show_layout (cr, layout);
+
+ /* Display state label */
+ if (!output->on)
+ {
+ PangoLayout *display_state;
+ display_state = gtk_widget_create_pango_layout ( GTK_WIDGET (randr_gui_area), _("(Disabled)"));
+ layout_set_font (display_state, "Sans 9");
+ pango_layout_get_pixel_extents (display_state, &ink_extent, &log_extent);
+
+ available_w = w * scale + 0.5 - 6;
+ if (available_w < ink_extent.width)
+ factor = available_w / ink_extent.width;
+ else
+ factor = 1.0;
+ cairo_move_to (cr,
+ x + ((w * scale + 0.5) - factor * log_extent.width) / 2,
+ y + ((h * scale + 0.5) - factor * log_extent.height) / 2 + 18);
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.75);
+ pango_cairo_show_layout (cr, display_state);
+ g_object_unref (display_state);
+ }
+
+ cairo_restore (cr);
+
+ if (pat_lin)
+ cairo_pattern_destroy(pat_lin);
+ if (pat_radial)
+ cairo_pattern_destroy(pat_radial);
+
+ g_object_unref (layout);
+}
+
+static void
+on_area_paint (FooScrollArea *area,
+ cairo_t *cr,
+ GdkRectangle *extent,
+ GdkRegion *region,
+ gpointer data)
+{
+ GList *connected_outputs = NULL;
+ GList *list;
+ double x, y;
+
+ paint_background (area, cr);
+
+ connected_outputs = list_connected_outputs (NULL, NULL);
+
+ for (list = connected_outputs; list != NULL; list = list->next)
+ {
+ paint_output (cr, g_list_position (connected_outputs, list), &x, &y);
+
+ if (get_mirrored_configuration())
+ break;
+ }
+}
+
+static XfceOutputInfo *
+get_nearest_output (gint x, gint y)
+{
+ int nearest_index;
+ guint nearest_dist;
+ guint m;
+
+ nearest_index = -1;
+ nearest_dist = G_MAXINT;
+
+ /* Walk all the connected outputs */
+ for (m = 0; m < xfce_randr->noutput; ++m)
+ {
+ XfceOutputInfo *output;
+ guint dist_x, dist_y;
+
+ output = convert_xfce_output_info(m);
+
+ if (!(output->connected && output->on))
+ continue;
+
+ if (x < output->x)
+ dist_x = output->x - x;
+ else if (x >= output->x + (gint)output->width)
+ dist_x = x - (output->x + output->width) + 1;
+ else
+ dist_x = 0;
+
+ if (y < output->y)
+ dist_y = output->y - y;
+ else if (y >= output->y + (gint)output->height)
+ dist_y = y - (output->y + output->height) + 1;
+ else
+ dist_y = 0;
+
+ if (MIN (dist_x, dist_y) < nearest_dist)
+ {
+ nearest_dist = MIN (dist_x, dist_y);
+ nearest_index = m;
+ }
+ }
+
+ if (nearest_index != -1)
+ return convert_xfce_output_info(nearest_index);
+ else
+ return NULL;
+}
+
+/* Gets the output that contains the largest intersection with the window.
+ * Logic stolen from gdk_screen_get_monitor_at_window().
+ */
+static XfceOutputInfo *
+get_output_for_window (GdkWindow *window)
+{
+ GdkRectangle win_rect;
+ int largest_area;
+ int largest_index;
+ guint m;
+
+ gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height, NULL);
+ gdk_window_get_origin (window, &win_rect.x, &win_rect.y);
+
+ largest_area = 0;
+ largest_index = -1;
+
+ /* Walk all the connected outputs */
+ for (m = 0; m < xfce_randr->noutput; ++m)
+ {
+ XfceOutputInfo *output;
+ GdkRectangle output_rect, intersection;
+
+ output = convert_xfce_output_info(m);
+
+ output_rect.x = output->x;
+ output_rect.y = output->y;
+ output_rect.width = output->width;
+ output_rect.height = output->height;
+
+ if (xfce_randr->mode[m] != None)
+ {
+ if (gdk_rectangle_intersect (&win_rect, &output_rect, &intersection))
+ {
+ int area;
+
+ area = intersection.width * intersection.height;
+ if (area > largest_area)
+ {
+ largest_area = area;
+ largest_index = m;
+ }
+ }
+ }
+ }
+
+ if (largest_index != -1)
+ return convert_xfce_output_info(largest_index);
+ else
+ return get_nearest_output ( win_rect.x + win_rect.width / 2,
+ win_rect.y + win_rect.height / 2);
+}
+
+/* We select the current output, i.e. select the one being edited, based on
+ * which output is showing the configuration dialog.
+ */
+static void
+select_current_output_from_dialog_position (App *app)
+{
+ if (gtk_widget_get_realized (app->dialog))
+ app->current_output = get_output_for_window (gtk_widget_get_window (app->dialog));
+ else
+ app->current_output = NULL;
+}
+
+/* This is a GtkWidget::map-event handler. We wait for the display-properties
+ * dialog to be mapped, and then we select the output which corresponds to the
+ * monitor on which the dialog is being shown.
+ */
+static gboolean
+dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
+{
+ App *app = data;
+
+ select_current_output_from_dialog_position (app);
+ return FALSE;
+}
+
+static GtkWidget*
+_gtk_builder_get_widget (GtkBuilder *builder, const gchar *name)
+{
+ return GTK_WIDGET (gtk_builder_get_object (builder, name));
+}
+/* Xfce RANDR GUI */
+
+static void
+display_settings_show_main_dialog (GdkDisplay *display)
+{
+ GtkBuilder *builder;
+ GtkWidget *dialog, *plug;
+ GObject *plug_child;
GError *error = NULL;
+ GtkWidget *gui_container;
+ App *app;
/* Load the Gtk user-interface file */
builder = gtk_builder_new ();
@@ -1769,11 +2687,39 @@ display_settings_show_main_dialog (GdkDisplay *display)
randr_event_base,
RRNotify + 1);
gdk_window_add_filter (gdk_get_default_root_window (), screen_on_event, builder);
-
+
/* Show/Hide the helper popups when the dialog is shown/hidden */
g_signal_connect(G_OBJECT(dialog), "focus-out-event", G_CALLBACK (focus_out_event), builder);
g_signal_connect(G_OBJECT(dialog), "focus-in-event", G_CALLBACK (focus_in_event), builder);
+ app = g_new0 (App, 1);
+
+ initialize_connected_outputs();
+
+ app->dialog = _gtk_builder_get_widget (builder, "display-dialog");
+ g_signal_connect_after (app->dialog, "map-event",
+ G_CALLBACK (dialog_map_event_cb), app);
+
+ /* Scroll Area */
+ randr_gui_area = (GtkWidget *)foo_scroll_area_new ();
+ randr_outputs_combobox = _gtk_builder_get_widget (builder, "randr-outputs");
+
+ g_object_set_data (G_OBJECT (randr_gui_area), "app", app);
+
+ set_monitors_tooltip (NULL);
+
+ /* FIXME: this should be computed dynamically */
+ foo_scroll_area_set_min_size (FOO_SCROLL_AREA (randr_gui_area), -1, 200);
+ gtk_widget_show (randr_gui_area);
+ g_signal_connect (randr_gui_area, "paint",
+ G_CALLBACK (on_area_paint), app);
+ g_signal_connect (randr_gui_area, "viewport_changed",
+ G_CALLBACK (on_viewport_changed), app);
+
+ gui_container = GTK_WIDGET(gtk_builder_get_object(builder, "randr-dnd"));
+ gtk_container_add(GTK_CONTAINER(gui_container), GTK_WIDGET(randr_gui_area));
+ gtk_widget_show_all(gui_container);
+
if (G_UNLIKELY (opt_socket_id == 0))
{
g_signal_connect (G_OBJECT (dialog), "response",
@@ -1869,6 +2815,7 @@ display_settings_show_minimal_dialog (GdkDisplay *display)
GObject *only_display1, *only_display2, *mirror_displays;
GObject *extend_right, *advanced, *fake_button, *label;
GError *error = NULL;
+ gboolean found = FALSE;
RRMode mode;
builder = gtk_builder_new ();
@@ -1910,30 +2857,39 @@ display_settings_show_minimal_dialog (GdkDisplay *display)
label = gtk_builder_get_object (builder, "label4");
gtk_label_set_text (GTK_LABEL (label), xfce_randr->friendly_name[1]);
gtk_widget_set_tooltip_text(GTK_WIDGET(label), xfce_randr->friendly_name[1]);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (only_display2),
- xfce_randr->mode[1] != None);
-
+
/* Can outputs be cloned? */
if (display_settings_get_n_active_outputs () > 1)
mode = xfce_randr_clonable_mode (xfce_randr);
-
gtk_widget_set_sensitive (GTK_WIDGET (mirror_displays), mode != None);
- if (xfce_randr->mode[0] != None && xfce_randr->mode[1] != None)
+ if (xfce_randr->mode[0] != None)
+ {
+ if (xfce_randr->mode[1] != None)
+ {
+ /* Check for mirror */
+ if (xfce_randr->mirrored[0] && xfce_randr->mirrored[1])
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mirror_displays), TRUE);
+ found = TRUE;
+ }
+ /* Check for Extend Right */
+ if (!found && (gint)xfce_randr->position[1].x == (gint)xfce_randr->position[0].x + (gint)xfce_randr_find_mode_by_id (xfce_randr, 0, xfce_randr->mode[0])->width)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extend_right), TRUE);
+ found = TRUE;
+ }
+ }
+ /* Toggle Primary */
+ if (!found)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (only_display1), TRUE);
+ }
+ }
+ /* Toggle Secondary */
+ else
{
- /* Check for mirror */
- if ((xfce_randr->relation[1] == XFCE_RANDR_PLACEMENT_MIRROR &&
- xfce_randr->related_to[1] == 0) || (xfce_randr->related_to[0] == 1 &&
- xfce_randr->relation[0] == XFCE_RANDR_PLACEMENT_MIRROR))
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mirror_displays),
- TRUE);
-
- /* Check for Extend Right */
- if ((xfce_randr->relation[1] == XFCE_RANDR_PLACEMENT_RIGHT &&
- xfce_randr->related_to[1] == 0) || (xfce_randr->related_to[0] == 1 &&
- xfce_randr->relation[1] == XFCE_RANDR_PLACEMENT_LEFT))
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extend_right),
- TRUE);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (only_display2), TRUE);
}
}
else
diff --git a/dialogs/display-settings/scrollarea.c b/dialogs/display-settings/scrollarea.c
new file mode 100644
index 0000000..4e61aa5
--- /dev/null
+++ b/dialogs/display-settings/scrollarea.c
@@ -0,0 +1,1433 @@
+/* Copyright 2006, 2007, 2008, Soren Sandmann <sandmann at daimi.au.dk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gdk/gdkprivate.h> /* For GDK_PARENT_RELATIVE_BG */
+#include "scrollarea.h"
+#include "foo-marshal.h"
+
+G_DEFINE_TYPE (FooScrollArea, foo_scroll_area, GTK_TYPE_CONTAINER);
+
+static GtkWidgetClass *parent_class;
+
+typedef struct BackingStore BackingStore;
+
+typedef void (* ExposeFunc) (cairo_t *cr, GdkRegion *region, gpointer data);
+
+typedef struct InputPath InputPath;
+typedef struct InputRegion InputRegion;
+typedef struct AutoScrollInfo AutoScrollInfo;
+
+struct InputPath
+{
+ gboolean is_stroke;
+ cairo_fill_rule_t fill_rule;
+ double line_width;
+ cairo_path_t *path; /* In canvas coordinates */
+
+ FooScrollAreaEventFunc func;
+ gpointer data;
+
+ InputPath *next;
+};
+
+/* InputRegions are mutually disjoint */
+struct InputRegion
+{
+ GdkRegion *region; /* the boundary of this area in canvas coordinates */
+ InputPath *paths;
+};
+
+struct AutoScrollInfo
+{
+ int dx;
+ int dy;
+ int timeout_id;
+ int begin_x;
+ int begin_y;
+ double res_x;
+ double res_y;
+ GTimer *timer;
+};
+
+struct FooScrollAreaPrivate
+{
+ GdkWindow *input_window;
+
+ int width;
+ int height;
+
+ GtkAdjustment *hadj;
+ GtkAdjustment *vadj;
+ int x_offset;
+ int y_offset;
+
+ int min_width;
+ int min_height;
+
+ GPtrArray *input_regions;
+
+ AutoScrollInfo *auto_scroll_info;
+
+ /* During expose, this region is set to the region
+ * being exposed. At other times, it is NULL
+ *
+ * It is used for clipping of input areas
+ */
+ GdkRegion *expose_region;
+ InputRegion *current_input;
+
+ gboolean grabbed;
+ FooScrollAreaEventFunc grab_func;
+ gpointer grab_data;
+
+ GdkPixmap *pixmap;
+ GdkRegion *update_region; /* In canvas coordinates */
+};
+
+enum
+{
+ VIEWPORT_CHANGED,
+ PAINT,
+ INPUT,
+ LAST_SIGNAL,
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+static void foo_scroll_area_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+
+static gboolean foo_scroll_area_expose (GtkWidget *widget,
+ GdkEventExpose *expose);
+
+static void foo_scroll_area_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+static void foo_scroll_area_set_scroll_adjustments (FooScrollArea *scroll_area,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+
+static void foo_scroll_area_realize (GtkWidget *widget);
+static void foo_scroll_area_unrealize (GtkWidget *widget);
+static void foo_scroll_area_map (GtkWidget *widget);
+static void foo_scroll_area_unmap (GtkWidget *widget);
+static gboolean foo_scroll_area_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean foo_scroll_area_button_release (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean foo_scroll_area_motion (GtkWidget *widget,
+ GdkEventMotion *event);
+
+static void
+foo_scroll_area_map (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ if (area->priv->input_window)
+ gdk_window_show (area->priv->input_window);
+}
+
+static void
+foo_scroll_area_unmap (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ if (area->priv->input_window)
+ gdk_window_hide (area->priv->input_window);
+
+ GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+static void
+foo_scroll_area_finalize (GObject *object)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (object);
+
+ g_object_unref (scroll_area->priv->hadj);
+ g_object_unref (scroll_area->priv->vadj);
+
+ g_ptr_array_free (scroll_area->priv->input_regions, TRUE);
+
+ g_free (scroll_area->priv);
+
+ G_OBJECT_CLASS (foo_scroll_area_parent_class)->finalize (object);
+}
+
+static void
+foo_scroll_area_class_init (FooScrollAreaClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+ object_class->finalize = foo_scroll_area_finalize;
+
+ widget_class->size_request = foo_scroll_area_size_request;
+ widget_class->expose_event = foo_scroll_area_expose;
+
+ widget_class->size_allocate = foo_scroll_area_size_allocate;
+ widget_class->realize = foo_scroll_area_realize;
+ widget_class->unrealize = foo_scroll_area_unrealize;
+ widget_class->button_press_event = foo_scroll_area_button_press;
+ widget_class->button_release_event = foo_scroll_area_button_release;
+ widget_class->motion_notify_event = foo_scroll_area_motion;
+ widget_class->map = foo_scroll_area_map;
+ widget_class->unmap = foo_scroll_area_unmap;
+
+ class->set_scroll_adjustments = foo_scroll_area_set_scroll_adjustments;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ signals[VIEWPORT_CHANGED] =
+ g_signal_new ("viewport_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (FooScrollAreaClass,
+ viewport_changed),
+ NULL, NULL,
+ foo_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE, 2,
+ GDK_TYPE_RECTANGLE,
+ GDK_TYPE_RECTANGLE);
+
+ signals[PAINT] =
+ g_signal_new ("paint",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (FooScrollAreaClass,
+ paint),
+ NULL, NULL,
+ foo_marshal_VOID__POINTER_BOXED_POINTER,
+ G_TYPE_NONE, 3,
+ G_TYPE_POINTER,
+ GDK_TYPE_RECTANGLE,
+ G_TYPE_POINTER);
+
+ widget_class->set_scroll_adjustments_signal =
+ g_signal_new ("set_scroll_adjustments",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (FooScrollAreaClass,
+ set_scroll_adjustments),
+ NULL, NULL,
+ foo_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_ADJUSTMENT,
+ GTK_TYPE_ADJUSTMENT);
+}
+
+static GtkAdjustment *
+new_adjustment (void)
+{
+ return GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+}
+
+static void
+foo_scroll_area_init (FooScrollArea *scroll_area)
+{
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (scroll_area);
+
+ gtk_widget_set_has_window (widget, FALSE);
+ gtk_widget_set_redraw_on_allocate (widget, FALSE);
+
+ scroll_area->priv = g_new0 (FooScrollAreaPrivate, 1);
+ scroll_area->priv->width = 0;
+ scroll_area->priv->height = 0;
+ scroll_area->priv->hadj = g_object_ref_sink (new_adjustment());
+ scroll_area->priv->vadj = g_object_ref_sink (new_adjustment());
+ scroll_area->priv->x_offset = 0.0;
+ scroll_area->priv->y_offset = 0.0;
+ scroll_area->priv->min_width = -1;
+ scroll_area->priv->min_height = -1;
+ scroll_area->priv->auto_scroll_info = NULL;
+ scroll_area->priv->input_regions = g_ptr_array_new ();
+ scroll_area->priv->pixmap = NULL;
+ scroll_area->priv->update_region = gdk_region_new ();
+
+ gtk_widget_set_double_buffered (widget, FALSE);
+}
+
+static void
+translate_cairo_device (cairo_t *cr,
+ int x_offset,
+ int y_offset)
+{
+ cairo_surface_t *surface = cairo_get_target (cr);
+ double dev_x;
+ double dev_y;
+
+ cairo_surface_get_device_offset (surface, &dev_x, &dev_y);
+ dev_x += x_offset;
+ dev_y += y_offset;
+ cairo_surface_set_device_offset (surface, dev_x, dev_y);
+}
+
+typedef void (* PathForeachFunc) (double *x,
+ double *y,
+ gpointer data);
+
+static void
+path_foreach_point (cairo_path_t *path,
+ PathForeachFunc func,
+ gpointer user_data)
+{
+ int i;
+
+ for (i = 0; i < path->num_data; i += path->data[i].header.length)
+ {
+ cairo_path_data_t *data = &(path->data[i]);
+
+ switch (data->header.type)
+ {
+ case CAIRO_PATH_MOVE_TO:
+ case CAIRO_PATH_LINE_TO:
+ func (&(data[1].point.x), &(data[1].point.y), user_data);
+ break;
+
+ case CAIRO_PATH_CURVE_TO:
+ func (&(data[1].point.x), &(data[1].point.y), user_data);
+ func (&(data[2].point.x), &(data[2].point.y), user_data);
+ func (&(data[3].point.x), &(data[3].point.y), user_data);
+ break;
+
+ case CAIRO_PATH_CLOSE_PATH:
+ break;
+ }
+ }
+}
+
+typedef struct
+{
+ double x1, y1, x2, y2;
+} Box;
+
+static void
+input_path_free_list (InputPath *paths)
+{
+ if (!paths)
+ return;
+
+ input_path_free_list (paths->next);
+ cairo_path_destroy (paths->path);
+ g_free (paths);
+}
+
+static void
+input_region_free (InputRegion *region)
+{
+ input_path_free_list (region->paths);
+ gdk_region_destroy (region->region);
+
+ g_free (region);
+}
+
+static void
+get_viewport (FooScrollArea *scroll_area,
+ GdkRectangle *viewport)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ viewport->x = scroll_area->priv->x_offset;
+ viewport->y = scroll_area->priv->y_offset;
+ viewport->width = allocation.width;
+ viewport->height = allocation.height;
+}
+
+static void
+allocation_to_canvas (FooScrollArea *area,
+ int *x,
+ int *y)
+{
+ *x += area->priv->x_offset;
+ *y += area->priv->y_offset;
+}
+
+static void
+clear_exposed_input_region (FooScrollArea *area,
+ GdkRegion *exposed) /* in canvas coordinates */
+{
+ guint i;
+ GdkRegion *viewport;
+ GdkRectangle allocation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation_to_canvas (area, &allocation.x, &allocation.y);
+ viewport = gdk_region_rectangle (&allocation);
+ gdk_region_subtract (viewport, exposed);
+
+ for (i = 0; i < area->priv->input_regions->len; ++i)
+ {
+ InputRegion *region = area->priv->input_regions->pdata[i];
+
+ gdk_region_intersect (region->region, viewport);
+
+ if (gdk_region_empty (region->region))
+ {
+ input_region_free (region);
+ g_ptr_array_remove_index_fast (area->priv->input_regions, i--);
+ }
+ }
+
+ gdk_region_destroy (viewport);
+}
+
+static void
+setup_background_cr (GdkWindow *window,
+ cairo_t *cr,
+ int x_offset,
+ int y_offset)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+
+ if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
+ {
+ x_offset += private->x;
+ y_offset += private->y;
+
+ setup_background_cr (GDK_WINDOW (private->parent), cr, x_offset, y_offset);
+ }
+ else if (private->bg_pixmap &&
+ private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+ private->bg_pixmap != GDK_NO_BG)
+ {
+ gdk_cairo_set_source_pixmap (cr, private->bg_pixmap, -x_offset, -y_offset);
+ }
+ else
+ {
+ gdk_cairo_set_source_color (cr, &private->bg_color);
+ }
+}
+
+static void
+initialize_background (GtkWidget *widget,
+ cairo_t *cr)
+{
+ setup_background_cr (gtk_widget_get_window (widget), cr, 0, 0);
+
+ cairo_paint (cr);
+}
+
+static void
+clip_to_region (cairo_t *cr, GdkRegion *region)
+{
+ int n_rects;
+ GdkRectangle *rects;
+
+ gdk_region_get_rectangles (region, &rects, &n_rects);
+
+ cairo_new_path (cr);
+ while (n_rects--)
+ {
+ GdkRectangle *rect = &(rects[n_rects]);
+
+ cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+ }
+ cairo_clip (cr);
+
+ g_free (rects);
+}
+
+static void
+simple_draw_drawable (GdkDrawable *dst,
+ GdkDrawable *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ int width,
+ int height)
+{
+ GdkGC *gc = gdk_gc_new (dst);
+
+ gdk_draw_drawable (dst, gc, src, src_x, src_y, dst_x, dst_y, width, height);
+
+ g_object_unref (gc);
+}
+
+static gboolean
+foo_scroll_area_expose (GtkWidget *widget,
+ GdkEventExpose *expose)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget);
+ cairo_t *cr;
+ GdkGC *gc;
+ GdkRectangle extents;
+ GdkWindow *window = gtk_widget_get_window (widget);
+ GdkRegion *region;
+ int x_offset, y_offset;
+ GtkAllocation widget_allocation;
+
+ /* I don't think expose can ever recurse for the same area */
+ g_assert (!scroll_area->priv->expose_region);
+
+ /* Note that this function can be called at a time
+ * where the adj->value is different from x_offset.
+ * Ie., the GtkScrolledWindow changed the adj->value
+ * without emitting the value_changed signal.
+ *
+ * Hence we must always use the value we got
+ * the last time the signal was emitted, ie.,
+ * priv->{x,y}_offset.
+ */
+
+ x_offset = scroll_area->priv->x_offset;
+ y_offset = scroll_area->priv->y_offset;
+
+ scroll_area->priv->expose_region = expose->region;
+
+ /* Setup input areas */
+ clear_exposed_input_region (scroll_area, scroll_area->priv->update_region);
+
+ scroll_area->priv->current_input = g_new0 (InputRegion, 1);
+ scroll_area->priv->current_input->region = gdk_region_copy (scroll_area->priv->update_region);
+ scroll_area->priv->current_input->paths = NULL;
+ g_ptr_array_add (scroll_area->priv->input_regions,
+ scroll_area->priv->current_input);
+
+ region = scroll_area->priv->update_region;
+ scroll_area->priv->update_region = gdk_region_new ();
+
+ /* Create cairo context */
+ cr = gdk_cairo_create (scroll_area->priv->pixmap);
+ translate_cairo_device (cr, -x_offset, -y_offset);
+ clip_to_region (cr, region);
+ initialize_background (widget, cr);
+
+ /* Create regions */
+ gdk_region_get_clipbox (region, &extents);
+
+ g_signal_emit (widget, signals[PAINT], 0, cr, &extents, region);
+
+ /* Destroy stuff */
+ cairo_destroy (cr);
+
+ scroll_area->priv->expose_region = NULL;
+ scroll_area->priv->current_input = NULL;
+
+ /* Finally draw the backing pixmap */
+ gc = gdk_gc_new (window);
+
+ gdk_gc_set_clip_region (gc, expose->region);
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ gdk_draw_drawable (window, gc, scroll_area->priv->pixmap,
+ 0, 0, widget_allocation.x, widget_allocation.y,
+ widget_allocation.width, widget_allocation.height);
+
+ g_object_unref (gc);
+ gdk_region_destroy (region);
+
+ return TRUE;
+}
+
+void
+foo_scroll_area_get_viewport (FooScrollArea *scroll_area,
+ GdkRectangle *viewport)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ if (!viewport)
+ return;
+
+ get_viewport (scroll_area, viewport);
+}
+
+static void
+process_event (FooScrollArea *scroll_area,
+ FooScrollAreaEventType input_type,
+ int x,
+ int y);
+
+static void
+emit_viewport_changed (FooScrollArea *scroll_area,
+ GdkRectangle *new_viewport,
+ GdkRectangle *old_viewport)
+{
+ int px, py;
+ g_signal_emit (scroll_area, signals[VIEWPORT_CHANGED], 0,
+ new_viewport, old_viewport);
+
+ gdk_window_get_pointer (scroll_area->priv->input_window, &px, &py, NULL);
+
+ process_event (scroll_area, FOO_MOTION, px, py);
+}
+
+static void
+clamp_adjustment (GtkAdjustment *adj)
+{
+ if (gtk_adjustment_get_upper (adj) >= gtk_adjustment_get_page_size (adj))
+ gtk_adjustment_set_value (adj, CLAMP (gtk_adjustment_get_value (adj), 0.0,
+ gtk_adjustment_get_upper (adj)
+ - gtk_adjustment_get_page_size (adj)));
+ else
+ gtk_adjustment_set_value (adj, 0.0);
+
+ gtk_adjustment_changed (adj);
+}
+
+static gboolean
+set_adjustment_values (FooScrollArea *scroll_area)
+{
+ GtkAllocation allocation;
+
+ GtkAdjustment *hadj = scroll_area->priv->hadj;
+ GtkAdjustment *vadj = scroll_area->priv->vadj;
+
+ /* Horizontal */
+ gtk_widget_get_allocation (GTK_WIDGET (scroll_area), &allocation);
+ g_object_freeze_notify (G_OBJECT (hadj));
+ gtk_adjustment_set_page_size (hadj, allocation.width);
+ gtk_adjustment_set_step_increment (hadj, 0.1 * allocation.width);
+ gtk_adjustment_set_page_increment (hadj, 0.9 * allocation.width);
+ gtk_adjustment_set_lower (hadj, 0.0);
+ gtk_adjustment_set_upper (hadj, scroll_area->priv->width);
+ g_object_thaw_notify (G_OBJECT (hadj));
+
+ /* Vertical */
+ g_object_freeze_notify (G_OBJECT (vadj));
+ gtk_adjustment_set_page_size (vadj, allocation.height);
+ gtk_adjustment_set_step_increment (vadj, 0.1 * allocation.height);
+ gtk_adjustment_set_page_increment (vadj, 0.9 * allocation.height);
+ gtk_adjustment_set_lower (vadj, 0.0);
+ gtk_adjustment_set_upper (vadj, scroll_area->priv->height);
+ g_object_thaw_notify (G_OBJECT (vadj));
+
+ clamp_adjustment (hadj);
+ clamp_adjustment (vadj);
+
+ return TRUE;
+}
+
+static void
+foo_scroll_area_realize (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+ GdkWindowAttr attributes;
+ GtkAllocation widget_allocation;
+ GdkWindow *window;
+ gint attributes_mask;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ gtk_widget_set_realized (widget, TRUE);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget_allocation.x;
+ attributes.y = widget_allocation.y;
+ attributes.width = widget_allocation.width;
+ attributes.height = widget_allocation.height;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+ window = gtk_widget_get_parent_window (widget);
+ gtk_widget_set_window (widget, window);
+ g_object_ref (window);
+
+ area->priv->input_window = gdk_window_new (window,
+ &attributes, attributes_mask);
+
+ area->priv->pixmap = gdk_pixmap_new (window,
+ widget_allocation.width,
+ widget_allocation.height,
+ -1);
+
+ gdk_window_set_user_data (area->priv->input_window, area);
+
+ gtk_widget_style_attach (widget);
+}
+
+static void
+foo_scroll_area_unrealize (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ if (area->priv->input_window)
+ {
+ gdk_window_set_user_data (area->priv->input_window, NULL);
+ gdk_window_destroy (area->priv->input_window);
+ area->priv->input_window = NULL;
+ }
+
+ GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
+}
+
+static GdkPixmap *
+create_new_pixmap (GtkWidget *widget,
+ GdkPixmap *old)
+{
+ GtkAllocation widget_allocation;
+ GdkPixmap *new;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+
+ new = gdk_pixmap_new (gtk_widget_get_window (widget),
+ widget_allocation.width,
+ widget_allocation.height,
+ -1);
+
+ /* Unfortunately we don't know in which direction we were resized,
+ * so we just assume we were dragged from the south-east corner.
+ *
+ * Although, maybe we could get the root coordinates of the input-window?
+ * That might just work, actually. We need to make sure marco uses
+ * static gravity for the window before this will be useful.
+ */
+ simple_draw_drawable (new, old, 0, 0, 0, 0, -1, -1);
+
+ return new;
+}
+
+static void
+allocation_to_canvas_region (FooScrollArea *area,
+ GdkRegion *region)
+{
+ gdk_region_offset (region, area->priv->x_offset, area->priv->y_offset);
+}
+
+static void
+foo_scroll_area_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget);
+ GdkRectangle new_viewport;
+ GdkRectangle old_viewport;
+ GdkRegion *old_allocation;
+ GdkRegion *invalid;
+ GtkAllocation widget_allocation;
+
+ get_viewport (scroll_area, &old_viewport);
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ old_allocation = gdk_region_rectangle (&widget_allocation);
+ gdk_region_offset (old_allocation,
+ -widget_allocation.x, -widget_allocation.y);
+ invalid = gdk_region_rectangle (allocation);
+ gdk_region_offset (invalid, -allocation->x, -allocation->y);
+ gdk_region_xor (invalid, old_allocation);
+ allocation_to_canvas_region (scroll_area, invalid);
+ foo_scroll_area_invalidate_region (scroll_area, invalid);
+ gdk_region_destroy (old_allocation);
+ gdk_region_destroy (invalid);
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (scroll_area->priv->input_window)
+ {
+ GdkPixmap *new_pixmap;
+
+ gdk_window_move_resize (scroll_area->priv->input_window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ new_pixmap = create_new_pixmap (widget, scroll_area->priv->pixmap);
+ g_object_unref (scroll_area->priv->pixmap);
+ scroll_area->priv->pixmap = new_pixmap;
+ }
+
+ get_viewport (scroll_area, &new_viewport);
+
+ emit_viewport_changed (scroll_area, &new_viewport, &old_viewport);
+}
+
+static void
+emit_input (FooScrollArea *scroll_area,
+ FooScrollAreaEventType type,
+ int x,
+ int y,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ FooScrollAreaEvent event;
+
+ if (!func)
+ return;
+
+ if (type != FOO_MOTION)
+ emit_input (scroll_area, FOO_MOTION, x, y, func, data);
+
+ event.type = type;
+ event.x = x;
+ event.y = y;
+
+ func (scroll_area, &event, data);
+}
+
+static void
+process_event (FooScrollArea *scroll_area,
+ FooScrollAreaEventType input_type,
+ int x,
+ int y)
+{
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+ guint i;
+
+ allocation_to_canvas (scroll_area, &x, &y);
+
+ if (scroll_area->priv->grabbed)
+ {
+ emit_input (scroll_area, input_type, x, y,
+ scroll_area->priv->grab_func,
+ scroll_area->priv->grab_data);
+ return;
+ }
+
+ for (i = 0; i < scroll_area->priv->input_regions->len; ++i)
+ {
+ InputRegion *region = scroll_area->priv->input_regions->pdata[i];
+
+ if (gdk_region_point_in (region->region, x, y))
+ {
+ InputPath *path;
+
+ path = region->paths;
+ while (path)
+ {
+ cairo_t *cr;
+ gboolean inside;
+
+ cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ cairo_set_fill_rule (cr, path->fill_rule);
+ cairo_set_line_width (cr, path->line_width);
+ cairo_append_path (cr, path->path);
+
+ if (path->is_stroke)
+ inside = cairo_in_stroke (cr, x, y);
+ else
+ inside = cairo_in_fill (cr, x, y);
+
+ cairo_destroy (cr);
+
+ if (inside)
+ {
+ emit_input (scroll_area, input_type,
+ x, y,
+ path->func,
+ path->data);
+ return;
+ }
+
+ path = path->next;
+ }
+
+ /* Since the regions are all disjoint, no other region
+ * can match. Of course we could be clever and try and
+ * sort the regions, but so far I have been unable to
+ * make this loop show up on a profile.
+ */
+ return;
+ }
+ }
+}
+
+static void
+process_gdk_event (FooScrollArea *scroll_area,
+ int x,
+ int y,
+ GdkEvent *event)
+{
+ FooScrollAreaEventType input_type;
+
+ if (event->type == GDK_BUTTON_PRESS)
+ input_type = FOO_BUTTON_PRESS;
+ else if (event->type == GDK_BUTTON_RELEASE)
+ input_type = FOO_BUTTON_RELEASE;
+ else if (event->type == GDK_MOTION_NOTIFY)
+ input_type = FOO_MOTION;
+ else
+ return;
+
+ process_event (scroll_area, input_type, x, y);
+}
+
+static gboolean
+foo_scroll_area_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ process_gdk_event (area, event->x, event->y, (GdkEvent *)event);
+
+ return TRUE;
+}
+
+static gboolean
+foo_scroll_area_button_release (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ process_gdk_event (area, event->x, event->y, (GdkEvent *)event);
+
+ return FALSE;
+}
+
+static gboolean
+foo_scroll_area_motion (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ process_gdk_event (area, event->x, event->y, (GdkEvent *)event);
+ return TRUE;
+}
+
+void
+foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area,
+ int width,
+ int height,
+ int old_y,
+ int new_y)
+{
+ scroll_area->priv->width = width;
+ scroll_area->priv->height = height;
+
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj));
+ gtk_adjustment_set_value (scroll_area->priv->vadj, new_y);
+
+ set_adjustment_values (scroll_area);
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj));
+}
+
+void
+foo_scroll_area_set_size (FooScrollArea *scroll_area,
+ int width,
+ int height)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ /* FIXME: Default scroll algorithm should probably be to
+ * keep the same *area* outside the screen as before.
+ *
+ * For wrapper widgets that will do something roughly
+ * right. For widgets that don't change size, it
+ * will do the right thing. Except for idle-layouting
+ * widgets.
+ *
+ * Maybe there should be some generic support for those
+ * widgets. Can that even be done?
+ *
+ * Should we have a version of this function using
+ * fixed points?
+ */
+
+ scroll_area->priv->width = width;
+ scroll_area->priv->height = height;
+
+ set_adjustment_values (scroll_area);
+}
+
+static void
+foo_scroll_area_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget);
+
+ requisition->width = scroll_area->priv->min_width;
+ requisition->height = scroll_area->priv->min_height;
+}
+
+static void
+foo_scroll_area_scroll (FooScrollArea *area,
+ gint dx,
+ gint dy)
+{
+ GdkRectangle allocation;
+ GdkRectangle src_area;
+ GdkRectangle move_area;
+ GdkRegion *invalid_region;
+
+ gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
+ allocation.x = 0;
+ allocation.y = 0;
+
+ src_area = allocation;
+ src_area.x -= dx;
+ src_area.y -= dy;
+
+ invalid_region = gdk_region_rectangle (&allocation);
+
+ if (gdk_rectangle_intersect (&allocation, &src_area, &move_area))
+ {
+ GdkRegion *move_region;
+
+ simple_draw_drawable (area->priv->pixmap, area->priv->pixmap,
+ move_area.x, move_area.y,
+ move_area.x + dx, move_area.y + dy,
+ move_area.width, move_area.height);
+
+ gtk_widget_queue_draw (GTK_WIDGET (area));
+
+ move_region = gdk_region_rectangle (&move_area);
+ gdk_region_offset (move_region, dx, dy);
+ gdk_region_subtract (invalid_region, move_region);
+ gdk_region_destroy (move_region);
+ }
+
+ allocation_to_canvas_region (area, invalid_region);
+
+ foo_scroll_area_invalidate_region (area, invalid_region);
+
+ gdk_region_destroy (invalid_region);
+}
+
+static void
+foo_scrollbar_adjustment_changed (GtkAdjustment *adj,
+ FooScrollArea *scroll_area)
+{
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+ gint dx = 0;
+ gint dy = 0;
+ GdkRectangle old_viewport, new_viewport;
+
+ get_viewport (scroll_area, &old_viewport);
+
+ if (adj == scroll_area->priv->hadj)
+ {
+ /* FIXME: do we treat the offset as int or double, and,
+ * if int, how do we round?
+ */
+ dx = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->x_offset;
+ scroll_area->priv->x_offset = gtk_adjustment_get_value (adj);
+ }
+ else if (adj == scroll_area->priv->vadj)
+ {
+ dy = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->y_offset;
+ scroll_area->priv->y_offset = gtk_adjustment_get_value (adj);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ if (gtk_widget_get_realized (widget))
+ {
+ foo_scroll_area_scroll (scroll_area, -dx, -dy);
+ }
+
+ get_viewport (scroll_area, &new_viewport);
+
+ emit_viewport_changed (scroll_area, &new_viewport, &old_viewport);
+}
+
+static void
+set_one_adjustment (FooScrollArea *scroll_area,
+ GtkAdjustment *adjustment,
+ GtkAdjustment **location)
+{
+ g_return_if_fail (location != NULL);
+
+ if (adjustment == *location)
+ return;
+
+ if (!adjustment)
+ adjustment = new_adjustment ();
+
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ if (*location)
+ {
+ g_signal_handlers_disconnect_by_func (
+ *location, foo_scrollbar_adjustment_changed, scroll_area);
+
+ g_object_unref (*location);
+ }
+
+ *location = adjustment;
+
+ g_object_ref_sink (*location);
+
+ g_signal_connect (*location, "value_changed",
+ G_CALLBACK (foo_scrollbar_adjustment_changed),
+ scroll_area);
+}
+
+static void
+foo_scroll_area_set_scroll_adjustments (FooScrollArea *scroll_area,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ set_one_adjustment (scroll_area, hadjustment, &scroll_area->priv->hadj);
+ set_one_adjustment (scroll_area, vadjustment, &scroll_area->priv->vadj);
+
+ set_adjustment_values (scroll_area);
+}
+
+FooScrollArea *
+foo_scroll_area_new (void)
+{
+ return g_object_new (FOO_TYPE_SCROLL_AREA, NULL);
+}
+
+void
+foo_scroll_area_set_min_size (FooScrollArea *scroll_area,
+ int min_width,
+ int min_height)
+{
+ scroll_area->priv->min_width = min_width;
+ scroll_area->priv->min_height = min_height;
+
+ /* FIXME: think through invalidation.
+ *
+ * Goals: - no repainting everything on size_allocate(),
+ * - make sure input boxes are invalidated when
+ * needed
+ */
+ gtk_widget_queue_resize (GTK_WIDGET (scroll_area));
+}
+
+static void
+user_to_device (double *x, double *y,
+ gpointer data)
+{
+ cairo_t *cr = data;
+
+ cairo_user_to_device (cr, x, y);
+}
+
+static InputPath *
+make_path (FooScrollArea *area,
+ cairo_t *cr,
+ gboolean is_stroke,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ InputPath *path = g_new0 (InputPath, 1);
+
+ path->is_stroke = is_stroke;
+ path->fill_rule = cairo_get_fill_rule (cr);
+ path->line_width = cairo_get_line_width (cr);
+ path->path = cairo_copy_path (cr);
+ path_foreach_point (path->path, user_to_device, cr);
+ path->func = func;
+ path->data = data;
+ path->next = area->priv->current_input->paths;
+ area->priv->current_input->paths = path;
+ return path;
+}
+
+/* FIXME: we probably really want a
+ *
+ * foo_scroll_area_add_input_from_fill (area, cr, ...);
+ * and
+ * foo_scroll_area_add_input_from_stroke (area, cr, ...);
+ * as well.
+ */
+void
+foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (scroll_area->priv->current_input);
+
+ make_path (scroll_area, cr, FALSE, func, data);
+}
+
+void
+foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (scroll_area->priv->current_input);
+
+ make_path (scroll_area, cr, TRUE, func, data);
+}
+
+void
+foo_scroll_area_invalidate (FooScrollArea *scroll_area)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ foo_scroll_area_invalidate_rect (scroll_area,
+ scroll_area->priv->x_offset, scroll_area->priv->y_offset,
+ allocation.width,
+ allocation.height);
+}
+
+static void
+canvas_to_window (FooScrollArea *area,
+ GdkRegion *region)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ gdk_region_offset (region,
+ -area->priv->x_offset + allocation.x,
+ -area->priv->y_offset + allocation.y);
+}
+
+static void
+window_to_canvas (FooScrollArea *area,
+ GdkRegion *region)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ gdk_region_offset (region,
+ area->priv->x_offset - allocation.x,
+ area->priv->y_offset - allocation.y);
+}
+
+void
+foo_scroll_area_invalidate_region (FooScrollArea *area,
+ GdkRegion *region)
+{
+ GtkWidget *widget;
+
+ g_return_if_fail (FOO_IS_SCROLL_AREA (area));
+
+ widget = GTK_WIDGET (area);
+
+ gdk_region_union (area->priv->update_region, region);
+
+ if (gtk_widget_get_realized (widget))
+ {
+ canvas_to_window (area, region);
+
+ gdk_window_invalidate_region (gtk_widget_get_window (widget),
+ region, TRUE);
+
+ window_to_canvas (area, region);
+ }
+}
+
+void
+foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GdkRectangle rect = { x, y, width, height };
+ GdkRegion *region;
+
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ region = gdk_region_rectangle (&rect);
+
+ foo_scroll_area_invalidate_region (scroll_area, region);
+
+ gdk_region_destroy (region);
+}
+
+void
+foo_scroll_area_begin_grab (FooScrollArea *scroll_area,
+ FooScrollAreaEventFunc func,
+ gpointer input_data)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+ g_return_if_fail (!scroll_area->priv->grabbed);
+
+ scroll_area->priv->grabbed = TRUE;
+ scroll_area->priv->grab_func = func;
+ scroll_area->priv->grab_data = input_data;
+
+ /* FIXME: we should probably take a server grab */
+ /* Also, maybe there should be support for setting the grab cursor */
+}
+
+void
+foo_scroll_area_end_grab (FooScrollArea *scroll_area)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ scroll_area->priv->grabbed = FALSE;
+ scroll_area->priv->grab_func = NULL;
+ scroll_area->priv->grab_data = NULL;
+}
+
+gboolean
+foo_scroll_area_is_grabbed (FooScrollArea *scroll_area)
+{
+ return scroll_area->priv->grabbed;
+}
+
+void
+foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area,
+ int x,
+ int y)
+{
+ g_object_freeze_notify (G_OBJECT (scroll_area->priv->hadj));
+ g_object_freeze_notify (G_OBJECT (scroll_area->priv->vadj));
+ gtk_adjustment_set_value (scroll_area->priv->hadj, x);
+ gtk_adjustment_set_value (scroll_area->priv->vadj, y);
+
+ set_adjustment_values (scroll_area);
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->hadj));
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj));
+}
+
+static gboolean
+rect_contains (const GdkRectangle *rect, int x, int y)
+{
+ return (x >= rect->x &&
+ y >= rect->y &&
+ x < rect->x + rect->width &&
+ y < rect->y + rect->height);
+}
+
+static void
+stop_scrolling (FooScrollArea *area)
+{
+ if (area->priv->auto_scroll_info)
+ {
+ g_source_remove (area->priv->auto_scroll_info->timeout_id);
+ g_timer_destroy (area->priv->auto_scroll_info->timer);
+ g_free (area->priv->auto_scroll_info);
+
+ area->priv->auto_scroll_info = NULL;
+ }
+}
+
+static gboolean
+scroll_idle (gpointer data)
+{
+ GdkRectangle viewport, new_viewport;
+ FooScrollArea *area = data;
+ AutoScrollInfo *info = area->priv->auto_scroll_info;
+ int new_x, new_y;
+ double elapsed;
+
+ get_viewport (area, &viewport);
+
+ elapsed = g_timer_elapsed (info->timer, NULL);
+
+ info->res_x = elapsed * info->dx / 0.2;
+ info->res_y = elapsed * info->dy / 0.2;
+
+ new_x = viewport.x + info->res_x;
+ new_y = viewport.y + info->res_y;
+
+ foo_scroll_area_set_viewport_pos (area, new_x, new_y);
+
+ get_viewport (area, &new_viewport);
+
+ if (viewport.x == new_viewport.x &&
+ viewport.y == new_viewport.y &&
+ (info->res_x > 1.0 ||
+ info->res_y > 1.0 ||
+ info->res_x < -1.0 ||
+ info->res_y < -1.0))
+ {
+ stop_scrolling (area);
+
+ /* stop scrolling if it didn't have an effect */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+ensure_scrolling (FooScrollArea *area,
+ int dx,
+ int dy)
+{
+ if (!area->priv->auto_scroll_info)
+ {
+ area->priv->auto_scroll_info = g_new0 (AutoScrollInfo, 1);
+ area->priv->auto_scroll_info->timeout_id =
+ g_idle_add (scroll_idle, area);
+ area->priv->auto_scroll_info->timer = g_timer_new ();
+ }
+
+ area->priv->auto_scroll_info->dx = dx;
+ area->priv->auto_scroll_info->dy = dy;
+}
+
+void
+foo_scroll_area_auto_scroll (FooScrollArea *scroll_area,
+ FooScrollAreaEvent *event)
+{
+ GdkRectangle viewport;
+
+ get_viewport (scroll_area, &viewport);
+
+ if (rect_contains (&viewport, event->x, event->y))
+ {
+ stop_scrolling (scroll_area);
+ }
+ else
+ {
+ int dx, dy;
+
+ dx = dy = 0;
+
+ if (event->y < viewport.y)
+ {
+ dy = event->y - viewport.y;
+ dy = MIN (dy + 2, 0);
+ }
+ else if (event->y >= viewport.y + viewport.height)
+ {
+ dy = event->y - (viewport.y + viewport.height - 1);
+ dy = MAX (dy - 2, 0);
+ }
+
+ if (event->x < viewport.x)
+ {
+ dx = event->x - viewport.x;
+ dx = MIN (dx + 2, 0);
+ }
+ else if (event->x >= viewport.x + viewport.width)
+ {
+ dx = event->x - (viewport.x + viewport.width - 1);
+ dx = MAX (dx - 2, 0);
+ }
+
+ ensure_scrolling (scroll_area, dx, dy);
+ }
+}
+
+void
+foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area)
+{
+ /* noop for now */
+}
+
+void
+foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area)
+{
+ stop_scrolling (scroll_area);
+}
diff --git a/dialogs/display-settings/scrollarea.h b/dialogs/display-settings/scrollarea.h
new file mode 100644
index 0000000..dc8bb0d
--- /dev/null
+++ b/dialogs/display-settings/scrollarea.h
@@ -0,0 +1,137 @@
+/* Copyright 2006, 2007, 2008, Soren Sandmann <sandmann at daimi.au.dk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#define FOO_TYPE_SCROLL_AREA (foo_scroll_area_get_type ())
+#define FOO_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_SCROLL_AREA, FooScrollArea))
+#define FOO_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass))
+#define FOO_IS_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_SCROLL_AREA))
+#define FOO_IS_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_SCROLL_AREA))
+#define FOO_SCROLL_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass))
+
+typedef struct FooScrollArea FooScrollArea;
+typedef struct FooScrollAreaClass FooScrollAreaClass;
+typedef struct FooScrollAreaPrivate FooScrollAreaPrivate;
+typedef struct FooScrollAreaEvent FooScrollAreaEvent;
+
+typedef enum
+{
+ FOO_BUTTON_PRESS,
+ FOO_BUTTON_RELEASE,
+ FOO_MOTION
+} FooScrollAreaEventType;
+
+struct FooScrollAreaEvent
+{
+ FooScrollAreaEventType type;
+ int x;
+ int y;
+};
+
+typedef void (* FooScrollAreaEventFunc) (FooScrollArea *area,
+ FooScrollAreaEvent *event,
+ gpointer data);
+
+struct FooScrollArea
+{
+ GtkContainer parent_instance;
+
+ FooScrollAreaPrivate *priv;
+};
+
+struct FooScrollAreaClass
+{
+ GtkContainerClass parent_class;
+
+ void (*set_scroll_adjustments) (FooScrollArea *scroll_area,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+
+ void (*viewport_changed) (FooScrollArea *scroll_area,
+ GdkRectangle *old_viewport,
+ GdkRectangle *new_viewport);
+
+ void (*paint) (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ GdkRectangle *extents,
+ GdkRegion *region);
+};
+
+GType foo_scroll_area_get_type (void);
+
+FooScrollArea *foo_scroll_area_new (void);
+
+/* Set the requisition for the widget. */
+void foo_scroll_area_set_min_size (FooScrollArea *scroll_area,
+ int min_width,
+ int min_height);
+
+/* Set how much of the canvas can be scrolled into view */
+void foo_scroll_area_set_size (FooScrollArea *scroll_area,
+ int width,
+ int height);
+
+void foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area,
+ int width,
+ int height,
+ int old_y,
+ int new_y);
+
+void foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area,
+ int x,
+ int y);
+
+void foo_scroll_area_get_viewport (FooScrollArea *scroll_area,
+ GdkRectangle *viewport);
+
+void foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data);
+
+void foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data);
+
+void foo_scroll_area_invalidate_region (FooScrollArea *area,
+ GdkRegion *region);
+
+void foo_scroll_area_invalidate (FooScrollArea *scroll_area);
+
+void foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area,
+ int x,
+ int y,
+ int width,
+ int height);
+
+void foo_scroll_area_begin_grab (FooScrollArea *scroll_area,
+ FooScrollAreaEventFunc func,
+ gpointer input_data);
+
+void foo_scroll_area_end_grab (FooScrollArea *scroll_area);
+
+gboolean foo_scroll_area_is_grabbed (FooScrollArea *scroll_area);
+
+void foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area);
+
+void foo_scroll_area_auto_scroll (FooScrollArea *scroll_area,
+ FooScrollAreaEvent *event);
+
+void foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area);
diff --git a/dialogs/display-settings/xfce-randr.c b/dialogs/display-settings/xfce-randr.c
index c114824..1b3573f 100644
--- a/dialogs/display-settings/xfce-randr.c
+++ b/dialogs/display-settings/xfce-randr.c
@@ -36,17 +36,6 @@
-typedef struct _XfceOutputPosition XfceOutputPosition;
-
-
-
-struct _XfceOutputPosition
-{
- gint x;
- gint y;
-};
-
-
struct _XfceRandrPrivate
{
@@ -59,13 +48,13 @@ struct _XfceRandrPrivate
/* cache for the output/mode info */
XRROutputInfo **output_info;
XfceRRMode **modes;
- XfceOutputPosition *position;
};
static gchar *xfce_randr_friendly_name (XfceRandr *randr,
- guint output);
+ guint output,
+ guint output_rr_id);
@@ -140,111 +129,39 @@ xfce_randr_guess_relations (XfceRandr *randr)
guint n, m;
/* walk the connected outputs */
- for (n = 0; n < randr->noutput; ++n)
+ for (n=0; n < randr->noutput; ++n)
{
/* ignore relations for inactive outputs */
if (randr->mode[n] == None)
continue;
- for (m = 0; m < randr->noutput; ++m)
+ for (m=0; m < randr->noutput; ++m)
{
/* additionally ignore itself */
if (randr->mode[m] == None || m == n)
continue;
- /* horizontal scale */
- if (randr->priv->position[n].x == randr->priv->position[m].x)
+ if (randr->position[n].x == randr->position[m].x &&
+ randr->position[n].y == randr->position[m].y)
{
- if (randr->priv->position[n].y == randr->priv->position[m].y)
- randr->relation[n] = XFCE_RANDR_PLACEMENT_MIRROR;
- else if (randr->priv->position[n].y > randr->priv->position[m].y)
- randr->relation[n] = XFCE_RANDR_PLACEMENT_DOWN;
- else
- randr->relation[n] = XFCE_RANDR_PLACEMENT_UP;
-
- randr->related_to[n] = m;
- break;
- }
-
- /* vertical scale */
- if (randr->priv->position[n].y == randr->priv->position[m].y)
- {
- if (randr->priv->position[n].x == randr->priv->position[m].x)
- randr->relation[n] = XFCE_RANDR_PLACEMENT_MIRROR;
- else if (randr->priv->position[n].x > randr->priv->position[m].x)
- randr->relation[n] = XFCE_RANDR_PLACEMENT_RIGHT;
- else
- randr->relation[n] = XFCE_RANDR_PLACEMENT_LEFT;
-
- randr->related_to[n] = m;
- break;
+ randr->mirrored[n] = TRUE;
}
}
}
}
-
-static void
-xfce_randr_update_positions (XfceRandr *randr,
- guint output)
-{
- const XfceRRMode *cmode, *rmode;
- guint rel;
- gint x, y;
-
- rel = randr->related_to[output];
- /* ignore relations for inactive outputs */
- if (randr->mode[output] == None || randr->mode[rel] == None)
- return;
-
- /* modes of the two related outputs */
- cmode = xfce_randr_find_mode_by_id (randr, output, randr->mode[output]);
- rmode = xfce_randr_find_mode_by_id (randr, rel, randr->mode[rel]);
-
- /* coordinates of the related_to output */
- x = randr->priv->position[rel].x;
- y = randr->priv->position[rel].y;
-
- switch (randr->relation[output])
- {
- case XFCE_RANDR_PLACEMENT_LEFT:
- randr->priv->position[output].x = x;
- randr->priv->position[output].y = y;
- randr->priv->position[rel].x = x + xfce_randr_mode_width (cmode, randr->rotation[output]);
- break;
- case XFCE_RANDR_PLACEMENT_RIGHT:
- randr->priv->position[output].x = x + xfce_randr_mode_width (rmode, randr->rotation[rel]);
- randr->priv->position[output].y = y;
- break;
- case XFCE_RANDR_PLACEMENT_UP:
- randr->priv->position[output].x = x;
- randr->priv->position[output].y = y;
- randr->priv->position[rel].y = y + xfce_randr_mode_height (cmode, randr->rotation[output]);
- break;
- case XFCE_RANDR_PLACEMENT_DOWN:
- randr->priv->position[output].x = x;
- randr->priv->position[output].y = y + xfce_randr_mode_height (rmode, randr->rotation[rel]);
- break;
- default:
- randr->priv->position[output].x = x;
- randr->priv->position[output].y = y;
- break;
- }
-}
-
-
-
static void
xfce_randr_populate (XfceRandr *randr,
Display *xdisplay,
GdkWindow *root_window)
{
- GPtrArray *outputs;
- XRROutputInfo *output_info;
- XRRCrtcInfo *crtc_info;
- gint n;
- guint m;
+ GPtrArray *outputs;
+ XRROutputInfo *output_info;
+ XRRCrtcInfo *crtc_info;
+ gint n;
+ guint m, connected;
+ guint *output_ids = NULL;
g_return_if_fail (randr != NULL);
g_return_if_fail (randr->priv != NULL);
@@ -252,8 +169,10 @@ xfce_randr_populate (XfceRandr *randr,
/* prepare the temporary cache */
outputs = g_ptr_array_new ();
+ output_ids = g_malloc0 (randr->priv->resources->noutput * sizeof (guint));
/* walk the outputs */
+ connected = 0;
for (n = 0; n < randr->priv->resources->noutput; ++n)
{
/* get the output info */
@@ -266,6 +185,11 @@ xfce_randr_populate (XfceRandr *randr,
XRRFreeOutputInfo (output_info);
continue;
}
+ else
+ {
+ output_ids[connected] = n;
+ connected++;
+ }
/* cache it */
g_ptr_array_add (outputs, output_info);
@@ -278,11 +202,10 @@ xfce_randr_populate (XfceRandr *randr,
/* allocate final space for the settings */
randr->mode = g_new0 (RRMode, randr->noutput);
randr->priv->modes = g_new0 (XfceRRMode *, randr->noutput);
- randr->priv->position = g_new0 (XfceOutputPosition, randr->noutput);
+ randr->position = g_new0 (XfceOutputPosition, randr->noutput);
randr->rotation = g_new0 (Rotation, randr->noutput);
randr->rotations = g_new0 (Rotation, randr->noutput);
- randr->relation = g_new0 (XfceOutputRelation, randr->noutput);
- randr->related_to = g_new0 (guint, randr->noutput);
+ randr->mirrored = g_new0 (gboolean, randr->noutput);
randr->status = g_new0 (XfceOutputStatus, randr->noutput);
randr->friendly_name = g_new0 (gchar *, randr->noutput);
@@ -294,7 +217,7 @@ xfce_randr_populate (XfceRandr *randr,
#ifdef HAS_RANDR_ONE_POINT_THREE
/* find the primary screen if supported */
- if (randr->priv->has_1_3 && XRRGetOutputPrimary (xdisplay, GDK_WINDOW_XID (root_window)) == randr->priv->resources->outputs[m])
+ if (randr->priv->has_1_3 && XRRGetOutputPrimary (xdisplay, GDK_WINDOW_XID (root_window)) == randr->priv->resources->outputs[output_ids[m]])
randr->status[m] = XFCE_OUTPUT_STATUS_PRIMARY;
else
#endif
@@ -307,8 +230,8 @@ xfce_randr_populate (XfceRandr *randr,
randr->mode[m] = crtc_info->mode;
randr->rotation[m] = crtc_info->rotation;
randr->rotations[m] = crtc_info->rotations;
- randr->priv->position[m].x = crtc_info->x;
- randr->priv->position[m].y = crtc_info->y;
+ randr->position[m].x = crtc_info->x;
+ randr->position[m].y = crtc_info->y;
XRRFreeCrtcInfo (crtc_info);
}
else
@@ -320,11 +243,12 @@ xfce_randr_populate (XfceRandr *randr,
}
/* fill in the name used by the UI */
- randr->friendly_name[m] = xfce_randr_friendly_name (randr, m);
+ randr->friendly_name[m] = xfce_randr_friendly_name (randr, m, output_ids[m]);
}
-
- /* calculate relations from positions */
+ /* populate mirrored details */
xfce_randr_guess_relations (randr);
+
+ g_free (output_ids);
}
@@ -408,9 +332,7 @@ xfce_randr_cleanup (XfceRandr *randr)
g_free (randr->rotation);
g_free (randr->rotations);
g_free (randr->status);
- g_free (randr->relation);
- g_free (randr->related_to);
- g_free (randr->priv->position);
+ g_free (randr->position);
g_free (randr->priv->output_info);
}
@@ -463,8 +385,7 @@ void
xfce_randr_save_output (XfceRandr *randr,
const gchar *scheme,
XfconfChannel *channel,
- guint output,
- gint rel_changed)
+ guint output)
{
gchar property[512];
gchar *str_value;
@@ -539,17 +460,13 @@ xfce_randr_save_output (XfceRandr *randr,
randr->status[output] == XFCE_OUTPUT_STATUS_PRIMARY);
#endif
- /* update positions according to the current relations */
- if (rel_changed)
- xfce_randr_update_positions (randr, output);
-
/* save the position */
g_snprintf (property, sizeof (property), "/%s/%s/Position/X", scheme,
randr->priv->output_info[output]->name);
- xfconf_channel_set_int (channel, property, MAX (randr->priv->position[output].x, 0));
+ xfconf_channel_set_int (channel, property, MAX (randr->position[output].x, 0));
g_snprintf (property, sizeof (property), "/%s/%s/Position/Y", scheme,
randr->priv->output_info[output]->name);
- xfconf_channel_set_int (channel, property, MAX (randr->priv->position[output].y, 0));
+ xfconf_channel_set_int (channel, property, MAX (randr->position[output].y, 0));
}
@@ -612,12 +529,13 @@ xfce_randr_read_edid_data (Display *xdisplay,
static gchar *
xfce_randr_friendly_name (XfceRandr *randr,
- guint output)
+ guint output,
+ guint output_rr_id)
{
- Display *xdisplay;
- MonitorInfo *info = NULL;
- guint8 *edid_data;
- gchar *friendly_name = NULL;
+ Display *xdisplay;
+ MonitorInfo *info = NULL;
+ guint8 *edid_data;
+ gchar *friendly_name = NULL;
const gchar *name = randr->priv->output_info[output]->name;
/* special case, a laptop */
@@ -627,13 +545,13 @@ xfce_randr_friendly_name (XfceRandr *randr,
/* otherwise, get the vendor & size */
xdisplay = gdk_x11_display_get_xdisplay (randr->priv->display);
- edid_data = xfce_randr_read_edid_data (xdisplay, randr->priv->resources->outputs[output]);
+ edid_data = xfce_randr_read_edid_data (xdisplay, randr->priv->resources->outputs[output_rr_id]);
if (edid_data)
info = decode_edid (edid_data);
if (info)
- friendly_name = make_display_name (info);
+ friendly_name = make_display_name (info, output);
g_free (info);
g_free (edid_data);
@@ -784,8 +702,8 @@ xfce_randr_get_positions (XfceRandr *randr,
g_return_val_if_fail (randr != NULL && x != NULL && y != NULL, FALSE);
g_return_val_if_fail (output < randr->noutput, FALSE);
- *x = randr->priv->position[output].x;
- *y = randr->priv->position[output].y;
+ *x = randr->position[output].x;
+ *y = randr->position[output].y;
return TRUE;
}
diff --git a/dialogs/display-settings/xfce-randr.h b/dialogs/display-settings/xfce-randr.h
index 2a5ba4c..7bf23f3 100644
--- a/dialogs/display-settings/xfce-randr.h
+++ b/dialogs/display-settings/xfce-randr.h
@@ -37,8 +37,9 @@
typedef struct _XfceRandr XfceRandr;
typedef struct _XfceRandrPrivate XfceRandrPrivate;
typedef struct _XfceRRMode XfceRRMode;
+typedef struct _XfceOutputInfo XfceOutputInfo;
typedef enum _XfceOutputStatus XfceOutputStatus;
-typedef enum _XfceOutputRelation XfceOutputRelation;
+typedef struct _XfceOutputPosition XfceOutputPosition;
enum _XfceOutputStatus
{
@@ -46,15 +47,6 @@ enum _XfceOutputStatus
XFCE_OUTPUT_STATUS_SECONDARY
};
-enum _XfceOutputRelation
-{
- XFCE_RANDR_PLACEMENT_MIRROR,
- XFCE_RANDR_PLACEMENT_UP,
- XFCE_RANDR_PLACEMENT_DOWN,
- XFCE_RANDR_PLACEMENT_RIGHT,
- XFCE_RANDR_PLACEMENT_LEFT
-};
-
struct _XfceRRMode
{
RRMode id;
@@ -63,6 +55,12 @@ struct _XfceRRMode
gdouble rate;
};
+struct _XfceOutputPosition
+{
+ gint x;
+ gint y;
+};
+
struct _XfceRandr
{
/* number of connected outputs */
@@ -72,16 +70,43 @@ struct _XfceRandr
RRMode *mode;
Rotation *rotation;
Rotation *rotations;
- XfceOutputRelation *relation;
- guint *related_to;
+ XfceOutputPosition *position;
XfceOutputStatus *status;
+ gboolean *mirrored;
gchar **friendly_name;
/* implementation details */
XfceRandrPrivate *priv;
};
-
+struct _XfceOutputInfo
+{
+ /* Identifiers */
+ guint id;
+ gchar *display_name;
+
+ /* Status */
+ gboolean on;
+ gboolean connected;
+ gboolean mirrored;
+
+ /* Position */
+ gint x;
+ gint y;
+
+ /* Dimensions */
+ guint width;
+ guint height;
+ guint pref_width;
+ guint pref_height;
+ Rotation rotation;
+
+ /* Frequency */
+ gdouble rate;
+
+ /* User Data (e.g. GrabInfo) */
+ gpointer user_data;
+};
XfceRandr *xfce_randr_new (GdkDisplay *display,
GError **error);
@@ -93,8 +118,7 @@ void xfce_randr_reload (XfceRandr *randr);
void xfce_randr_save_output (XfceRandr *randr,
const gchar *scheme,
XfconfChannel *channel,
- guint output,
- gint rel_changed);
+ guint output);
void xfce_randr_apply (XfceRandr *randr,
const gchar *scheme,
diff --git a/xfsettingsd/debug.c b/xfsettingsd/debug.c
index e9653e8..1b26a6d 100644
--- a/xfsettingsd/debug.c
+++ b/xfsettingsd/debug.c
@@ -70,7 +70,7 @@ xfsettings_dbg_init (void)
-static void
+static void __attribute__((format (gnu_printf, 2,0)))
xfsettings_dbg_print (XfsdDebugDomain domain,
const gchar *message,
va_list args)
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the Xfce4-commits
mailing list