Merge lp:~smspillaz/compiz-core/compiz-core.lim into lp:compiz-core

Proposed by Sam Spilsbury
Status: Merged
Merged at revision: 3036
Proposed branch: lp:~smspillaz/compiz-core/compiz-core.lim
Merge into: lp:compiz-core
Diff against target: 1601 lines (+1218/-11)
16 files modified
gtk/window-decorator/CMakeLists.txt (+6/-0)
gtk/window-decorator/decorator.c (+32/-6)
gtk/window-decorator/events.c (+117/-3)
gtk/window-decorator/gtk-window-decorator.c (+59/-0)
gtk/window-decorator/gtk-window-decorator.h (+8/-1)
gtk/window-decorator/local-menus/CMakeLists.txt (+60/-0)
gtk/window-decorator/local-menus/src/local-menus.c (+438/-0)
gtk/window-decorator/local-menus/src/local-menus.h (+125/-0)
gtk/window-decorator/local-menus/tests/CMakeLists.txt (+3/-0)
gtk/window-decorator/local-menus/tests/check_local_menu_on_off/CMakeLists.txt (+21/-0)
gtk/window-decorator/local-menus/tests/check_local_menu_on_off/test-local-menu-on-off.cpp (+47/-0)
gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeLists.txt (+21/-0)
gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp (+89/-0)
gtk/window-decorator/local-menus/tests/test-local-menu.h (+106/-0)
gtk/window-decorator/metacity.c (+54/-0)
gtk/window-decorator/wnck.c (+32/-1)
To merge this branch: bzr merge lp:~smspillaz/compiz-core/compiz-core.lim
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Alan Griffiths Approve
Marco Trevisan (Treviño) Approve
Sam Spilsbury Pending
Review via email: mp+94891@code.launchpad.net

This proposal supersedes a proposal from 2012-02-25.

Description of the change

Adds support for Ubuntu's "locally integrated menu bars" into gtk-window-decorator.

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

8 +#define GWD_SHOW_LOCAL_MENU (WNCK_WINDOW_ACTION_BELOW << 1)

No plausible reason for using a macro. In C++ constants (enum or unsigned int) are better as they respect scope rules. Also, should this be inside "#ifdef META_HAS_LOCAL_MENUS" conditional?

296 button_layout->right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
297
298 - for (i = 3; i < MAX_BUTTONS_PER_CORNER; i++)
299 + for (i = 4; i < MAX_BUTTONS_PER_CORNER; i++)
300 button_layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
301 }

I'm not sure what the magic number "3"->"4" is. But we now seem to miss 3 entirely. Is that correct?

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> 8 +#define GWD_SHOW_LOCAL_MENU (WNCK_WINDOW_ACTION_BELOW << 1)
>
> No plausible reason for using a macro. In C++ constants (enum or unsigned
> int) are better as they respect scope rules. Also, should this be inside
> "#ifdef META_HAS_LOCAL_MENUS" conditional?
>

Its C

>
> 296 button_layout->right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
> 297
> 298 - for (i = 3; i < MAX_BUTTONS_PER_CORNER; i++)
> 299 + for (i = 4; i < MAX_BUTTONS_PER_CORNER; i++)
> 300 button_layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
> 301 }
>
> I'm not sure what the magic number "3"->"4" is. But we now seem to miss 3
> entirely. Is that correct?

Its for initializing the array, though maybe thats wrong. Good find let me check

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Please resubmit for target branch lp:compiz-core (0.9.7)

review: Needs Resubmitting
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Looks better

review: Approve
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

(More work needed to adopt to trevino;s changes)

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Fails to build ifndef META_HAS_LOCAL_MENUS

[ 0%] Building C object gtk/window-decorator/local-menus/CMakeFiles/gtk_window_decorator_local_menus.dir/src/local-menus.c.o
/home/dan/bzr/compiz-core/lim/gtk/window-decorator/local-menus/src/local-menus.c:36:1: error: ‘gwd_menu_mode_changed’ defined but not used [-Werror=unused-function]
/home/dan/bzr/compiz-core/lim/gtk/window-decorator/local-menus/src/local-menus.c:72:1: error: ‘on_local_menu_activated’ defined but not used [-Werror=unused-function]
cc1: all warnings being treated as errors

review: Needs Fixing
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

+ gboolean empty = g_strcmp0 (entry_id, "") == 0;

You can do the same with:
gboolean empty = (!entry_id || entry_id[0] == '\0');

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

If we're trying to be cryptic...

   gboolean empty = g_strcmp0 (entry_id, "") == 0;

can be written:

   gboolean empty = !entry_id || !*entry_id;

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Ah, Sam remember to update the "EntryActivated" signal against the new signature s(iiuu).

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Yep, done

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Fails to build for a whole new reason now :(

Scanning dependencies of target gtk_window_decorator_force_local_menu_on_test
[ 5%] Building CXX object gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeFiles/gtk_window_decorator_force_local_menu_on_test.dir/test-force-local-menu-on.cpp.o
/home/dan/bzr/compiz-core/lim/gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp: In member function ‘virtual void GtkWindowDecoratorTestLocalMenuLayout_TestForceNoCloseButtonSet_Test::TestBody()’:
/home/dan/bzr/compiz-core/lim/gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp:56:5: error: ‘META_BUTTON_FUNCTION_WINDOW_MENU’ was not declared in this scope
/home/dan/bzr/compiz-core/lim/gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp: In member function ‘virtual void GtkWindowDecoratorTestLocalMenuLayout_TestForceNoCloseMinimizeMaximizeButtonSet_Test::TestBody()’:
/home/dan/bzr/compiz-core/lim/gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp:69:5: error: ‘META_BUTTON_FUNCTION_WINDOW_MENU’ was not declared in this scope
make[2]: *** [gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeFiles/gtk_window_decorator_force_local_menu_on_test.dir/test-force-local-menu-on.cpp.o] Error 1
make[1]: *** [gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeFiles/gtk_window_decorator_force_local_menu_on_test.dir/all] Error 2
make: *** [all] Error 2

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Tests needed to be disabled on META_HAS_LOCAL_MENUS, thanks for catching that.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Test cases fail (crash). Maybe they need to be disabled if local menus are disabled...

The following tests FAILED:
   1 - gtk_window_decorator_local_menus_on_off (SEGFAULT)
   2 - gtk_window_decorator_force_local_menu_on (SEGFAULT)
Errors while running CTest
make: *** [test] Error 8

-----

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff709bb70 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
(gdb) bt
#0 0x00007ffff709bb70 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#1 0x00007ffff709e2f5 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#2 0x00007ffff6dc29f0 in g_object_unref ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#3 0x000000000042ef7d in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ()
#4 0x000000000042751f in testing::Test::Run() ()
#5 0x000000000042763d in testing::TestInfo::Run() ()
#6 0x0000000000427787 in testing::TestCase::Run() ()
#7 0x0000000000427a17 in testing::internal::UnitTestImpl::RunAllTests() ()
#8 0x000000000042eafd in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ()
#9 0x0000000000426c0b in testing::UnitTest::Run() ()
#10 0x0000000000413145 in main ()

-----

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff709bb70 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
(gdb) bt
#0 0x00007ffff709bb70 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#1 0x00007ffff709e2f5 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#2 0x00007ffff6dc29f0 in g_object_unref ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#3 0x000000000042ef7d in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ()
#4 0x000000000042751f in testing::Test::Run() ()
#5 0x000000000042763d in testing::TestInfo::Run() ()
#6 0x0000000000427787 in testing::TestCase::Run() ()
#7 0x0000000000427a17 in testing::internal::UnitTestImpl::RunAllTests() ()
#8 0x000000000042eafd in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ()
#9 0x0000000000426c0b in testing::UnitTest::Run() ()
#10 0x0000000000413145 in main ()

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Huh, that's weird. I've disabled META_HAS_LOCAL_MENUS here, and make sure to link to the system libmetacity-private and the tests are still passing for me.

Can you post the output of the individual tests before it reaches the point where they crash? Or do they just crash without outputting anything ?

(Could be something to do with the SetUp () function, so I'll give that a try

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Confirmed all unit tests now pass and no obvious bugs in manual testing.

I still think we need to be tidier with the CMake syntax as I've mentioned before...

review: Approve
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Yes, one day I'm going to introduce a bunch of functions to the CMake which reduce the verbosity.

Daniel - if you want to test this for realz, you can use the following:

lp:~smspillaz/metacity/metacity.lim
lp:~3v1n0/unity/lim-panel
lp:~indicator-applet-developers/indicator-appmenu/local-menus-single-menu
lp:~smspillaz/light-themes/light-themes.limv4

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Looks OK, Builds OK, automated tests run. (With no META_HAS_LOCAL_MENUS)

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

I've tested it, to be even better, maybe you could also sync the title geometries once you opened/closed the menu, but that can be optional.
One thing you need to fix is the double-click over the title, that currently doesn't work as expected.
Look at the logic I've used in PanelTitlebarGrabArea.

Then I guess we need to define with design better one case: if a window is unfocused, and the user presses over the title / icon, should we just focus it or also open the menu? Currently we do both, but I'm not sure this is the best choice.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Ah, don't care about syncing geometries. You don't need that and could cause problems to the panel... :)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Ah, one more thing. Please check if the window you're decorating has the "_UBUNTU_APPMENU_UNIQUE_NAME" utf8 atom set to check if it has menus.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Ah, I forgot... The decorator is still missing to react to the com.canonical.Unity.Panel.Service.EntryActivateRequest signal, that happens when you do Alt+F on terminal for example... :)

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

OK, I'll take care of these two things too. Thanks.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

No obvious errors

review: Abstain
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Confirmed again all unit tests now pass and no obvious bugs in manual testing.

Though, like Alan, I have not reviewed the theoretical correctness of the code in detail.

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Mostly it works, well.

By the way, I've tested the support for the EntryActivateRequest and even if it's correctly handled if a window is in focus (i.e. pressing Alt+F on the terminal causes the menu to show in the right place), otherwise if you have this scenario: a maximized window in focus, and a restored window unfocused, when pressing Alt+F (or something, that will be managed by the focused window) gtk-window-decorator crashes.

This is the stacktrace I have: http://paste.ubuntu.com/859831/
Actually you should just ignore that signal if no decorated window is in focus.

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Ack.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Crash fixed, it looks good to me now.

Unfortunately not all the apps yet supports the _UBUNTU_APPMENU_UNIQUE_NAME atom... So maybe for testing it could be temporary disabled (sorry). A temporary workaround could be this one: http://is.gd/IXPV4h

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) :
review: Approve
3003. By Sam Spilsbury

Tell us if we have them

Revision history for this message
Alan Griffiths (alan-griffiths) :
review: Approve
3004. By Sam Spilsbury

Merged lp:compiz-core

3005. By Sam Spilsbury

We also need to test the property too

3006. By Sam Spilsbury

Grab buttons too so that we can process motion events on the titlebar and
move the window instead.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

No obvious problems or regressions. And Valgrind is happy.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'gtk/window-decorator/CMakeLists.txt'
--- gtk/window-decorator/CMakeLists.txt 2011-02-16 17:39:56 +0000
+++ gtk/window-decorator/CMakeLists.txt 2012-03-02 02:56:17 +0000
@@ -4,7 +4,10 @@
4 set (CMAKE_INSTALL_RPATH ${libdir})4 set (CMAKE_INSTALL_RPATH ${libdir})
5 endif (COMPIZ_BUILD_WITH_RPATH)5 endif (COMPIZ_BUILD_WITH_RPATH)
66
7 add_subdirectory (local-menus)
8
7 include_directories (9 include_directories (
10 ${CMAKE_CURRENT_SOURCE_DIR}/local-menus/src
8 ${compiz_SOURCE_DIR}/include11 ${compiz_SOURCE_DIR}/include
9 ${CMAKE_BINARY_DIR}/gtk12 ${CMAKE_BINARY_DIR}/gtk
10 ${GTK_WINDOW_DECORATOR_INCLUDE_DIRS}13 ${GTK_WINDOW_DECORATOR_INCLUDE_DIRS}
@@ -63,6 +66,9 @@
63 target_link_libraries (66 target_link_libraries (
64 gtk-window-decorator67 gtk-window-decorator
65 decoration68 decoration
69
70 gtk_window_decorator_local_menus
71
66 ${GTK_WINDOW_DECORATOR_LIBRARIES}72 ${GTK_WINDOW_DECORATOR_LIBRARIES}
67 ${GCONF_LIBRARIES}73 ${GCONF_LIBRARIES}
68 ${DBUS_GLIB_LIBRARIES}74 ${DBUS_GLIB_LIBRARIES}
6975
=== modified file 'gtk/window-decorator/decorator.c'
--- gtk/window-decorator/decorator.c 2012-02-20 07:42:20 +0000
+++ gtk/window-decorator/decorator.c 2012-03-02 02:56:17 +0000
@@ -24,6 +24,7 @@
24 */24 */
2525
26#include "gtk-window-decorator.h"26#include "gtk-window-decorator.h"
27#include "local-menus.h"
2728
28decor_frame_t *29decor_frame_t *
29create_normal_frame (const gchar *type)30create_normal_frame (const gchar *type)
@@ -230,12 +231,16 @@
230void231void
231update_event_windows (WnckWindow *win)232update_event_windows (WnckWindow *win)
232{233{
234#define GWD_SHOW_LOCAL_MENU (WNCK_WINDOW_ACTION_BELOW << 1)
233 Display *xdisplay;235 Display *xdisplay;
234 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");236 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
235 gint x0, y0, width, height, x, y, w, h;237 gint x0, y0, width, height, x, y, w, h;
236 gint i, j, k, l;238 gint i, j, k, l;
237 gint actions = d->actions;239 gint actions = d->actions;
238240
241 if (gwd_window_should_have_local_menu (win ? wnck_window_get_xid (win) : 0))
242 actions |= GWD_SHOW_LOCAL_MENU;
243
239 xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());244 xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
240245
241 /* Get the geometry of the client */246 /* Get the geometry of the client */
@@ -298,11 +303,19 @@
298 XMapWindow (xdisplay, d->event_windows[i][j].window);303 XMapWindow (xdisplay, d->event_windows[i][j].window);
299 XMoveResizeWindow (xdisplay, d->event_windows[i][j].window,304 XMoveResizeWindow (xdisplay, d->event_windows[i][j].window,
300 x, y, w, h);305 x, y, w, h);
306
307 BoxPtr box = &d->event_windows[i][j].pos;
308 box->x1 = x;
309 box->x2 = x + w;
310 box->y1 = y;
311 box->y2 = y + h;
301 }312 }
302 /* No parent and no geometry - unmap all event windows */313 /* No parent and no geometry - unmap all event windows */
303 else if (!d->frame_window)314 else if (!d->frame_window)
304 {315 {
305 XUnmapWindow (xdisplay, d->event_windows[i][j].window);316 XUnmapWindow (xdisplay, d->event_windows[i][j].window);
317
318 memset (&d->event_windows[i][j].pos, 0, sizeof (Box));
306 }319 }
307 }320 }
308 }321 }
@@ -326,12 +339,18 @@
326 WNCK_WINDOW_ACTION_STICK,339 WNCK_WINDOW_ACTION_STICK,
327 WNCK_WINDOW_ACTION_UNSHADE,340 WNCK_WINDOW_ACTION_UNSHADE,
328 WNCK_WINDOW_ACTION_ABOVE,341 WNCK_WINDOW_ACTION_ABOVE,
329 WNCK_WINDOW_ACTION_UNSTICK342 WNCK_WINDOW_ACTION_UNSTICK,
330#else343#else
331 0,344 0,
332 0,345 0,
333 0,346 0,
334 0,347 0,
348 0,
349#endif
350
351#ifdef META_HAS_LOCAL_MENUS
352 GWD_SHOW_LOCAL_MENU
353#else
335 0354 0
336#endif355#endif
337356
@@ -371,10 +390,17 @@
371 Window win = d->button_windows[i].window;390 Window win = d->button_windows[i].window;
372 XMapWindow (xdisplay, win);391 XMapWindow (xdisplay, win);
373 XMoveResizeWindow (xdisplay, win, x, y, w, h);392 XMoveResizeWindow (xdisplay, win, x, y, w, h);
393
394 BoxPtr box = &d->button_windows[i].pos;
395 box->x1 = x;
396 box->x2 = x + w;
397 box->y1 = y;
398 box->y2 = y + h;
374 }399 }
375 else if (!d->frame_window)400 else if (!d->frame_window)
376 {401 {
377 XUnmapWindow (xdisplay, d->button_windows[i].window);402 XUnmapWindow (xdisplay, d->button_windows[i].window);
403 memset (&d->button_windows[i].pos, 0, sizeof (Box));
378 }404 }
379 }405 }
380406
381407
=== modified file 'gtk/window-decorator/events.c'
--- gtk/window-decorator/events.c 2012-02-20 07:46:35 +0000
+++ gtk/window-decorator/events.c 2012-03-02 02:56:17 +0000
@@ -24,6 +24,16 @@
24 */24 */
2525
26#include "gtk-window-decorator.h" 26#include "gtk-window-decorator.h"
27#include "local-menus.h"
28
29typedef struct _delayed_move_info
30{
31 WnckWindow *win;
32 int x_root;
33 int y_root;
34 unsigned int button;
35 unsigned int time;
36} delayed_move_info;
2737
28void38void
29move_resize_window (WnckWindow *win,39move_resize_window (WnckWindow *win,
@@ -65,8 +75,9 @@
65 ev.xclient.data.l[3] = gtkwd_event->button;75 ev.xclient.data.l[3] = gtkwd_event->button;
66 ev.xclient.data.l[4] = 1;76 ev.xclient.data.l[4] = 1;
6777
68 XUngrabPointer (xdisplay, gtkwd_event->time);78 XAllowEvents (xdisplay, AsyncKeyboard | AsyncPointer, CurrentTime);
69 XUngrabKeyboard (xdisplay, gtkwd_event->time);79 XUngrabPointer (xdisplay, CurrentTime);
80 XUngrabKeyboard (xdisplay, CurrentTime);
7081
71 XSendEvent (xdisplay, xroot, FALSE,82 XSendEvent (xdisplay, xroot, FALSE,
72 SubstructureRedirectMask | SubstructureNotifyMask,83 SubstructureRedirectMask | SubstructureNotifyMask,
@@ -75,6 +86,24 @@
75 XSync (xdisplay, FALSE);86 XSync (xdisplay, FALSE);
76}87}
7788
89static gboolean
90move_resize_window_on_timeout (gpointer user_data)
91{
92 delayed_move_info *info = (delayed_move_info *) user_data;
93
94 decor_event event;
95 event.x = 0;
96 event.y = 0;
97 event.x_root = info->x_root;
98 event.y_root = info->y_root;
99 event.button = info->button;
100 event.window = wnck_window_get_xid (info->win);
101
102 move_resize_window (info->win, WM_MOVERESIZE_MOVE, &event);
103
104 return FALSE;
105}
106
78void107void
79common_button_event (WnckWindow *win,108common_button_event (WnckWindow *win,
80 decor_event *gtkwd_event,109 decor_event *gtkwd_event,
@@ -380,6 +409,75 @@
380}409}
381410
382void411void
412on_local_menu_hidden (gpointer user_data)
413{
414 Window xid = GPOINTER_TO_INT (user_data);
415 WnckWindow *win = wnck_window_get (xid);
416 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
417
418 d->button_states[BUTTON_WINDOW_MENU] &= ~PRESSED_EVENT_WINDOW;
419
420 queue_decor_draw (d);
421}
422
423void
424window_menu_button_event (WnckWindow *win,
425 decor_event *gtkwd_event,
426 decor_event_type gtkwd_type)
427{
428 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
429 guint state = d->button_states[BUTTON_WINDOW_MENU];
430
431 common_button_event (win, gtkwd_event, gtkwd_type,
432 BUTTON_WINDOW_MENU, 1, _("Window Menu"));
433
434 switch (gtkwd_type) {
435 case GButtonPress:
436 if (gtkwd_event->button == 1)
437 {
438 if (d->button_states[BUTTON_WINDOW_MENU] & BUTTON_EVENT_ACTION_STATE)
439 {
440 delayed_move_info *info = g_new0 (delayed_move_info, 1);
441
442 info->button = gtkwd_event->button;
443 info->time = gtkwd_event->time;
444 info->win = win;
445 info->x_root = gtkwd_event->x_root;
446 info->y_root = gtkwd_event->y_root;
447
448 gwd_prepare_show_local_menu ((start_move_window_cb) move_resize_window_on_timeout, (gpointer) info, info->x_root, info->y_root);
449 }
450 }
451 break;
452 case GButtonRelease:
453 if (gtkwd_event->button == 1)
454 if (state)
455 {
456 int win_x, win_y;
457 int box_x = d->button_windows[BUTTON_WINDOW_MENU].pos.x1;
458
459 wnck_window_get_geometry (win, &win_x, &win_y, NULL, NULL);
460
461 int x = win_x + box_x;
462 int y = win_y + d->context->extents.top;
463
464 gwd_show_local_menu (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
465 wnck_window_get_xid (win),
466 x, y,
467 box_x,
468 d->context->extents.top,
469 gtkwd_event->button,
470 gtkwd_event->time,
471 (show_window_menu_hidden_cb) on_local_menu_hidden,
472 GINT_TO_POINTER (wnck_window_get_xid (d->win)));
473 }
474 break;
475 default:
476 break;
477 }
478}
479
480void
383handle_title_button_event (WnckWindow *win,481handle_title_button_event (WnckWindow *win,
384 int action,482 int action,
385 decor_event *gtkwd_event)483 decor_event *gtkwd_event)
@@ -485,7 +583,17 @@
485583
486 restack_window (win, Above);584 restack_window (win, Above);
487585
488 move_resize_window (win, WM_MOVERESIZE_MOVE, gtkwd_event);586 delayed_move_info *info = g_new0 (delayed_move_info, 1);
587
588 info->x_root = gtkwd_event->x_root;
589 info->y_root = gtkwd_event->y_root;
590 info->button = gtkwd_event->button;
591 info->time = gtkwd_event->time;
592 info->win = win;
593
594 move_resize_window_on_timeout ((gpointer) info);
595
596 g_free (info);
489 }597 }
490 }598 }
491 else if (gtkwd_event->button == 2)599 else if (gtkwd_event->button == 2)
@@ -918,6 +1026,7 @@
918 xid = (gulong)1026 xid = (gulong)
919 g_hash_table_lookup (frame_table,1027 g_hash_table_lookup (frame_table,
920 GINT_TO_POINTER (xevent->xbutton.window));1028 GINT_TO_POINTER (xevent->xbutton.window));
1029 XAllowEvents (gdk_x11_display_get_xdisplay (gdkdisplay), AsyncPointer, CurrentTime);
921 break;1030 break;
922 case EnterNotify:1031 case EnterNotify:
923 case LeaveNotify:1032 case LeaveNotify:
@@ -929,6 +1038,7 @@
929 xid = (gulong)1038 xid = (gulong)
930 g_hash_table_lookup (frame_table,1039 g_hash_table_lookup (frame_table,
931 GINT_TO_POINTER (xevent->xmotion.window));1040 GINT_TO_POINTER (xevent->xmotion.window));
1041 local_menu_process_motion (xevent->xmotion.x_root, xevent->xmotion.y_root);
932 break;1042 break;
933 case PropertyNotify:1043 case PropertyNotify:
934 if (xevent->xproperty.atom == frame_input_window_atom)1044 if (xevent->xproperty.atom == frame_input_window_atom)
@@ -1031,6 +1141,10 @@
1031 if (get_window_prop (xevent->xproperty.window, select_window_atom, &select))1141 if (get_window_prop (xevent->xproperty.window, select_window_atom, &select))
1032 update_switcher_window (xevent->xproperty.window, select);1142 update_switcher_window (xevent->xproperty.window, select);
1033 }1143 }
1144 else if (xevent->xproperty.atom == ubuntu_appmenu_unique_name_atom)
1145 {
1146 local_menu_cache_reload_xwindow (gdk_x11_display_get_xdisplay (gdkdisplay), xevent->xproperty.window);
1147 }
1034 break;1148 break;
1035 case DestroyNotify:1149 case DestroyNotify:
1036 g_hash_table_remove (frame_table,1150 g_hash_table_remove (frame_table,
10371151
=== modified file 'gtk/window-decorator/gtk-window-decorator.c'
--- gtk/window-decorator/gtk-window-decorator.c 2011-10-13 12:22:14 +0000
+++ gtk/window-decorator/gtk-window-decorator.c 2012-03-02 02:56:17 +0000
@@ -24,6 +24,7 @@
24 */24 */
2525
26#include "gtk-window-decorator.h"26#include "gtk-window-decorator.h"
27#include "local-menus.h"
2728
28gboolean minimal = FALSE;29gboolean minimal = FALSE;
2930
@@ -48,6 +49,7 @@
48Atom toolkit_action_atom;49Atom toolkit_action_atom;
49Atom toolkit_action_window_menu_atom;50Atom toolkit_action_window_menu_atom;
50Atom toolkit_action_force_quit_dialog_atom;51Atom toolkit_action_force_quit_dialog_atom;
52Atom ubuntu_appmenu_unique_name_atom;
5153
52Atom net_wm_state_atom;54Atom net_wm_state_atom;
53Atom net_wm_state_modal_atom;55Atom net_wm_state_modal_atom;
@@ -128,6 +130,38 @@
128 "normal", "modal_dialog", "dialog", "menu", "utility"130 "normal", "modal_dialog", "dialog", "menu", "utility"
129};131};
130132
133Box *
134get_active_window_local_menu_rectangle (gpointer user_data, int *dx, int *dy, int *top_height, Window *xid)
135{
136 WnckScreen *screen = (WnckScreen *) user_data;
137 WnckWindow *window = wnck_screen_get_active_window (screen);
138 int width, height;
139 decor_t *d = g_object_get_data (G_OBJECT (window), "decor");
140
141 if (!d->decorated)
142 return NULL;
143
144 wnck_window_get_geometry (window, dx, dy, &width, &height);
145
146 *top_height = d->context->extents.top;
147
148 *xid = wnck_window_get_xid (window);
149
150 Box *rect = &d->button_windows[BUTTON_WINDOW_MENU].pos;
151
152 return rect;
153}
154
155void
156on_local_menu_window_menu_updated (gpointer user_data)
157{
158 Window xid = GPOINTER_TO_INT (user_data);
159 WnckWindow *window = wnck_window_get (xid);
160 decor_t *d = g_object_get_data (G_OBJECT (window), "decor");
161
162 queue_decor_draw (d);
163}
164
131int165int
132main (int argc, char *argv[])166main (int argc, char *argv[])
133{167{
@@ -304,6 +338,7 @@
304338
305 net_wm_state_atom = XInternAtom (xdisplay,"_NET_WM_STATE", 0);339 net_wm_state_atom = XInternAtom (xdisplay,"_NET_WM_STATE", 0);
306 net_wm_state_modal_atom = XInternAtom (xdisplay, "_NET_WM_STATE_MODAL", 0);340 net_wm_state_modal_atom = XInternAtom (xdisplay, "_NET_WM_STATE_MODAL", 0);
341 ubuntu_appmenu_unique_name_atom = XInternAtom (xdisplay, "_UBUNTU_APPMENU_UNIQUE_NAME", 0);
307342
308 status = decor_acquire_dm_session (xdisplay,343 status = decor_acquire_dm_session (xdisplay,
309 gdk_screen_get_number (gdkscreen),344 gdk_screen_get_number (gdkscreen),
@@ -448,8 +483,32 @@
448483
449 update_default_decorations (gdkscreen);484 update_default_decorations (gdkscreen);
450485
486#ifdef META_HAS_LOCAL_MENUS
487 GDBusConnection *conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
488 local_menu_entry_activated_request_funcs funcs =
489 {
490 get_active_window_local_menu_rectangle,
491 on_local_menu_window_menu_updated
492 };
493
494 if (conn)
495 {
496 global_lim_listener = g_dbus_proxy_new_sync (conn, 0, NULL, "com.canonical.Unity.Panel.Service",
497 "/com/canonical/Unity/Panel/Service",
498 "com.canonical.Unity.Panel.Service",
499 NULL, NULL);
500
501 g_signal_connect (G_OBJECT (global_lim_listener), "g-signal", G_CALLBACK (local_menu_entry_activated_request), (gpointer) &funcs);
502 }
503#endif
451 gtk_main ();504 gtk_main ();
505#ifdef META_HAS_LOCAL_MENUS
506 if (global_lim_listener)
507 g_object_unref (global_lim_listener);
452508
509 if (conn)
510 g_object_unref (conn);
511#endif
453 win = windows = wnck_screen_get_windows (screen);512 win = windows = wnck_screen_get_windows (screen);
454513
455 while (win != NULL)514 while (win != NULL)
456515
=== modified file 'gtk/window-decorator/gtk-window-decorator.h'
--- gtk/window-decorator/gtk-window-decorator.h 2011-10-13 12:22:14 +0000
+++ gtk/window-decorator/gtk-window-decorator.h 2012-03-02 02:56:17 +0000
@@ -306,6 +306,7 @@
306extern Atom toolkit_action_force_quit_dialog_atom;306extern Atom toolkit_action_force_quit_dialog_atom;
307extern Atom net_wm_state_atom;307extern Atom net_wm_state_atom;
308extern Atom net_wm_state_modal_atom;308extern Atom net_wm_state_modal_atom;
309extern Atom ubuntu_appmenu_unique_name_atom;
309310
310extern Time dm_sn_timestamp;311extern Time dm_sn_timestamp;
311312
@@ -328,7 +329,8 @@
328#define BUTTON_UNSHADE 7329#define BUTTON_UNSHADE 7
329#define BUTTON_UNABOVE 8330#define BUTTON_UNABOVE 8
330#define BUTTON_UNSTICK 9331#define BUTTON_UNSTICK 9
331#define BUTTON_NUM 10332#define BUTTON_WINDOW_MENU 10
333#define BUTTON_NUM 11
332334
333struct _pos {335struct _pos {
334 int x, y, w, h;336 int x, y, w, h;
@@ -1013,6 +1015,11 @@
1013 decor_event_type gtkwd_type);1015 decor_event_type gtkwd_type);
10141016
1015void1017void
1018window_menu_button_event (WnckWindow *win,
1019 decor_event *gtkwd_event,
1020 decor_event_type gtkwd_type);
1021
1022void
1016handle_title_button_event (WnckWindow *win,1023handle_title_button_event (WnckWindow *win,
1017 int action,1024 int action,
1018 decor_event *gtkwd_event);1025 decor_event *gtkwd_event);
10191026
=== added directory 'gtk/window-decorator/local-menus'
=== added file 'gtk/window-decorator/local-menus/CMakeLists.txt'
--- gtk/window-decorator/local-menus/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/CMakeLists.txt 2012-03-02 02:56:17 +0000
@@ -0,0 +1,60 @@
1pkg_check_modules(
2 LOCAL_MENUS
3 REQUIRED
4 glib-2.0 gio-2.0 libwnck-1.0 gtk+-2.0>=2.18.0
5)
6
7INCLUDE_DIRECTORIES(
8 ${CMAKE_CURRENT_SOURCE_DIR}/include
9 ${CMAKE_CURRENT_SOURCE_DIR}/src
10
11 ${compiz_SOURCE_DIR}/gtk/window-decorator
12
13 ${Boost_INCLUDE_DIRS}
14
15 ${LOCAL_MENUS_INCLUDE_DIRS}
16 ${METACITY_INCLUDE_DIRS}
17)
18
19LINK_DIRECTORIES (${LOCAL_MENUS_LIBRARY_DIRS})
20
21SET(
22 PUBLIC_HEADERS
23)
24
25SET(
26 PRIVATE_HEADERS
27 ${CMAKE_CURRENT_SOURCE_DIR}/src/local-menus.h
28)
29
30SET(
31 SRCS
32 ${CMAKE_CURRENT_SOURCE_DIR}/src/local-menus.c
33)
34
35ADD_LIBRARY(
36 gtk_window_decorator_local_menus STATIC
37
38 ${SRCS}
39
40 ${PUBLIC_HEADERS}
41 ${PRIVATE_HEADERS}
42)
43
44IF (COMPIZ_BUILD_TESTING)
45ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
46ENDIF (COMPIZ_BUILD_TESTING)
47
48SET_TARGET_PROPERTIES(
49 gtk_window_decorator_local_menus PROPERTIES
50 PUBLIC_HEADER "${PUBLIC_HEADERS}"
51)
52
53install (FILES ${PUBLIC_HEADERS} DESTINATION ${COMPIZ_CORE_INCLUDE_DIR})
54
55TARGET_LINK_LIBRARIES(
56 gtk_window_decorator_local_menus
57
58 ${LOCAL_MENUS_LIBRARIES}
59)
60
061
=== added directory 'gtk/window-decorator/local-menus/include'
=== added directory 'gtk/window-decorator/local-menus/src'
=== added file 'gtk/window-decorator/local-menus/src/local-menus.c'
--- gtk/window-decorator/local-menus/src/local-menus.c 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/src/local-menus.c 2012-03-02 02:56:17 +0000
@@ -0,0 +1,438 @@
1/*
2 * Copyright © 2006 Novell, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * Author: David Reveman <davidr@novell.com>
20 *
21 * 2D Mode: Copyright © 2010 Sam Spilsbury <smspillaz@gmail.com>
22 * Frames Management: Copright © 2011 Canonical Ltd.
23 * Authored By: Sam Spilsbury <sam.spilsbury@canonical.com>
24 */
25
26#include <string.h>
27#include "local-menus.h"
28#include <gdk/gdk.h>
29#include <gdk/gdkx.h>
30#include <stdlib.h>
31
32#define GLOBAL 0
33#define LOCAL 1
34
35#define ALLOWED 2
36#define NOT_ALLOWED 1
37
38gint menu_mode = GLOBAL;
39
40GDBusProxy *global_lim_listener;
41
42
43#ifdef META_HAS_LOCAL_MENUS
44static void
45gwd_menu_mode_changed (GSettings *settings,
46 gchar *key,
47 gpointer user_data)
48{
49 menu_mode = g_settings_get_enum (settings, "menu-mode");
50}
51#endif
52
53active_local_menu *active_menu;
54pending_local_menu *pending_menu;
55
56GHashTable *get_windows_with_menus_table ()
57{
58 static GHashTable *windows_with_menus = NULL;
59
60 if (!windows_with_menus)
61 windows_with_menus = g_hash_table_new (NULL, NULL);
62
63 return windows_with_menus;
64}
65
66static gboolean read_xprop_for_window (Display *dpy, Window xid)
67{
68 Atom ubuntu_appmenu_unique_name = XInternAtom (dpy, "_UBUNTU_APPMENU_UNIQUE_NAME", FALSE);
69 Atom utf8_string = XInternAtom (dpy, "UTF8_STRING", FALSE);
70 Atom actual;
71 int fmt;
72 unsigned long nitems, nleft;
73 unsigned char *prop;
74 XGetWindowProperty (dpy, xid, ubuntu_appmenu_unique_name,
75 0L, 16L, FALSE, utf8_string, &actual, &fmt, &nitems, &nleft, &prop);
76
77 if (actual == utf8_string && fmt == 8 && nitems > 1)
78 {
79 g_hash_table_replace (get_windows_with_menus_table (), GINT_TO_POINTER (xid), GINT_TO_POINTER (ALLOWED));
80 return TRUE;
81 }
82 else
83 {
84 g_hash_table_replace (get_windows_with_menus_table (), GINT_TO_POINTER (xid), GINT_TO_POINTER (NOT_ALLOWED));
85 return FALSE;
86 }
87}
88
89gboolean
90local_menu_allowed_on_window (Display *dpy, Window xid)
91{
92 gpointer local_menu_allowed_found = g_hash_table_lookup (get_windows_with_menus_table (), GINT_TO_POINTER (xid));
93
94 if (local_menu_allowed_found)
95 {
96 return GPOINTER_TO_INT (local_menu_allowed_found) == ALLOWED;
97 }
98 else if (dpy && xid)
99 {
100 return read_xprop_for_window (dpy, xid);
101 }
102
103 return FALSE;
104}
105
106gboolean
107gwd_window_should_have_local_menu (Window win)
108{
109#ifdef META_HAS_LOCAL_MENUS
110 const gchar * const *schemas = g_settings_list_schemas ();
111 static GSettings *lim_settings = NULL;
112 while (*schemas != NULL && !lim_settings)
113 {
114 if (g_str_equal (*schemas, "com.canonical.indicator.appmenu"))
115 {
116 lim_settings = g_settings_new ("com.canonical.indicator.appmenu");
117 menu_mode = g_settings_get_enum (lim_settings, "menu-mode");
118 g_signal_connect (lim_settings, "changed::menu-mode", G_CALLBACK (gwd_menu_mode_changed), NULL);
119 break;
120 }
121 ++schemas;
122 }
123
124 if (lim_settings && win)
125 return menu_mode == LOCAL && local_menu_allowed_on_window (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), win);
126#endif
127
128 return FALSE;
129}
130
131gchar *
132gwd_get_entry_id_from_sync_variant (GVariant *args)
133{
134 /* We need to get the indicator data once we've called show */
135
136 GVariantIter* iter = NULL;
137 gchar* name_hint = NULL;
138 gchar* indicator_id = NULL;
139 gchar* entry_id = NULL;
140 gchar* label = NULL;
141 gboolean label_sensitive = FALSE;
142 gboolean label_visible = FALSE;
143 guint32 image_type = 0;
144 gchar* image_data = NULL;
145 gboolean image_sensitive = FALSE;
146 gboolean image_visible = FALSE;
147 gint32 priority = -1;
148
149 g_variant_get (args, "(a(ssssbbusbbi))", &iter);
150 while (g_variant_iter_loop (iter, "(ssssbbusbbi)",
151 &indicator_id,
152 &entry_id,
153 &name_hint,
154 &label,
155 &label_sensitive,
156 &label_visible,
157 &image_type,
158 &image_data,
159 &image_sensitive,
160 &image_visible,
161 &priority))
162 {
163 g_variant_unref (args);
164 return g_strdup (entry_id);
165 }
166
167 g_variant_unref (args);
168 g_assert_not_reached ();
169 return NULL;
170}
171#ifdef META_HAS_LOCAL_MENUS
172static void
173on_local_menu_activated (GDBusProxy *proxy,
174 gchar *sender_name,
175 gchar *signal_name,
176 GVariant *parameters,
177 gpointer user_data)
178{
179
180 if (g_strcmp0 (signal_name, "EntryActivated") == 0)
181 {
182 show_local_menu_data *d = (show_local_menu_data *) user_data;
183 gchar *entry_id = NULL;
184 gint x_out, y_out;
185 guint width, height;
186
187 g_variant_get (parameters, "(s(iiuu))", &entry_id, &x_out, &y_out, &width, &height, NULL);
188
189 if (!d->local_menu_entry_id)
190 {
191 GError *error = NULL;
192 GVariant *params = g_variant_new ("(s)", "libappmenu.so", NULL);
193 GVariant *args = g_dbus_proxy_call_sync (proxy, "SyncOne", params, 0, 500, NULL, &error);
194
195 g_assert_no_error (error);
196 d->local_menu_entry_id = gwd_get_entry_id_from_sync_variant (args);
197 }
198
199 if (g_strcmp0 (entry_id, d->local_menu_entry_id) == 0)
200 {
201 d->rect->x = x_out - d->dx;
202 d->rect->y = y_out - d->dy;
203 d->rect->width = width;
204 d->rect->height = height;
205 (*d->cb) (d->user_data);
206 }
207 else if (g_strcmp0 (entry_id, "") == 0)
208 {
209 memset (d->rect, 0, sizeof (GdkRectangle));
210 (*d->cb) (d->user_data);
211
212 g_signal_handlers_disconnect_by_func (proxy, on_local_menu_activated, d);
213
214 if (active_menu)
215 {
216 g_free (active_menu);
217 active_menu = NULL;
218 }
219
220 g_free (d->local_menu_entry_id);
221 g_free (d);
222 }
223 }
224
225}
226#endif
227gboolean
228gwd_move_window_instead (gpointer user_data)
229{
230 (*pending_menu->cb) (pending_menu->user_data);
231 g_source_remove (pending_menu->move_timeout_id);
232 g_free (pending_menu->user_data);
233 g_free (pending_menu);
234 pending_menu = NULL;
235 return FALSE;
236}
237
238void
239local_menu_process_motion(gint x_root, gint y_root)
240{
241 if (!pending_menu)
242 return;
243
244 if (abs (pending_menu->x_root - x_root) > 4 &&
245 abs (pending_menu->y_root - y_root) > 4)
246 gwd_move_window_instead (pending_menu);
247}
248
249void
250gwd_prepare_show_local_menu (start_move_window_cb start_move_window,
251 gpointer user_data_start_move_window,
252 gint x_root,
253 gint y_root)
254{
255 if (pending_menu)
256 {
257 g_source_remove (pending_menu->move_timeout_id);
258 g_free (pending_menu->user_data);
259 g_free (pending_menu);
260 pending_menu = NULL;
261 }
262
263 pending_menu = g_new0 (pending_local_menu, 1);
264 pending_menu->cb = start_move_window;
265 pending_menu->user_data = user_data_start_move_window;
266 pending_menu->move_timeout_id = g_timeout_add (150, gwd_move_window_instead, pending_menu);
267}
268
269#ifdef META_HAS_LOCAL_MENUS
270void
271local_menu_entry_activated_request (GDBusProxy *proxy,
272 gchar *sender_name,
273 gchar *signal_name,
274 GVariant *parameters,
275 gpointer user_data)
276{
277 if (g_strcmp0 (signal_name, "EntryActivateRequest") == 0)
278 {
279 gchar *activated_entry_id;
280 gchar *local_menu_entry_id;
281 local_menu_entry_activated_request_funcs *funcs = (local_menu_entry_activated_request_funcs *) user_data;
282
283 g_variant_get (parameters, "(s)", &activated_entry_id, NULL);
284
285 GError *error = NULL;
286 GVariant *params = g_variant_new ("(s)", "libappmenu.so", NULL);
287 GVariant *args = g_dbus_proxy_call_sync (proxy, "SyncOne", params, 0, 500, NULL, &error);
288
289 g_assert_no_error (error);
290 local_menu_entry_id = gwd_get_entry_id_from_sync_variant (args);
291
292 if (g_strcmp0 (activated_entry_id, local_menu_entry_id) == 0)
293 {
294 WnckScreen *screen = wnck_screen_get_for_root (gdk_x11_get_default_root_xwindow ());
295 int dx, dy, top_height;
296 Window xid;
297
298 if (screen)
299 {
300 Box *rect = (*funcs->active_window_local_menu_rect_callback) ((gpointer) screen, &dx, &dy, &top_height, &xid);
301
302 if (rect)
303 {
304 int x = rect->x1;
305 int y = top_height;
306
307 gwd_show_local_menu (gdk_x11_display_get_xdisplay (gdk_display_get_default ()),
308 xid, x + dx, y + dy, x, y, 0, 0,
309 funcs->show_window_menu_hidden_callback, GINT_TO_POINTER (xid));
310 }
311 }
312 }
313 }
314}
315#endif
316
317gboolean
318gwd_show_local_menu (Display *xdisplay,
319 Window frame_xwindow,
320 int x,
321 int y,
322 int x_win,
323 int y_win,
324 int button,
325 guint32 timestamp,
326 show_window_menu_hidden_cb cb,
327 gpointer user_data_show_window_menu)
328{
329 if (pending_menu)
330 {
331 g_source_remove (pending_menu->move_timeout_id);
332 g_free (pending_menu->user_data);
333 g_free (pending_menu);
334 pending_menu = NULL;
335 }
336
337#ifdef META_HAS_LOCAL_MENUS
338
339
340 XUngrabPointer (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), CurrentTime);
341 XUngrabKeyboard (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), CurrentTime);
342 XSync (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), FALSE);
343
344 GDBusProxy *proxy = global_lim_listener;
345
346 if (proxy)
347 {
348 GVariant *message = g_variant_new ("(uiiu)", frame_xwindow, x, y, time);
349 GError *error = NULL;
350 g_dbus_proxy_call_sync (proxy, "ShowAppMenu", message, 0, 500, NULL, &error);
351 if (error)
352 {
353 g_print ("error calling ShowAppMenu: %s\n", error->message);
354 return FALSE;
355 }
356
357 show_local_menu_data *data = g_new0 (show_local_menu_data, 1);
358
359 if (active_menu)
360 g_free (active_menu);
361
362 active_menu = g_new0 (active_local_menu, 1);
363
364 data->cb = cb;
365 data->user_data = user_data_show_window_menu;
366 data->rect = &active_menu->rect;
367 data->dx = x - x_win;
368 data->dy = y - y_win;
369 data->local_menu_entry_id = NULL;
370
371 g_signal_connect (proxy, "g-signal", G_CALLBACK (on_local_menu_activated), data);
372
373 return TRUE;
374 }
375#endif
376 return FALSE;
377}
378
379void
380force_local_menus_on (Window win,
381 MetaButtonLayout *button_layout)
382{
383#ifdef META_HAS_LOCAL_MENUS
384 if (gwd_window_should_have_local_menu (win))
385 {
386 if (button_layout->left_buttons[0] != META_BUTTON_FUNCTION_LAST)
387 {
388 unsigned int i = 0;
389 for (; i < MAX_BUTTONS_PER_CORNER; i++)
390 {
391 if (button_layout->left_buttons[i] == META_BUTTON_FUNCTION_WINDOW_MENU)
392 break;
393 else if (button_layout->left_buttons[i] == META_BUTTON_FUNCTION_LAST)
394 {
395 if ((i + 1) < MAX_BUTTONS_PER_CORNER)
396 {
397 button_layout->left_buttons[i + 1] = META_BUTTON_FUNCTION_LAST;
398 button_layout->left_buttons[i] = META_BUTTON_FUNCTION_WINDOW_MENU;
399 break;
400 }
401 }
402 }
403 }
404 if (button_layout->right_buttons[0] != META_BUTTON_FUNCTION_LAST)
405 {
406 unsigned int i = 0;
407 for (; i < MAX_BUTTONS_PER_CORNER; i++)
408 {
409 if (button_layout->right_buttons[i] == META_BUTTON_FUNCTION_WINDOW_MENU)
410 break;
411 else if (button_layout->right_buttons[i] == META_BUTTON_FUNCTION_LAST)
412 {
413 if ((i + 1) < MAX_BUTTONS_PER_CORNER)
414 {
415 button_layout->right_buttons[i + 1] = META_BUTTON_FUNCTION_LAST;
416 button_layout->right_buttons[i] = META_BUTTON_FUNCTION_WINDOW_MENU;
417 break;
418 }
419 }
420 }
421 }
422 }
423#endif
424}
425
426void
427local_menu_cache_notify_window_destroyed (Window xid)
428{
429 g_hash_table_remove (get_windows_with_menus_table (), GINT_TO_POINTER (xid));
430}
431
432void
433local_menu_cache_reload_xwindow (Display *dpy, Window xid)
434{
435 read_xprop_for_window (dpy, xid);
436}
437
438
0439
=== added file 'gtk/window-decorator/local-menus/src/local-menus.h'
--- gtk/window-decorator/local-menus/src/local-menus.h 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/src/local-menus.h 2012-03-02 02:56:17 +0000
@@ -0,0 +1,125 @@
1/*
2 * Copyright © 2006 Novell, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * Author: David Reveman <davidr@novell.com>
20 *
21 * 2D Mode: Copyright © 2010 Sam Spilsbury <smspillaz@gmail.com>
22 * Frames Management: Copright © 2011 Canonical Ltd.
23 * Authored By: Sam Spilsbury <sam.spilsbury@canonical.com>
24 */
25
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31#include <glib.h>
32#include <gio/gio.h>
33#ifndef WNCK_I_KNOW_THIS_IS_UNSTABLE
34#define WNCK_I_KNOW_THIS_IS_UNSTABLE
35#endif
36#include <libwnck/libwnck.h>
37#include <libwnck/window-action-menu.h>
38#include <metacity-private/theme.h>
39#include <X11/Xregion.h>
40
41
42typedef void (*show_window_menu_hidden_cb) (gpointer);
43typedef void (*start_move_window_cb) (gpointer);
44typedef Box * (*get_active_window_local_menu_rect_cb) (gpointer, int *, int *, int *, Window *);
45
46typedef struct _pending_local_menu
47{
48 gint move_timeout_id;
49 gpointer user_data;
50 start_move_window_cb cb;
51 gint x_root;
52 gint y_root;
53} pending_local_menu;
54
55typedef struct _active_local_menu
56{
57 GdkRectangle rect;
58} active_local_menu;
59
60extern active_local_menu *active_menu;
61extern GDBusProxy *global_lim_listener;
62
63typedef struct _show_local_menu_data
64{
65 show_window_menu_hidden_cb cb;
66 gpointer user_data;
67 GdkRectangle *rect;
68 gint dx;
69 gint dy;
70 gchar *local_menu_entry_id;
71} show_local_menu_data;
72
73typedef struct _local_menu_entry_activated_request_funcs
74{
75 get_active_window_local_menu_rect_cb active_window_local_menu_rect_callback;
76 show_window_menu_hidden_cb show_window_menu_hidden_callback;
77} local_menu_entry_activated_request_funcs;
78
79gboolean
80gwd_window_should_have_local_menu (Window win);
81
82void
83force_local_menus_on (Window win,
84 MetaButtonLayout *layout);
85
86/* Button Down */
87void
88gwd_prepare_show_local_menu (start_move_window_cb start_move_window,
89 gpointer user_data_start_move_window, gint x_root, gint y_root);
90
91/* Button Up */
92gboolean
93gwd_show_local_menu (Display *xdisplay,
94 Window frame_xwindow,
95 int x,
96 int y,
97 int x_win,
98 int y_win,
99 int button,
100 guint32 timestamp,
101 show_window_menu_hidden_cb cb,
102 gpointer user_data_show_window_menu);
103
104void
105local_menu_cache_notify_window_destroyed (Window xid);
106
107void
108local_menu_cache_reload_xwindow (Display *xdisplay, Window xid);
109
110gboolean
111local_menu_allowed_on_window (Display *dpy, Window xid);
112
113void
114local_menu_entry_activated_request (GDBusProxy *proxy,
115 gchar *sender_name,
116 gchar *signal_name,
117 GVariant *parameters,
118 gpointer user_data);
119
120void
121local_menu_process_motion (gint x_root, gint y_root);
122
123#ifdef __cplusplus
124}
125#endif
0126
=== added directory 'gtk/window-decorator/local-menus/tests'
=== added file 'gtk/window-decorator/local-menus/tests/CMakeLists.txt'
--- gtk/window-decorator/local-menus/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/tests/CMakeLists.txt 2012-03-02 02:56:17 +0000
@@ -0,0 +1,3 @@
1include_directories (${CMAKE_CURRENT_SOURCE_DIR})
2add_subdirectory (check_local_menu_on_off)
3add_subdirectory (force_local_menu_on)
04
=== added directory 'gtk/window-decorator/local-menus/tests/check_local_menu_on_off'
=== added file 'gtk/window-decorator/local-menus/tests/check_local_menu_on_off/CMakeLists.txt'
--- gtk/window-decorator/local-menus/tests/check_local_menu_on_off/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/tests/check_local_menu_on_off/CMakeLists.txt 2012-03-02 02:56:17 +0000
@@ -0,0 +1,21 @@
1include_directories (${CMAKE_CURRENT_SOURCE_DIR}
2 ${compiz_SOURCE_DIR}/gtk/window-decorator/local-menus/tests
3 ${compiz_SOURCE_DIR}/gtk/window-decorator
4 ${compiz_SOURCE_DIR}/gtk/window-decorator/local-menus/src)
5
6add_executable(
7 gtk_window_decorator_check_local_menu_on_off_test
8
9 ${CMAKE_CURRENT_SOURCE_DIR}/test-local-menu-on-off.cpp
10)
11
12target_link_libraries(
13 gtk_window_decorator_check_local_menu_on_off_test
14
15 gtk_window_decorator_local_menus
16
17 ${GTEST_BOTH_LIBRARIES}
18 ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
19)
20
21add_test (gtk_window_decorator_local_menus_on_off gtk_window_decorator_check_local_menu_on_off_test)
022
=== added directory 'gtk/window-decorator/local-menus/tests/check_local_menu_on_off/check_local_menu_on_off'
=== added directory 'gtk/window-decorator/local-menus/tests/check_local_menu_on_off/check_local_menu_on_off/CMakeFiles'
=== added file 'gtk/window-decorator/local-menus/tests/check_local_menu_on_off/test-local-menu-on-off.cpp'
--- gtk/window-decorator/local-menus/tests/check_local_menu_on_off/test-local-menu-on-off.cpp 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/tests/check_local_menu_on_off/test-local-menu-on-off.cpp 2012-03-02 02:56:17 +0000
@@ -0,0 +1,47 @@
1#include "test-local-menu.h"
2#include <string.h>
3#include <gdk/gdkx.h>
4
5#define GLOBAL 0
6#define LOCAL 1
7#ifdef META_HAS_LOCAL_MENUS
8
9TEST_F (GtkWindowDecoratorTestLocalMenu, TestOnNoProp)
10{
11 g_settings_set_enum (getSettings (), "menu-mode", LOCAL);
12 gboolean result = gwd_window_should_have_local_menu (getWindow ());
13
14 EXPECT_FALSE (result);
15}
16
17TEST_F (GtkWindowDecoratorTestLocalMenu, TestOnWithProp)
18{
19 g_settings_set_enum (getSettings (), "menu-mode", LOCAL);
20
21 Window xid = getWindow ();
22 Atom ubuntu_appmenu_unique_name = XInternAtom (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), "_UBUNTU_APPMENU_UNIQUE_NAME", FALSE);
23 Atom utf8_string = XInternAtom (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), "UTF8_STRING", FALSE);
24 const char data[] = ":abcd1234";
25
26 XChangeProperty (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), xid, ubuntu_appmenu_unique_name, utf8_string, 8, PropModeReplace, (const unsigned char *) data, strlen (data));
27
28 gdk_display_sync (gdk_display_get_default ());
29
30 gboolean result = gwd_window_should_have_local_menu (getWindow ());
31
32 EXPECT_TRUE (result);
33}
34
35TEST_F (GtkWindowDecoratorTestLocalMenu, TestOff)
36{
37 g_settings_set_enum (getSettings (), "menu-mode", GLOBAL);
38 gboolean result = gwd_window_should_have_local_menu (getWindow ());
39
40 EXPECT_FALSE (result);
41}
42#else
43TEST_F (GtkWindowDecoratorTestLocalMenu, NoMenus)
44{
45 ASSERT_TRUE (true) << "Local menus tests not enabled because META_HAS_LOCAL_MENUS is off";
46}
47#endif
048
=== added directory 'gtk/window-decorator/local-menus/tests/force_local_menu_on'
=== added file 'gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeLists.txt'
--- gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/tests/force_local_menu_on/CMakeLists.txt 2012-03-02 02:56:17 +0000
@@ -0,0 +1,21 @@
1include_directories (${CMAKE_CURRENT_SOURCE_DIR}
2 ${compiz_SOURCE_DIR}/gtk/window-decorator/local-menus/tests
3 ${compiz_SOURCE_DIR}/gtk/window-decorator
4 ${compiz_SOURCE_DIR}/gtk/window-decorator/local-menus/src)
5
6add_executable(
7 gtk_window_decorator_force_local_menu_on_test
8
9 ${CMAKE_CURRENT_SOURCE_DIR}/test-force-local-menu-on.cpp
10)
11
12target_link_libraries(
13 gtk_window_decorator_force_local_menu_on_test
14
15 gtk_window_decorator_local_menus
16
17 ${GTEST_BOTH_LIBRARIES}
18 ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
19)
20
21add_test (gtk_window_decorator_force_local_menu_on gtk_window_decorator_force_local_menu_on_test)
022
=== added file 'gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp'
--- gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/tests/force_local_menu_on/test-force-local-menu-on.cpp 2012-03-02 02:56:17 +0000
@@ -0,0 +1,89 @@
1#include "test-local-menu.h"
2#include <cstring>
3#include <gdk/gdkx.h>
4
5#define GLOBAL 0
6#define LOCAL 1
7#ifdef META_HAS_LOCAL_MENUS
8
9namespace
10{
11 void initializeMetaButtonLayout (MetaButtonLayout *layout)
12 {
13 memset (layout, 0, sizeof (MetaButtonLayout));
14
15 unsigned int i;
16
17 for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++)
18 {
19 layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
20 layout->left_buttons[i] = META_BUTTON_FUNCTION_LAST;
21 }
22 }
23}
24
25class GtkWindowDecoratorTestLocalMenuLayout :
26 public GtkWindowDecoratorTestLocalMenu
27{
28 public:
29
30 MetaButtonLayout * getLayout () { return &mLayout; }
31
32 virtual void SetUp ()
33 {
34 GtkWindowDecoratorTestLocalMenu::SetUp ();
35 ::initializeMetaButtonLayout (&mLayout);
36 g_settings_set_enum (getSettings (), "menu-mode", LOCAL);
37
38 Window xid = getWindow ();
39 Atom ubuntu_appmenu_unique_name = XInternAtom (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), "_UBUNTU_APPMENU_UNIQUE_NAME", FALSE);
40 Atom utf8_string = XInternAtom (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), "UTF8_STRING", FALSE);
41 const char data[] = ":abcd1234";
42
43 XChangeProperty (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), xid, ubuntu_appmenu_unique_name, utf8_string, 8, PropModeReplace, (const unsigned char *) data, strlen (data));
44
45 gdk_display_sync (gdk_display_get_default ());
46
47 ASSERT_TRUE (gwd_window_should_have_local_menu (getWindow ()));
48 }
49
50 private:
51
52 MetaButtonLayout mLayout;
53};
54
55TEST_F (GtkWindowDecoratorTestLocalMenuLayout, TestForceNoButtonsSet)
56{
57 force_local_menus_on (getWindow (), getLayout ());
58
59 EXPECT_EQ (getLayout ()->right_buttons[0], META_BUTTON_FUNCTION_LAST);
60 EXPECT_EQ (getLayout ()->left_buttons[0], META_BUTTON_FUNCTION_LAST);
61}
62
63TEST_F (GtkWindowDecoratorTestLocalMenuLayout, TestForceNoCloseButtonSet)
64{
65 getLayout ()->right_buttons[0] = META_BUTTON_FUNCTION_CLOSE;
66
67 force_local_menus_on (getWindow (), getLayout ());
68
69 EXPECT_EQ (getLayout ()->right_buttons[1], META_BUTTON_FUNCTION_WINDOW_MENU);
70 EXPECT_EQ (getLayout ()->left_buttons[0], META_BUTTON_FUNCTION_LAST);
71}
72
73TEST_F (GtkWindowDecoratorTestLocalMenuLayout, TestForceNoCloseMinimizeMaximizeButtonSet)
74{
75 getLayout ()->left_buttons[0] = META_BUTTON_FUNCTION_CLOSE;
76 getLayout ()->left_buttons[1] = META_BUTTON_FUNCTION_CLOSE;
77 getLayout ()->left_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
78
79 force_local_menus_on (getWindow (), getLayout ());
80
81 EXPECT_EQ (getLayout ()->right_buttons[0], META_BUTTON_FUNCTION_LAST);
82 EXPECT_EQ (getLayout ()->left_buttons[3], META_BUTTON_FUNCTION_WINDOW_MENU);
83}
84#else
85TEST_F (GtkWindowDecoratorTestLocalMenu, NoMenus)
86{
87 ASSERT_TRUE (true) << "Local menus tests not enabled because META_HAS_LOCAL_MENUS is off";
88}
89#endif
090
=== added directory 'gtk/window-decorator/local-menus/tests/show_hide_menu'
=== added file 'gtk/window-decorator/local-menus/tests/test-local-menu.h'
--- gtk/window-decorator/local-menus/tests/test-local-menu.h 1970-01-01 00:00:00 +0000
+++ gtk/window-decorator/local-menus/tests/test-local-menu.h 2012-03-02 02:56:17 +0000
@@ -0,0 +1,106 @@
1#include <gtest/gtest.h>
2#include <gmock/gmock.h>
3#include "local-menus.h"
4#include <X11/Xlib.h>
5#include <gio/gio.h>
6#include <sys/poll.h>
7#include <X11/Xatom.h>
8
9class GtkWindowDecoratorTestLocalMenu :
10 public ::testing::Test
11{
12 public:
13
14#ifdef META_HAS_LOCAL_MENUS
15 Window getWindow () { return mXWindow; }
16 GSettings * getSettings () { return mSettings; }
17 virtual void SetUp ()
18 {
19 gtk_init (NULL, NULL);
20
21 mXDisplay = XOpenDisplay (NULL);
22
23 XSelectInput (mXDisplay, DefaultRootWindow (mXDisplay), PropertyChangeMask);
24
25 mXWindow = XCreateSimpleWindow (mXDisplay, DefaultRootWindow (mXDisplay), 0, 0, 100, 100, 0, 0, 0);
26
27 Atom net_client_list = XInternAtom (mXDisplay, "_NET_CLIENT_LIST", FALSE);
28
29 XMapRaised (mXDisplay, mXWindow);
30
31 XFlush (mXDisplay);
32
33 /* Wait for _NET_CLIENT_LIST to be updated with this window */
34 while (1)
35 {
36 struct pollfd pfd;
37
38 pfd.events = POLLIN;
39 pfd.revents = 0;
40 pfd.fd = ConnectionNumber (mXDisplay);
41
42 XEvent event;
43
44 poll (&pfd, 1, -1);
45
46 XNextEvent (mXDisplay, &event);
47
48 gboolean foundWindow = FALSE;
49
50 switch (event.type)
51 {
52 case PropertyNotify:
53 {
54 if (event.xproperty.atom == net_client_list)
55 {
56 Atom type;
57 int fmt;
58 unsigned long nitems, nleft;
59 unsigned char *prop;
60
61 XGetWindowProperty (mXDisplay, event.xproperty.window, net_client_list,
62 0L, 128L, FALSE, XA_WINDOW, &type, &fmt, &nitems, &nleft, &prop);
63
64 if (fmt == 32 && type == XA_WINDOW && nitems && !nleft)
65 {
66 Window *windows = (Window *) prop;
67
68 while (nitems--)
69 {
70 if (*(windows++) == mXWindow)
71 foundWindow = TRUE;
72 }
73 }
74
75 XFree (prop);
76 }
77
78 break;
79 }
80 default:
81 break;
82 }
83
84 if (foundWindow)
85 break;
86 }
87
88 g_setenv("GSETTINGS_BACKEND", "memory", true);
89 mSettings = g_settings_new ("com.canonical.indicator.appmenu");
90 }
91
92 virtual void TearDown ()
93 {
94 XDestroyWindow (mXDisplay, mXWindow);
95 XCloseDisplay (mXDisplay);
96
97 g_object_unref (mSettings);
98 }
99#endif
100
101 private:
102
103 Window mXWindow;
104 Display *mXDisplay;
105 GSettings *mSettings;
106};
0107
=== modified file 'gtk/window-decorator/metacity.c'
--- gtk/window-decorator/metacity.c 2012-02-16 06:51:37 +0000
+++ gtk/window-decorator/metacity.c 2012-03-02 02:56:17 +0000
@@ -24,6 +24,7 @@
24 */24 */
2525
26#include "gtk-window-decorator.h"26#include "gtk-window-decorator.h"
27#include "local-menus.h"
2728
28#ifdef USE_METACITY29#ifdef USE_METACITY
2930
@@ -488,6 +489,8 @@
488 button_layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;489 button_layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
489 }490 }
490491
492 force_local_menus_on (d->win ? wnck_window_get_xid (d->win) : 0, button_layout);
493
491 *flags = 0;494 *flags = 0;
492495
493 if (d->actions & WNCK_WINDOW_ACTION_CLOSE)496 if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
@@ -538,6 +541,12 @@
538 *flags |= (MetaFrameFlags ) META_FRAME_ABOVE;541 *flags |= (MetaFrameFlags ) META_FRAME_ABOVE;
539#endif542#endif
540543
544#ifdef META_HAS_LOCAL_MENUS
545 if (d->win &&
546 local_menu_allowed_on_window (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), wnck_window_get_xid (d->win)))
547 *flags |= (MetaFrameFlags ) META_FRAME_ALLOWS_WINDOW_MENU;
548#endif
549
541 meta_theme_get_frame_borders (theme,550 meta_theme_get_frame_borders (theme,
542 frame_type,551 frame_type,
543 d->frame->text_height,552 d->frame->text_height,
@@ -558,6 +567,15 @@
558 else567 else
559 clip->height = d->border_layout.left.y2 - d->border_layout.left.y1;568 clip->height = d->border_layout.left.y2 - d->border_layout.left.y1;
560569
570 memset (fgeom, 0, sizeof (MetaFrameGeometry));
571
572#ifdef META_HAS_LOCAL_MENUS
573
574 if (d->layout)
575 fgeom->text_layout = g_object_ref (d->layout);
576
577#endif
578
561 meta_theme_calc_geometry (theme,579 meta_theme_calc_geometry (theme,
562 frame_type,580 frame_type,
563 d->frame->text_height,581 d->frame->text_height,
@@ -567,6 +585,15 @@
567 button_layout,585 button_layout,
568 fgeom);586 fgeom);
569587
588#ifdef META_HAS_LOCAL_MENUS
589
590 if (d->layout)
591 g_object_unref (fgeom->text_layout);
592
593 fgeom->text_layout = NULL;
594
595#endif
596
570 clip->width += left_width + right_width;597 clip->width += left_width + right_width;
571 clip->height += top_height + bottom_height;598 clip->height += top_height + bottom_height;
572}599}
@@ -601,6 +628,11 @@
601 GdkColor bg_color;628 GdkColor bg_color;
602 double bg_alpha;629 double bg_alpha;
603630
631 memset (&button_layout, 0, sizeof (MetaButtonLayout));
632
633 for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++)
634 button_layout.left_buttons[i] = button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
635
604 if (!d->pixmap || !d->picture)636 if (!d->pixmap || !d->picture)
605 return;637 return;
606638
@@ -675,6 +707,9 @@
675707
676 size = MAX (fgeom.top_height, fgeom.bottom_height);708 size = MAX (fgeom.top_height, fgeom.bottom_height);
677709
710 if (active_menu)
711 g_object_set_data (G_OBJECT (style_window), "local_menu_rect", &active_menu->rect);
712
678 if (rect.width && size)713 if (rect.width && size)
679 {714 {
680 XRenderPictFormat *format;715 XRenderPictFormat *format;
@@ -899,6 +934,9 @@
899 XRenderFreePicture (xdisplay, src);934 XRenderFreePicture (xdisplay, src);
900 }935 }
901936
937 if (active_menu)
938 g_object_set_data (G_OBJECT (style_window), "local_menu_rect", NULL);
939
902 copy_to_front_buffer (d);940 copy_to_front_buffer (d);
903941
904 if (d->frame_window)942 if (d->frame_window)
@@ -1078,6 +1116,15 @@
1078 break;1116 break;
1079#endif1117#endif
10801118
1119#ifdef META_HAS_LOCAL_MENUS
1120 case BUTTON_WINDOW_MENU:
1121 if (!meta_button_present (&button_layout, META_BUTTON_FUNCTION_WINDOW_MENU))
1122 return FALSE;
1123
1124 space = &fgeom.window_menu_rect;
1125 break;
1126#endif
1127
1081 default:1128 default:
1082 return FALSE;1129 return FALSE;
1083 }1130 }
@@ -1266,6 +1313,8 @@
1266 MetaTheme *theme;1313 MetaTheme *theme;
1267 GdkRectangle clip;1314 GdkRectangle clip;
12681315
1316 memset (&fgeom, 0, sizeof (MetaFrameGeometry));
1317
1269 theme = meta_theme_get_current ();1318 theme = meta_theme_get_current ();
12701319
1271 meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,1320 meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
@@ -1490,6 +1539,11 @@
1490 return META_BUTTON_FUNCTION_UNSTICK;1539 return META_BUTTON_FUNCTION_UNSTICK;
1491#endif1540#endif
14921541
1542#ifdef META_HAS_LOCAL_MENUS
1543 else if (strcmp (str, "window_menu") == 0)
1544 return META_BUTTON_FUNCTION_WINDOW_MENU;
1545#endif
1546
1493 else1547 else
1494 return META_BUTTON_FUNCTION_LAST;1548 return META_BUTTON_FUNCTION_LAST;
1495}1549}
14961550
=== modified file 'gtk/window-decorator/wnck.c'
--- gtk/window-decorator/wnck.c 2012-02-10 10:23:27 +0000
+++ gtk/window-decorator/wnck.c 2012-03-02 02:56:17 +0000
@@ -24,6 +24,7 @@
24 */24 */
2525
26#include "gtk-window-decorator.h"26#include "gtk-window-decorator.h"
27#include "local-menus.h"
2728
28const gchar *29const gchar *
29get_frame_type (WnckWindow *win)30get_frame_type (WnckWindow *win)
@@ -375,6 +376,19 @@
375 if (cursor[i][j].cursor)376 if (cursor[i][j].cursor)
376 XDefineCursor (xdisplay, d->event_windows[i][j].window,377 XDefineCursor (xdisplay, d->event_windows[i][j].window,
377 cursor[i][j].cursor);378 cursor[i][j].cursor);
379
380 XGrabButton (xdisplay,
381 Button1Mask,
382 AnyModifier,
383 d->event_windows[i][j].window,
384 FALSE,
385 ButtonPressMask |
386 ButtonReleaseMask |
387 PointerMotionMask,
388 GrabModeAsync,
389 GrabModeAsync,
390 None,
391 None);
378 }392 }
379 }393 }
380394
@@ -389,6 +403,20 @@
389 CopyFromParent, CopyFromParent, CopyFromParent,403 CopyFromParent, CopyFromParent, CopyFromParent,
390 CWOverrideRedirect | CWEventMask, &attr);404 CWOverrideRedirect | CWEventMask, &attr);
391405
406
407 XGrabButton (xdisplay,
408 Button1Mask,
409 AnyModifier,
410 d->button_windows[i].window,
411 FALSE,
412 ButtonPressMask |
413 ButtonReleaseMask |
414 PointerMotionMask,
415 GrabModeAsync,
416 GrabModeAsync,
417 None,
418 None);
419
392 d->button_states[i] = 0;420 d->button_states[i] = 0;
393 }421 }
394 }422 }
@@ -738,7 +766,8 @@
738 stick_button_event,766 stick_button_event,
739 unshade_button_event,767 unshade_button_event,
740 unabove_button_event,768 unabove_button_event,
741 unstick_button_event769 unstick_button_event,
770 window_menu_button_event
742 };771 };
743772
744 d = calloc (1, sizeof (decor_t));773 d = calloc (1, sizeof (decor_t));
@@ -784,6 +813,8 @@
784window_closed (WnckScreen *screen,813window_closed (WnckScreen *screen,
785 WnckWindow *win)814 WnckWindow *win)
786{815{
816 local_menu_cache_notify_window_destroyed (wnck_window_get_xid (win));
817
787 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");818 decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
788819
789 if (d)820 if (d)

Subscribers

People subscribed via source and target branches