diff options
author | William Hua <william.hua@canonical.com> | 2015-09-18 13:40:36 -0400 |
---|---|---|
committer | William Hua <william.hua@canonical.com> | 2016-01-06 10:37:41 -0500 |
commit | 24c54e7f982955c48b320079763b4896919c1f1c (patch) | |
tree | 9f460bb70612181df8ad179d9b738fa3c1238e8b | |
parent | 47afccb41bc5258b15b3b14148ffcc50fb3a0933 (diff) | |
download | gtk+-24c54e7f982955c48b320079763b4896919c1f1c.tar.gz |
gdkattachparams: add GdkAttachParams
-rw-r--r-- | docs/reference/gdk/Makefile.am | 2 | ||||
-rw-r--r-- | docs/reference/gdk/gdk-docs.sgml | 1 | ||||
-rw-r--r-- | docs/reference/gdk/gdk3-sections.txt | 30 | ||||
-rw-r--r-- | docs/reference/gdk/images/gdkattachparams.png | bin | 0 -> 19297 bytes | |||
-rw-r--r-- | docs/reference/gdk/images/gdkattachparams.svg | 729 | ||||
-rw-r--r-- | docs/reference/gdk/images/gdkattachrule.png | bin | 0 -> 29487 bytes | |||
-rw-r--r-- | gdk/Makefile.am | 3 | ||||
-rw-r--r-- | gdk/gdk.h | 1 | ||||
-rw-r--r-- | gdk/gdkattachparams.c | 932 | ||||
-rw-r--r-- | gdk/gdkattachparams.h | 165 | ||||
-rw-r--r-- | gdk/gdkattachparamsprivate.h | 83 |
11 files changed, 1946 insertions, 0 deletions
diff --git a/docs/reference/gdk/Makefile.am b/docs/reference/gdk/Makefile.am index aef7cabca8..857c8dbed8 100644 --- a/docs/reference/gdk/Makefile.am +++ b/docs/reference/gdk/Makefile.am @@ -85,6 +85,8 @@ HTML_IMAGES = \ images/draped_box.png \ images/exchange.png \ images/fleur.png \ + images/gdkattachparams.png \ + images/gdkattachrule.png \ images/gobbler.png \ images/gumby.png \ images/hand1.png \ diff --git a/docs/reference/gdk/gdk-docs.sgml b/docs/reference/gdk/gdk-docs.sgml index fdd36a4444..6962b4de10 100644 --- a/docs/reference/gdk/gdk-docs.sgml +++ b/docs/reference/gdk/gdk-docs.sgml @@ -47,6 +47,7 @@ <xi:include href="xml/wayland_interaction.xml" /> <xi:include href="xml/gdkapplaunchcontext.xml" /> <xi:include href="xml/gdktestutils.xml" /> + <xi:include href="xml/gdkattachparams.xml" /> </reference> <reference> diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt index 7b1b9f7419..15690c11bf 100644 --- a/docs/reference/gdk/gdk3-sections.txt +++ b/docs/reference/gdk/gdk3-sections.txt @@ -551,6 +551,36 @@ gdk_fullscreen_mode_get_type </SECTION> <SECTION> +<TITLE>Attachment Parameters</TITLE> +<FILE>gdkattachparams</FILE> +GdkAttachParams +GdkAttachRule +GdkAttachCallback +gdk_attach_params_new +gdk_attach_params_copy +gdk_attach_params_free +gdk_attach_params_set_attach_origin +gdk_attach_params_set_attach_rect +gdk_attach_params_set_attach_margin +gdk_attach_params_set_window_margin +gdk_attach_params_set_window_padding +gdk_attach_params_set_window_offset +gdk_attach_params_add_primary_rules +gdk_attach_params_add_secondary_rules +gdk_attach_params_add_primary_rules_valist +gdk_attach_params_add_secondary_rules_valist +gdk_attach_params_primary_rules_foreach +gdk_attach_params_secondary_rules_foreach +gdk_attach_params_set_position_callback + +<SUBSECTION Private> +_GdkAttachParams +gdk_attach_params_choose_position +gdk_attach_params_choose_position_for_window +gdk_attach_params_move_window +</SECTION> + +<SECTION> <TITLE>Selections</TITLE> <FILE>selections</FILE> GDK_SELECTION_PRIMARY diff --git a/docs/reference/gdk/images/gdkattachparams.png b/docs/reference/gdk/images/gdkattachparams.png Binary files differnew file mode 100644 index 0000000000..8695098edf --- /dev/null +++ b/docs/reference/gdk/images/gdkattachparams.png diff --git a/docs/reference/gdk/images/gdkattachparams.svg b/docs/reference/gdk/images/gdkattachparams.svg new file mode 100644 index 0000000000..2d9c965298 --- /dev/null +++ b/docs/reference/gdk/images/gdkattachparams.svg @@ -0,0 +1,729 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="520" + height="540" + viewBox="0 0 520.00001 540" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="gdkattachparams.svg"> + <defs + id="defs4"> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker4541" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + inkscape:connector-curvature="0" + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path4543" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker4477" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotM"> + <path + inkscape:connector-curvature="0" + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path4479" /> + </marker> + <marker + inkscape:stockid="Arrow2Mstart" + orient="auto" + refY="0" + refX="0" + id="Arrow2Mstart" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path4354" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="scale(0.6,0.6)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0" + refX="0" + id="Arrow1Mstart" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path4336" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + transform="matrix(0.4,0,0,0.4,4,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker9510" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend"> + <path + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path9512" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="DotM" + orient="auto" + refY="0" + refX="0" + id="marker8880" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path8882" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker4896" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow2Mend" + inkscape:collect="always"> + <path + transform="scale(-0.6,-0.6)" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + id="path4898" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker4868" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="DotM" + inkscape:collect="always"> + <path + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + id="path4870" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow2Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Mend" + style="overflow:visible" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path4357" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="scale(-0.6,-0.6)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="DotM" + orient="auto" + refY="0" + refX="0" + id="DotM" + style="overflow:visible" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path4394" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + transform="matrix(0.4,0,0,0.4,2.96,0.4)" + inkscape:connector-curvature="0" /> + </marker> + <filter + style="color-interpolation-filters:sRGB" + inkscape:label="Drop Shadow" + id="filter4230"> + <feFlood + flood-opacity="0.498039" + flood-color="rgb(0,0,0)" + result="flood" + id="feFlood4232" /> + <feComposite + in="flood" + in2="SourceGraphic" + operator="in" + result="composite1" + id="feComposite4234" /> + <feGaussianBlur + in="composite1" + stdDeviation="10" + result="blur" + id="feGaussianBlur4236" /> + <feOffset + dx="0" + dy="0" + result="offset" + id="feOffset4238" /> + <feComposite + in="SourceGraphic" + in2="offset" + operator="over" + result="fbSourceGraphic" + id="feComposite4240" /> + <feColorMatrix + result="fbSourceGraphicAlpha" + in="fbSourceGraphic" + values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0" + id="feColorMatrix4242" /> + <feFlood + id="feFlood4244" + flood-opacity="0.498039" + flood-color="rgb(0,0,0)" + result="flood" + in="fbSourceGraphic" /> + <feComposite + id="feComposite4246" + in2="fbSourceGraphic" + in="flood" + operator="out" + result="composite1" /> + <feGaussianBlur + id="feGaussianBlur4248" + in="composite1" + stdDeviation="10" + result="blur" /> + <feOffset + id="feOffset4250" + dx="0" + dy="0" + result="offset" /> + <feComposite + id="feComposite4252" + in2="fbSourceGraphic" + in="offset" + operator="atop" + result="fbSourceGraphic" /> + <feColorMatrix + result="fbSourceGraphicAlpha" + in="fbSourceGraphic" + values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0" + id="feColorMatrix4254" /> + <feFlood + id="feFlood4256" + flood-opacity="0.498039" + flood-color="rgb(0,0,0)" + result="flood" + in="fbSourceGraphic" /> + <feComposite + id="feComposite4258" + in2="fbSourceGraphic" + in="flood" + operator="out" + result="composite1" /> + <feGaussianBlur + id="feGaussianBlur4260" + in="composite1" + stdDeviation="10" + result="blur" /> + <feOffset + id="feOffset4262" + dx="0" + dy="0" + result="offset" /> + <feComposite + id="feComposite4264" + in2="fbSourceGraphic" + in="offset" + operator="atop" + result="composite2" /> + </filter> + <filter + style="color-interpolation-filters:sRGB" + inkscape:label="Drop Shadow" + id="filter4268"> + <feFlood + flood-opacity="0.498039" + flood-color="rgb(0,0,0)" + result="flood" + id="feFlood4270" /> + <feComposite + in="flood" + in2="SourceGraphic" + operator="in" + result="composite1" + id="feComposite4272" /> + <feGaussianBlur + in="composite1" + stdDeviation="20" + result="blur" + id="feGaussianBlur4274" /> + <feOffset + dx="0" + dy="0" + result="offset" + id="feOffset4276" /> + <feComposite + in="SourceGraphic" + in2="offset" + operator="over" + result="fbSourceGraphic" + id="feComposite4278" /> + <feColorMatrix + result="fbSourceGraphicAlpha" + in="fbSourceGraphic" + values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0" + id="feColorMatrix4280" /> + <feFlood + id="feFlood4282" + flood-opacity="0.498039" + flood-color="rgb(0,0,0)" + result="flood" + in="fbSourceGraphic" /> + <feComposite + id="feComposite4284" + in2="fbSourceGraphic" + in="flood" + operator="in" + result="composite1" /> + <feGaussianBlur + id="feGaussianBlur4286" + in="composite1" + stdDeviation="20" + result="blur" /> + <feOffset + id="feOffset4288" + dx="0" + dy="0" + result="offset" /> + <feComposite + id="feComposite4290" + in2="offset" + in="offset" + operator="atop" + result="composite2" /> + </filter> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1" + inkscape:cx="260" + inkscape:cy="269.99998" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1215" + inkscape:window-height="776" + inkscape:window-x="65" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:snap-path-clip="true" + inkscape:snap-path-mask="true" + objecttolerance="10000" + inkscape:snap-bbox="true" + units="px" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-512.36216)"> + <g + id="g7389" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <rect + y="772.36218" + x="0" + height="280" + width="440" + id="rect14784" + style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <g + id="g7355"> + <rect + style="fill:#0000ff;fill-opacity:0.50196078;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3336" + width="99" + height="19" + x="220.5" + y="817.70105" /> + <rect + style="fill:#ff00ff;fill-opacity:0.50196078;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3338" + width="199" + height="99" + x="220.5" + y="837.70105" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" + d="m 220,937.20109 0,50" + id="path4292" + inkscape:connector-curvature="0" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="220.55762" + y="999.84265" + id="text4294" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4296" + x="220.55762" + y="999.84265">(GDK_ATTACH_AXIS_X |</tspan><tspan + sodipodi:role="line" + x="220.55762" + y="1012.3427" + id="tspan4304">GDK_ATTACH_RECT_MIN |</tspan><tspan + sodipodi:role="line" + x="220.55762" + y="1024.8427" + id="tspan4300">GDK_ATTACH_WINDOW_MIN)</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="163.67676" + y="827.34265" + id="text4306" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4308" + x="163.67676" + y="827.34265">(GDK_ATTACH_AXIS_Y |</tspan><tspan + sodipodi:role="line" + x="163.67676" + y="839.84265" + id="tspan4310">GDK_ATTACH_RECT_MAX |</tspan><tspan + sodipodi:role="line" + x="163.67676" + y="852.34265" + id="tspan4312">GDK_ATTACH_WINDOW_MIN)</tspan></text> + <path + inkscape:connector-curvature="0" + id="path4314" + d="m 170,837.20109 50,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="299.92188" + y="805.12097" + id="text4316" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4318" + x="299.92188" + y="805.12097">Attachment Rectangle</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="358.66797" + y="957.05945" + id="text4320" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4322" + x="358.66797" + y="957.05945">Window</tspan></text> + <path + inkscape:connector-curvature="0" + id="path4866" + d="m 294.97321,802.29289 -19.04081,23.801" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow2Mend)" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker4868);marker-end:url(#marker4896)" + d="m 354.06249,953.42949 -14.28061,-31.338" + id="path4324" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <g + id="g14739" + transform="translate(236,-218.16109)"> + <path + sodipodi:nodetypes="ccc" + inkscape:connector-curvature="0" + d="m -60,1102.3622 -40,0 0,40" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart);marker-end:url(#marker9510)" + id="path9508" /> + <text + sodipodi:linespacing="125%" + id="text14727" + y="1153.2821" + x="-107.05957" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + id="tspan14735" + y="1153.2821" + x="-107.05957" + sodipodi:role="line">+y</tspan></text> + <text + sodipodi:linespacing="125%" + id="text14731" + y="1105.3622" + x="-56.05957" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1105.3622" + x="-56.05957" + id="tspan14733" + sodipodi:role="line">+x</tspan></text> + </g> + </g> + </g> + <g + id="g7314" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <rect + y="512.36218" + x="6.2500001e-09" + height="260" + width="520" + id="rect15010" + style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <g + id="g7275"> + <rect + style="fill:#7f7fff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect14833" + width="159" + height="79" + x="195.9628" + y="614.86218" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="140.84619" + y="612.00378" + id="text14908" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan14910" + x="140.84619" + y="612.00378">GDK_ATTACH_AXIS_Y |</tspan><tspan + sodipodi:role="line" + x="140.84619" + y="624.50378" + id="tspan14912">GDK_ATTACH_RECT_MIN</tspan></text> + <text + sodipodi:linespacing="125%" + id="text14841" + y="543.75378" + x="196.36768" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="543.75378" + x="196.36768" + id="tspan14843" + sodipodi:role="line">GDK_ATTACH_AXIS_X |</tspan><tspan + id="tspan14845" + y="556.25378" + x="196.36768" + sodipodi:role="line">GDK_ATTACH_RECT_MIN</tspan></text> + <text + sodipodi:linespacing="125%" + id="text14914" + y="730.75256" + x="275.47546" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve" + transform="scale(0.9999983,1.0000017)"><tspan + y="730.75256" + x="275.47546" + id="tspan14916" + sodipodi:role="line">GDK_ATTACH_AXIS_X |</tspan><tspan + id="tspan14918" + y="743.25256" + x="275.47546" + sodipodi:role="line">GDK_ATTACH_RECT_MID</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="382.88916" + y="650.75378" + id="text14902" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan14904" + x="382.88916" + y="650.75378">GDK_ATTACH_AXIS_Y |</tspan><tspan + sodipodi:role="line" + x="382.88916" + y="663.25378" + id="tspan14906">GDK_ATTACH_RECT_MID</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="352.75311" + y="543.75378" + id="text14920" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan14922" + x="352.75311" + y="543.75378">GDK_ATTACH_AXIS_X |</tspan><tspan + sodipodi:role="line" + x="352.75311" + y="556.25378" + id="tspan14924">GDK_ATTACH_RECT_MAX</tspan></text> + <text + sodipodi:linespacing="125%" + id="text14847" + y="690.00378" + x="140.18213" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="690.00378" + x="140.18213" + id="tspan14849" + sodipodi:role="line">GDK_ATTACH_AXIS_Y |</tspan><tspan + id="tspan14851" + y="702.50378" + x="140.18213" + sodipodi:role="line">GDK_ATTACH_RECT_MAX</tspan></text> + <path + inkscape:connector-curvature="0" + id="path14928" + d="m 145.45068,693.61218 50,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" + d="m 279.45068,654.61218 100,0" + id="path14932" + inkscape:connector-curvature="0" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" + d="m 196.45068,614.61218 0,-50" + id="path14934" + inkscape:connector-curvature="0" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" + d="m 354.45068,614.61218 0,-50" + id="path14936" + inkscape:connector-curvature="0" /> + <path + inkscape:connector-curvature="0" + id="path14930" + d="m 275.45068,717.6122 0,-60" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2.00000002, 2.00000002;stroke-dashoffset:0;stroke-opacity:1" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" + d="m 145.45068,615.61218 50,0" + id="path14926" + inkscape:connector-curvature="0" /> + <g + id="g14944" + transform="translate(94.710564,20.967103)"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 186.04342,628.34178 -10.6066,10.6066" + id="path14942" + inkscape:connector-curvature="0" /> + <path + inkscape:connector-curvature="0" + id="path14938" + d="m 186.04342,638.94838 -10.6066,-10.6066" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + </g> + <g + transform="translate(511.45068,-406.74998)" + id="g14998"> + <path + id="path15000" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart);marker-end:url(#marker9510)" + d="m -60,1102.3622 -40,0 0,40" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccc" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="-107.05957" + y="1153.2821" + id="text15002" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + x="-107.05957" + y="1153.2821" + id="tspan15004">+y</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="-56.05957" + y="1105.3622" + id="text15006" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan15008" + x="-56.05957" + y="1105.3622">+x</tspan></text> + </g> + <text + sodipodi:linespacing="125%" + id="text4471" + y="610.2821" + x="379.92188" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="610.2821" + x="379.92188" + id="tspan4473" + sodipodi:role="line">Attachment Rectangle</tspan></text> + <path + sodipodi:nodetypes="cc" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker4477);marker-end:url(#marker4541)" + d="m 374.97321,608.29289 -33.04081,17.801" + id="path4475" + inkscape:connector-curvature="0" /> + </g> + </g> + </g> +</svg> diff --git a/docs/reference/gdk/images/gdkattachrule.png b/docs/reference/gdk/images/gdkattachrule.png Binary files differnew file mode 100644 index 0000000000..54c1351048 --- /dev/null +++ b/docs/reference/gdk/images/gdkattachrule.png diff --git a/gdk/Makefile.am b/gdk/Makefile.am index bb0007afa8..a56dd566d1 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -63,6 +63,7 @@ gdk_public_h_sources = \ gdk.h \ gdk-autocleanup.h \ gdkapplaunchcontext.h \ + gdkattachparams.h \ gdkcairo.h \ gdkcursor.h \ gdkdevice.h \ @@ -103,6 +104,7 @@ gdk_h_sources = \ gdk_private_headers = \ gdk-private.h \ gdkapplaunchcontextprivate.h \ + gdkattachparamsprivate.h \ gdkcursorprivate.h \ gdkdevicemanagerprivate.h \ gdkdeviceprivate.h \ @@ -129,6 +131,7 @@ gdk_c_sources = \ gdk-private.c \ gdk.c \ gdkapplaunchcontext.c \ + gdkattachparams.c \ gdkcairo.c \ gdkcursor.c \ gdkdeprecated.c \ @@ -30,6 +30,7 @@ #include <gdk/gdkconfig.h> #include <gdk/gdkversionmacros.h> #include <gdk/gdkapplaunchcontext.h> +#include <gdk/gdkattachparams.h> #include <gdk/gdkcairo.h> #include <gdk/gdkcursor.h> #include <gdk/gdkdevice.h> diff --git a/gdk/gdkattachparams.c b/gdk/gdkattachparams.c new file mode 100644 index 0000000000..7aa8cc16c8 --- /dev/null +++ b/gdk/gdkattachparams.c @@ -0,0 +1,932 @@ +#include "config.h" + +#include "gdkattachparamsprivate.h" +#include "gdkscreen.h" +#include "gdkwindow.h" + +/** + * SECTION: gdkattachparams + * @section_id: gdkattachparams + * @title: Attachment Parameters + * @short_description: Describing relative window position + * @stability: Unstable + * @include: gdk/gdkattachparams.h + * + * A full description of how a window should be positioned relative to an + * attachment rectangle. + * + * Certain widgets such as menus and combo boxes don't require explicit + * absolute positioning; they only need to be aligned with respect to another + * anchoring widget, such as a menu item, in such a way to not overflow + * off-screen. GTK+ cannot always determine such an optimal position since it + * requires knowledge of the geometry of the monitor workarea as well as the + * ability to position windows in absolute root window coordinates, which some + * GDK backends do not support. + * + * A minimal #GdkAttachParams description should have an attachment rectangle, + * a list of primary constraints, and a list of secondary constraints. The + * attachment rectangle is the allocation of the anchoring widget, which can + * be a menu item, menu button, combo box, etc. It can even be a 1x1 pixel at + * the current cursor position. The primary constraints are a list of + * #GdkAttachRules in descending priority that the GDK backend can try in order + * to fix the position of the window either horizontally or vertically. The + * secondary constraints are a list of #GdkAttachRules in descending priority + * to fix the position of the window on the other axis. + * + * ![](gdkattachrule.png) + * + * A #GdkAttachRule is a bit mask that constrains the position of a window on a + * single axis: %GDK_ATTACH_AXIS_X or %GDK_ATTACH_AXIS_Y. It must also specify + * one of %GDK_ATTACH_RECT_MIN, %GDK_ATTACH_RECT_MID, or %GDK_ATTACH_RECT_MAX, + * and one of %GDK_ATTACH_WINDOW_MIN, %GDK_ATTACH_WINDOW_MID, or + * %GDK_ATTACH_WINDOW_MAX. The backend will make a best effort to align the + * window position to the attachment rectangle position on that axis, or move + * on to the next constraint if available. + * + * ![](gdkattachparams.png) + * + * There are also additional parameters that can be set to fine tune the + * positioning of the window, such as margins and paddings, as well as a + * callback to obtain the final position of the window. + * + * Since: 3.20 + */ + +/** + * gdk_attach_params_new: + * + * Creates a new #GdkAttachParams for describing the position of a #GdkWindow + * relative to an attachment #GdkRectangle. + * + * Returns: (transfer full): a new #GdkAttachParams, to be freed with + * gdk_attach_params_free() + * + * Since: 3.20 + */ +GdkAttachParams * +gdk_attach_params_new (void) +{ + GdkAttachParams *params = g_new0 (GdkAttachParams, 1); + + params->primary_rules = g_array_new (TRUE, TRUE, sizeof (GdkAttachRule)); + params->secondary_rules = g_array_new (TRUE, TRUE, sizeof (GdkAttachRule)); + + return params; +} + +/** + * gdk_attach_params_copy: + * @src: the #GdkAttachParams to copy + * @data: (nullable): unused + * + * Creates a deep copy of @src. + * + * Returns: (transfer full) (nullable): a deep copy of @src, to be freed with + * gdk_attach_params_free() + * + * Since: 3.20 + */ +gpointer +gdk_attach_params_copy (gconstpointer src, + gpointer data) +{ + GdkAttachParams *copy; + const GdkAttachParams *params; + + if (!src) + return NULL; + + params = src; + + copy = g_memdup (params, sizeof (*params)); + + copy->primary_rules = g_array_sized_new (TRUE, TRUE, sizeof (GdkAttachRule), + params->primary_rules->len); + + g_array_append_vals (copy->primary_rules, + params->primary_rules->data, + params->primary_rules->len); + + copy->secondary_rules = g_array_sized_new (TRUE, TRUE, sizeof (GdkAttachRule), + params->secondary_rules->len); + + g_array_append_vals (copy->secondary_rules, + params->secondary_rules->data, + params->secondary_rules->len); + + return copy; +} + +/** + * gdk_attach_params_free: + * @data: the #GdkAttachParams to free + * + * Releases @data. + * + * Since: 3.20 + */ +void +gdk_attach_params_free (gpointer data) +{ + GdkAttachParams *params; + + g_return_if_fail (data); + + params = data; + + if (params->attach_user_data && params->attach_destroy_notify) + params->attach_destroy_notify (params->attach_user_data); + + g_array_unref (params->secondary_rules); + g_array_unref (params->primary_rules); + + g_free (params); +} + +/** + * gdk_attach_params_set_attach_origin: + * @params: a #GdkAttachParams + * @x: x-coordinate of the attachment rectangle's origin + * @y: y-coordinate of the attachment rectangle's origin + * + * Sets the origin of the attachment rectangle's coordinate system in root + * coordinates. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_attach_origin (GdkAttachParams *params, + gint x, + gint y) +{ + g_return_if_fail (params); + + params->origin_x = x; + params->origin_y = y; +} + +/** + * gdk_attach_params_set_attach_rect: + * @params: a #GdkAttachParams + * @rectangle: (nullable): the attachment rectangle + * + * Sets the attachment rectangle the window needs to be aligned relative to. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_attach_rect (GdkAttachParams *params, + const GdkRectangle *rectangle) +{ + g_return_if_fail (params); + + if (rectangle) + { + params->has_attach_rect = TRUE; + params->attach_rect = *rectangle; + } + else + params->has_attach_rect = FALSE; +} + +/** + * gdk_attach_params_set_attach_margin: + * @params: a #GdkAttachParams + * @margin: (nullable): the space around the attachment rectangle + * + * Sets the amount of space to leave around the attachment rectangle. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_attach_margin (GdkAttachParams *params, + const GdkBorder *margin) +{ + GdkBorder zero = { 0 }; + + g_return_if_fail (params); + + params->attach_margin = margin ? *margin : zero; +} + +/** + * gdk_attach_params_set_window_margin: + * @params: a #GdkAttachParams + * @margin: (nullable): the space around the window + * + * Sets the amount of space to leave around the window. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_window_margin (GdkAttachParams *params, + const GdkBorder *margin) +{ + GdkBorder zero = { 0 }; + + g_return_if_fail (params); + + params->window_margin = margin ? *margin : zero; +} + +/** + * gdk_attach_params_set_window_padding: + * @params: a #GdkAttachParams + * @padding: (nullable): the space between the window and its + * contents. + * + * Sets the amount of space between the window and its contents. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_window_padding (GdkAttachParams *params, + const GdkBorder *padding) +{ + GdkBorder zero = { 0 }; + + g_return_if_fail (params); + + params->window_padding = padding ? *padding : zero; +} + +/** + * gdk_attach_params_set_window_offset: + * @params: a #GdkAttachParams + * @x: horizontal displacement + * @y: vertical displacement + * + * Sets the offset to displace the window by. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_window_offset (GdkAttachParams *params, + gint x, + gint y) +{ + g_return_if_fail (params); + + params->offset_x = x; + params->offset_y = y; +} + +static void +add_rules (GArray *array, + GdkAttachRule first_rule, + va_list args) +{ + GdkAttachRule rule; + + for (rule = first_rule; rule; rule = va_arg (args, GdkAttachRule)) + g_array_append_val (array, rule); +} + +/** + * gdk_attach_params_add_primary_rules_valist: + * @params: a #GdkAttachParams + * @first_rule: first primary rule + * @args: a #va_list of the remaining primary rules + * + * Non-variadic version of gdk_attach_params_add_primary_rules(). + * + * Since: 3.20 + */ +void +gdk_attach_params_add_primary_rules_valist (GdkAttachParams *params, + GdkAttachRule first_rule, + va_list args) +{ + add_rules (params->primary_rules, first_rule, args); +} + +/** + * gdk_attach_params_add_secondary_rules_valist: + * @params: a #GdkAttachParams + * @first_rule: first secondary rule + * @args: a #va_list of the remaining secondary rules + * + * Non-variadic version of gdk_attach_params_add_secondary_rules(). + * + * Since: 3.20 + */ +void +gdk_attach_params_add_secondary_rules_valist (GdkAttachParams *params, + GdkAttachRule first_rule, + va_list args) +{ + add_rules (params->secondary_rules, first_rule, args); +} + +/** + * gdk_attach_params_add_primary_rules: + * @params: a #GdkAttachParams + * @first_rule: first primary rule + * @...: a %NULL-terminated list of rules + * + * Appends to the list of primary positioning rules to try. + * + * A typical backend will try each primary rule in the order they're added. If + * a rule can be satisfied, it will then try each secondary rule until it + * finds a satisfiable secondary rule that doesn't conflict with the primary + * rule. If it finds a pair of satisfiable non-conflicting rules, then it will + * place the window there. If it cannot find a pair, it proceeds to the next + * primary rule and tries again. + * + * Since: 3.20 + */ +void +gdk_attach_params_add_primary_rules (GdkAttachParams *params, + GdkAttachRule first_rule, + ...) +{ + va_list args; + + g_return_if_fail (params); + + va_start (args, first_rule); + + gdk_attach_params_add_primary_rules_valist (params, first_rule, args); + + va_end (args); +} + +/** + * gdk_attach_params_add_secondary_rules: + * @params: a #GdkAttachParams + * @first_rule: first secondary rule + * @...: a %NULL-terminated list of rules + * + * Appends to the list of secondary positioning rules to try. + * + * A typical backend will try each primary rule in the order they're added. If + * a rule can be satisfied, it will then try each secondary rule until it + * finds a satisfiable secondary rule that doesn't conflict with the primary + * rule. If it finds a pair of satisfiable non-conflicting rules, then it will + * place the window there. If it cannot find a pair, it proceeds to the next + * primary rule and tries again. + * + * Since: 3.20 + */ +void +gdk_attach_params_add_secondary_rules (GdkAttachParams *params, + GdkAttachRule first_rule, + ...) +{ + va_list args; + + g_return_if_fail (params); + + va_start (args, first_rule); + + gdk_attach_params_add_secondary_rules_valist (params, first_rule, args); + + va_end (args); +} + +static void +rules_foreach (GArray *array, + GFunc func, + gpointer user_data) +{ + gint i; + + for (i = 0; i < array->len; i++) + func (&g_array_index (array, GdkAttachRule, i), user_data); +} + +/** + * gdk_attach_params_primary_rules_foreach: + * @params: a #GdkAttachParams + * @func: the function to call with each primary rule + * @user_data: (nullable): user data to pass to the function + * + * Applies @func to each primary rule in @params. + * + * Since: 3.20 + */ +void +gdk_attach_params_primary_rules_foreach (GdkAttachParams *params, + GFunc func, + gpointer user_data) +{ + g_return_if_fail (params); + g_return_if_fail (func); + + rules_foreach (params->primary_rules, func, user_data); +} + +/** + * gdk_attach_params_secondary_rules_foreach: + * @params: a #GdkAttachParams + * @func: the function to call with each secondary rule + * @user_data: (nullable): user data to pass to the function + * + * Applies @func to each secondary rule in @params. + * + * Since: 3.20 + */ +void +gdk_attach_params_secondary_rules_foreach (GdkAttachParams *params, + GFunc func, + gpointer user_data) +{ + g_return_if_fail (params); + g_return_if_fail (func); + + rules_foreach (params->secondary_rules, func, user_data); +} + +/** + * gdk_attach_params_set_position_callback: + * @params: a #GdkAttachParams + * @callback: (nullable): a function to be called when the final position of + * the window is known + * @user_data: (transfer full) (nullable): additional data to pass to @callback + * @destroy_notify: (nullable): a function to release @user_data + * + * Sets the function to be called when the final position of the window is + * known. + * + * Since: 3.20 + */ +void +gdk_attach_params_set_position_callback (GdkAttachParams *params, + GdkAttachCallback callback, + gpointer user_data, + GDestroyNotify destroy_notify) +{ + g_return_if_fail (params); + + params->attach_callback = callback; + + if (user_data != params->attach_user_data) + { + if (params->attach_user_data && params->attach_destroy_notify) + params->attach_destroy_notify (params->attach_user_data); + + params->attach_user_data = user_data; + params->attach_destroy_notify = destroy_notify; + } + else if (user_data) + g_warning ("%s (): params already owns user data", G_STRFUNC); +} + +static gboolean +is_satisfiable (GdkAttachRule rule, + const GdkAttachParams *params, + gint width, + gint height, + const GdkRectangle *bounds, + gint *value) +{ + gboolean use_rect_margin; + gboolean use_window_margin; + gboolean use_window_padding; + + g_return_val_if_fail (params, FALSE); + g_return_val_if_fail (params->has_attach_rect, FALSE); + + use_rect_margin = (((rule & GDK_ATTACH_RECT_MASK) == GDK_ATTACH_RECT_MIN && + (rule & GDK_ATTACH_WINDOW_MASK) == GDK_ATTACH_WINDOW_MAX) || + ((rule & GDK_ATTACH_RECT_MASK) == GDK_ATTACH_RECT_MAX && + (rule & GDK_ATTACH_WINDOW_MASK) == GDK_ATTACH_WINDOW_MIN)); + + use_window_margin = use_rect_margin; + + use_window_padding = TRUE; + + switch (rule & GDK_ATTACH_AXIS_MASK) + { + case GDK_ATTACH_AXIS_X: + *value = params->origin_x; + + switch (rule & GDK_ATTACH_RECT_MASK) + { + case GDK_ATTACH_RECT_MIN: + *value += params->attach_rect.x; + + if (use_rect_margin) + *value -= params->attach_margin.left; + + break; + + case GDK_ATTACH_RECT_MID: + *value += params->attach_rect.x + params->attach_rect.width / 2; + break; + + case GDK_ATTACH_RECT_MAX: + *value += params->attach_rect.x + params->attach_rect.width; + + if (use_rect_margin) + *value += params->attach_margin.right; + + break; + } + + switch (rule & GDK_ATTACH_WINDOW_MASK) + { + case GDK_ATTACH_WINDOW_MIN: + if (use_window_margin) + *value += params->window_margin.left; + + if (use_window_padding) + *value -= params->window_margin.left; + + break; + + case GDK_ATTACH_WINDOW_MID: + *value -= width / 2; + break; + + case GDK_ATTACH_WINDOW_MAX: + *value -= width; + + if (use_window_margin) + *value -= params->window_margin.right; + + if (use_window_padding) + *value += params->window_margin.right; + + break; + } + + *value += params->offset_x; + + return !bounds || (bounds->x <= *value && *value + width <= bounds->x + bounds->width); + + case GDK_ATTACH_AXIS_Y: + *value = params->origin_y; + + switch (rule & GDK_ATTACH_RECT_MASK) + { + case GDK_ATTACH_RECT_MIN: + *value += params->attach_rect.y; + + if (use_rect_margin) + *value -= params->attach_margin.top; + + break; + + case GDK_ATTACH_RECT_MID: + *value += params->attach_rect.y + params->attach_rect.height / 2; + break; + + case GDK_ATTACH_RECT_MAX: + *value += params->attach_rect.y + params->attach_rect.height; + + if (use_rect_margin) + *value += params->attach_margin.bottom; + + break; + } + + switch (rule & GDK_ATTACH_WINDOW_MASK) + { + case GDK_ATTACH_WINDOW_MIN: + if (use_window_margin) + *value += params->window_margin.top; + + if (use_window_padding) + *value -= params->window_margin.top; + + break; + + case GDK_ATTACH_WINDOW_MID: + *value -= height / 2; + break; + + case GDK_ATTACH_WINDOW_MAX: + *value -= height; + + if (use_window_margin) + *value -= params->window_margin.bottom; + + if (use_window_padding) + *value += params->window_margin.bottom; + + break; + } + + *value += params->offset_y; + + return !bounds || (bounds->y <= *value && *value + height <= bounds->y + bounds->height); + } + + return FALSE; +} + +#define BEST 0 +#define GOOD 1 +#define PRIMARY 0 +#define SECONDARY 1 +#define X 0 +#define Y 1 + +/** + * gdk_attach_params_choose_position: + * @params: a #GdkAttachParams + * @width: window width + * @height: window height + * @bounds: (nullable): monitor geometry + * @x: (out) (optional): the best x-coordinate for the window + * @y: (out) (optional): the best y-coordinate for the window + * @offset_x: (out) (optional): the horizontal displacement needed to push the + * window on-screen + * @offset_y: (out) (optional): the vertical displacement needed to push the + * window on-screen + * @primary_rule: (out) (optional): the best primary rule + * @secondary_rule: (out) (optional): the best secondary rule + * + * Finds the best position for a window of size @width and @height on a screen + * with @bounds using the given @params. + * + * Returns: %TRUE if there is a pair of satisfiable primary and secondary + * rules that do not conflict with each other + * + * Since: 3.20 + */ +gboolean +gdk_attach_params_choose_position (const GdkAttachParams *params, + gint width, + gint height, + const GdkRectangle *bounds, + gint *x, + gint *y, + gint *offset_x, + gint *offset_y, + GdkAttachRule *primary_rule, + GdkAttachRule *secondary_rule) +{ + gint tmp_x; + gint tmp_y; + gint tmp_offset_x; + gint tmp_offset_y; + GdkAttachRule pr; + GdkAttachRule sr; + GdkAttachRule rules[2][2][2] = { 0 }; + gint axes[2][2] = { 0 }; + gint values[2][2][2] = { 0 }; + GArray *arrays[2]; + gint i; + gint j; + gint k; + GdkAttachRule rule; + gint axis; + gint value; + gboolean satisfiable; + gboolean success; + + g_return_val_if_fail (params, FALSE); + g_return_val_if_fail (params->has_attach_rect, FALSE); + + if (!x) + x = &tmp_x; + + if (!y) + y = &tmp_y; + + if (!offset_x) + offset_x = &tmp_offset_x; + + if (!offset_y) + offset_y = &tmp_offset_y; + + if (!primary_rule) + primary_rule = ≺ + + if (!secondary_rule) + secondary_rule = &sr; + + arrays[PRIMARY] = params->primary_rules; + arrays[SECONDARY] = params->secondary_rules; + + for (i = PRIMARY; i <= SECONDARY; i++) + { + for (j = 0; j < arrays[i]->len; j++) + { + rule = g_array_index (arrays[i], GdkAttachRule, j); + + switch (rule & GDK_ATTACH_AXIS_MASK) + { + case GDK_ATTACH_AXIS_X: + axis = X; + break; + + case GDK_ATTACH_AXIS_Y: + axis = Y; + break; + + default: + axis = -1; + break; + } + + if (axis < 0) + { + g_warning ("%s (): invalid constraint axis: 0x%X", G_STRFUNC, rule); + continue; + } + + satisfiable = is_satisfiable (rule, params, width, height, bounds, &value); + + if (satisfiable && !rules[i][BEST][axis]) + { + rules[i][BEST][axis] = rule; + values[i][BEST][axis] = value; + + if (rules[i][BEST][!axis]) + break; + else + axes[i][BEST] = axis; + } + else if (!rules[i][GOOD][axis]) + { + rules[i][GOOD][axis] = rule; + values[i][GOOD][axis] = value; + + if (!rules[i][GOOD][!axis]) + axes[i][GOOD] = axis; + } + } + } + + success = FALSE; + + for (i = BEST; i <= GOOD; i++) + { + for (j = BEST; j <= GOOD; j++) + { + for (k = Y; k >= X; k--) + { + if (rules[PRIMARY][i][axes[PRIMARY][i] == k] && rules[SECONDARY][j][axes[PRIMARY][i] != k]) + { + *primary_rule = rules[PRIMARY][i][axes[PRIMARY][i] == k]; + *secondary_rule = rules[SECONDARY][j][axes[PRIMARY][i] != k]; + + if ((axes[PRIMARY][i] == k) == X) + { + *x = values[PRIMARY][i][X]; + *y = values[SECONDARY][j][Y]; + } + else + { + *x = values[SECONDARY][j][X]; + *y = values[PRIMARY][i][Y]; + } + + *offset_x = 0; + *offset_y = 0; + success = TRUE; + break; + } + } + + if (success) + break; + } + + if (success) + break; + } + + if (success && bounds) + { + if (*x + width > bounds->x + bounds->width) + { + *offset_x += bounds->x + bounds->width - width - *x; + *x = bounds->x + bounds->width - width; + } + + if (*x < bounds->x) + { + *offset_x += bounds->x - *x; + *x = bounds->x; + } + + if (*y + height > bounds->y + bounds->height) + { + *offset_y += bounds->y + bounds->height - height - *y; + *y = bounds->y + bounds->height - height; + } + + if (*y < bounds->y) + { + *offset_y += bounds->y - *y; + *y = bounds->y; + } + } + + return success; +} + +/** + * gdk_attach_params_choose_position_for_window: + * @params: a #GdkAttachParams + * @window: (transfer none) (not nullable): the #GdkWindow to find the best + * position for + * @x: (out) (optional): the best x-coordinate for the window + * @y: (out) (optional): the best y-coordinate for the window + * @offset_x: (out) (optional): the horizontal displacement needed to push the + * window on-screen + * @offset_y: (out) (optional): the vertical displacement needed to push the + * window on-screen + * @primary_rule: (out) (optional): the best primary rule + * @secondary_rule: (out) (optional): the best secondary rule + * + * Finds the best position for @window according to @params. + * + * Returns: %TRUE if there's a best position + * + * Since: 3.20 + */ +gboolean +gdk_attach_params_choose_position_for_window (const GdkAttachParams *params, + GdkWindow *window, + gint *x, + gint *y, + gint *offset_x, + gint *offset_y, + GdkAttachRule *primary_rule, + GdkAttachRule *secondary_rule) +{ + GdkScreen *screen; + gint center_x; + gint center_y; + gint monitor; + GdkRectangle bounds; + gint width; + gint height; + + g_return_val_if_fail (params, FALSE); + g_return_val_if_fail (params->has_attach_rect, FALSE); + g_return_val_if_fail (window, FALSE); + + screen = gdk_window_get_screen (window); + center_x = params->origin_x + params->attach_rect.x + params->attach_rect.width / 2; + center_y = params->origin_y + params->attach_rect.y + params->attach_rect.height / 2; + monitor = gdk_screen_get_monitor_at_point (screen, center_x, center_y); + gdk_screen_get_monitor_workarea (screen, monitor, &bounds); + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); + + return gdk_attach_params_choose_position (params, + width, + height, + &bounds, + x, + y, + offset_x, + offset_y, + primary_rule, + secondary_rule); +} + +/** + * gdk_attach_params_move_window: + * @params: a #GdkAttachParams + * @window: (transfer none) (not nullable): the #GdkWindow to position + * + * Moves @window to the best position according to @params. + * + * Since: 3.20 + */ +void +gdk_attach_params_move_window (const GdkAttachParams *params, + GdkWindow *window) +{ + gint x; + gint y; + gint offset_x; + gint offset_y; + GdkAttachRule primary_rule; + GdkAttachRule secondary_rule; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (!params || !params->has_attach_rect) + return; + + if (gdk_attach_params_choose_position_for_window (params, + window, + &x, + &y, + &offset_x, + &offset_y, + &primary_rule, + &secondary_rule)) + { + gdk_window_move (window, x, y); + + if (params->attach_callback) + params->attach_callback (window, + params, + x, + y, + offset_x, + offset_y, + primary_rule, + secondary_rule, + params->attach_user_data); + } +} diff --git a/gdk/gdkattachparams.h b/gdk/gdkattachparams.h new file mode 100644 index 0000000000..e7b2878813 --- /dev/null +++ b/gdk/gdkattachparams.h @@ -0,0 +1,165 @@ +#ifndef __GDK_ATTACH_PARAMS_H__ +#define __GDK_ATTACH_PARAMS_H__ + +#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION) +#error "Only <gdk/gdk.h> can be included directly." +#endif + +#include <gdk/gdktypes.h> +#include <gdk/gdkversionmacros.h> + +G_BEGIN_DECLS + +/** + * GdkAttachRule: + * @GDK_ATTACH_UNKNOWN: not a constraint + * @GDK_ATTACH_AXIS_X: constrain horizontally + * @GDK_ATTACH_AXIS_Y: constrain vertically + * @GDK_ATTACH_AXIS_MASK: mask for constraint axis + * @GDK_ATTACH_RECT_MIN: left/top edge of rectangle + * @GDK_ATTACH_RECT_MID: center of rectangle + * @GDK_ATTACH_RECT_MAX: right/bottom edge of rectangle + * @GDK_ATTACH_RECT_MASK: mask for rectangle anchor + * @GDK_ATTACH_WINDOW_MIN: left/top edge of window + * @GDK_ATTACH_WINDOW_MID: center of window + * @GDK_ATTACH_WINDOW_MAX: right/bottom edge of window + * @GDK_ATTACH_WINDOW_MASK: mask for window anchor + * + * Constraints on the position of the window relative to its attachment + * rectangle. + * + * ![](gdkattachrule.png) + * + * Since: 3.20 + */ +typedef enum _GdkAttachRule +{ + GDK_ATTACH_UNKNOWN = 0, + GDK_ATTACH_AXIS_X = 1 << 0, + GDK_ATTACH_AXIS_Y = 1 << 1, + GDK_ATTACH_AXIS_MASK = GDK_ATTACH_AXIS_X | GDK_ATTACH_AXIS_Y, + GDK_ATTACH_RECT_MIN = 1 << 2, + GDK_ATTACH_RECT_MID = 2 << 2, + GDK_ATTACH_RECT_MAX = 3 << 2, + GDK_ATTACH_RECT_MASK = GDK_ATTACH_RECT_MIN | GDK_ATTACH_RECT_MID | GDK_ATTACH_RECT_MAX, + GDK_ATTACH_WINDOW_MIN = 1 << 4, + GDK_ATTACH_WINDOW_MID = 2 << 4, + GDK_ATTACH_WINDOW_MAX = 3 << 4, + GDK_ATTACH_WINDOW_MASK = GDK_ATTACH_WINDOW_MIN | GDK_ATTACH_WINDOW_MID | GDK_ATTACH_WINDOW_MAX +} GdkAttachRule; + +/** + * GdkAttachParams: + * + * Opaque type containing the information needed to position a window relative + * to an attachment rectangle. + * + * Since: 3.20 + */ +typedef struct _GdkAttachParams GdkAttachParams; + +/** + * GdkAttachCallback: + * @window: the #GdkWindow that was moved + * @params: (transfer none) (nullable): the #GdkAttachParams that was used + * @x: the final x-coordinate of @window + * @y: the final y-coordinate of @window + * @offset_x: the horizontal displacement applied to keep @window on-screen + * @offset_y: the vertical displacement applied to keep @window on-screen + * @primary_rule: the primary rule that was used for positioning. If unknown, + * this will be %GDK_ATTACH_UNKNOWN + * @secondary_rule: the secondary rule that was used for positioning. If + * unknown, this will be %GDK_ATTACH_UNKNOWN + * @user_data: (transfer none) (nullable): the user data that was set on + * @params + * + * A function that can be used to receive information about the final position + * of a window. + * + * Since: 3.20 + */ +typedef void (*GdkAttachCallback) (GdkWindow *window, + const GdkAttachParams *params, + gint x, + gint y, + gint offset_x, + gint offset_y, + GdkAttachRule primary_rule, + GdkAttachRule secondary_rule, + gpointer user_data); + +GDK_AVAILABLE_IN_3_20 +GdkAttachParams * gdk_attach_params_new (void); + +GDK_AVAILABLE_IN_3_20 +gpointer gdk_attach_params_copy (gconstpointer src, + gpointer data); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_free (gpointer data); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_attach_origin (GdkAttachParams *params, + gint x, + gint y); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_attach_rect (GdkAttachParams *params, + const GdkRectangle *rectangle); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_attach_margin (GdkAttachParams *params, + const GdkBorder *margin); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_window_margin (GdkAttachParams *params, + const GdkBorder *margin); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_window_padding (GdkAttachParams *params, + const GdkBorder *padding); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_window_offset (GdkAttachParams *params, + gint x, + gint y); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_add_primary_rules_valist (GdkAttachParams *params, + GdkAttachRule first_rule, + va_list args); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_add_secondary_rules_valist (GdkAttachParams *params, + GdkAttachRule first_rule, + va_list args); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_add_primary_rules (GdkAttachParams *params, + GdkAttachRule first_rule, + ...) G_GNUC_NULL_TERMINATED; + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_add_secondary_rules (GdkAttachParams *params, + GdkAttachRule first_rule, + ...) G_GNUC_NULL_TERMINATED; + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_primary_rules_foreach (GdkAttachParams *params, + GFunc func, + gpointer user_data); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_secondary_rules_foreach (GdkAttachParams *params, + GFunc func, + gpointer user_data); + +GDK_AVAILABLE_IN_3_20 +void gdk_attach_params_set_position_callback (GdkAttachParams *params, + GdkAttachCallback callback, + gpointer user_data, + GDestroyNotify destroy_notify); + +G_END_DECLS + +#endif /* __GDK_ATTACH_PARAMS_H__ */ diff --git a/gdk/gdkattachparamsprivate.h b/gdk/gdkattachparamsprivate.h new file mode 100644 index 0000000000..f82d2251c7 --- /dev/null +++ b/gdk/gdkattachparamsprivate.h @@ -0,0 +1,83 @@ +#ifndef __GDK_ATTACH_PARAMS_PRIVATE_H__ +#define __GDK_ATTACH_PARAMS_PRIVATE_H__ + +#include "gdkattachparams.h" + +G_BEGIN_DECLS + +/* + * GdkAttachParams: + * @origin_x: x-coordinate of root origin of @attach_rect coordinate system + * @origin_y: y-coordinate of root origin of @attach_rect coordinate system + * @has_attach_rect: %TRUE if @attach_rect is valid + * @attach_rect: the attachment rectangle to attach the window to + * @attach_margin: the space to leave around @attach_rect + * @window_margin: the space to leave around the window + * @window_padding: the space between the window and its contents + * @offset_x: the horizontal offset to displace the window by + * @offset_y: the vertical offset to displace the window by + * @primary_rules: an array of primary #GdkAttachRule + * @secondary_rules: an array of secondary #GdkAttachRule + * @position_callback: a function to call when the final position is known + * @position_callback_user_data: additional data to pass to @position_callback + * @position_callback_destroy_notify: a function to free + * @position_callback_user_data + * + * Opaque type containing the information needed to position a window relative + * to an attachment rectangle. + * + * Since: 3.20 + */ +struct _GdkAttachParams +{ + /*< private >*/ + gint origin_x; + gint origin_y; + + gboolean has_attach_rect; + GdkRectangle attach_rect; + + GdkBorder attach_margin; + GdkBorder window_margin; + GdkBorder window_padding; + + gint offset_x; + gint offset_y; + + GArray *primary_rules; + GArray *secondary_rules; + + GdkAttachCallback attach_callback; + gpointer attach_user_data; + GDestroyNotify attach_destroy_notify; +}; + +G_GNUC_INTERNAL +gboolean gdk_attach_params_choose_position (const GdkAttachParams *params, + gint width, + gint height, + const GdkRectangle *bounds, + gint *x, + gint *y, + gint *offset_x, + gint *offset_y, + GdkAttachRule *primary_rule, + GdkAttachRule *secondary_rule); + +G_GNUC_INTERNAL +gboolean gdk_attach_params_choose_position_for_window (const GdkAttachParams *params, + GdkWindow *window, + gint *x, + gint *y, + gint *offset_x, + gint *offset_y, + GdkAttachRule *primary_rule, + GdkAttachRule *secondary_rule); + +G_GNUC_INTERNAL +void gdk_attach_params_move_window (const GdkAttachParams *params, + GdkWindow *window); + +G_END_DECLS + +#endif /* __GDK_ATTACH_PARAMS_PRIVATE_H__ */ |