338. How to set up an application to run in the system tray using GtkStatusIcon - Part 7 - ensure only one popup menu?

Problem

If you have run the example How to set up an application to run in the system tray using GtkStatusIcon - Part 4 - display popup menu on right click? or How to set up an application to run in the system tray using GtkStatusIcon - Part 5 - make the tray icon blink?, you will have noticed that if you keep pressing the right-mouse button on the system tray icon without selecting any of the menu item, you will end up having many popup windows surrounding the tray icon.

Let's fix this in this article as shown below:

How to set up an application to run in the system tray using GtkStatusIcon - Part 7 - ensure only one popup menu?


Solution

  1. Use a variable as a flag to let us know if there's any active popup window.
  2. If there's already a previous popup window, pop it down using the method GtkMenu::popdown() before displaying the new popup window.

Important Note: This only works for PHP-GTK2 compliled with gtk+ v2.10 and above. If you are using an older version, for linux, you may follow the step-by-step instructions to recompile php-gtk2 with gtk+ v2.10. For windows, please refer to How to install php gtk2 on windows? You may also want to take a look here to see some of the new exciting PHP-GTK2 Functionalities.


Sample Code

1   
2   
3   
4   
5   
7   
8   
9   
10   
11   
12   
13   
14   
15   
16   
17   
18   
19   
20   
21   
22   
23   
24   
25   
26   
27   
28   
29   
30   
31   
32   
33   
34   
35   
36   
37   
38   
39   
40   
41   
42   
43   
44   
45   
46   
47   
48   
49   
50   
51   
52   
53   
54   
55   
56   
57   
58   
59   
60   
61   
62   
63   
64   
65   
66   
67   
68   
69   
70   
71   
72   
73   
74   
75   
76   
77   
78   
79   
80   
81   
82   
84   
85   
87   
88   
89   
90   
92   
93   
94   
95   
96   
97   
98   
99   
101   
102   
103   
104   
105   
106   
107   
108   
109   
110   
111   
112   
113   
114   
115   
116   
117   
118   
119   
120   
121   
122   
123   
124   
125   
126   
129   
130   
131   
132   
133   
134   
135   
136   
137   
138   
139   
140   
141   
142   
143   
144   
145   
146   
147   
<?php
// setup GTK main application
$window = new GtkWindow();
$window->set_title($argv[0]);
$window->set_size_request(400, 300);
$window->connect('destroy', 'destroy');

$window->add($vbox = new GtkVBox());

$vbox->pack_start($hbox = new GtkHBox(), 0, 0);
$hbox->set_size_request(-1, 2);

// Create the top textview to display the conversation
$buffer1 = new GtkTextBuffer();
$view1 = new GtkTextView();
$view1->set_buffer($buffer1);
$view1->set_editable(false);
$view1->modify_font(new PangoFontDescription("Arial 9"));
$view1->set_wrap_mode(Gtk::WRAP_WORD);

$scrolled_win1 = new GtkScrolledWindow();
$scrolled_win1->set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC);
$frame1 = new GtkFrame();
$frame1->add($scrolled_win1);
$vbox->pack_start($frame1, 0, 0);
$scrolled_win1->add($view1);
$scrolled_win1->set_size_request(400,200);

$vbox->pack_start($hbox = new GtkHBox(), 0, 0);
$hbox->set_size_request(-1, 1);

// Create the bottom textview to type your message
$buffer2 = new GtkTextBuffer();
$buffer2->set_text('type your message here');
$view2 = new GtkTextView();
$view2->set_buffer($buffer2);
$view2->modify_font(new PangoFontDescription("Arial 9"));
$view2->set_wrap_mode(Gtk::WRAP_WORD);

$scrolled_win2 = new GtkScrolledWindow();
$scrolled_win2->set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC);
$frame2 = new GtkFrame();
$frame2->add($scrolled_win2);
$vbox->pack_start($frame2, 0, 0);
$scrolled_win2->add($view2);
$view2->connect('key-press-event', 'on_key_press',
    $view1, $buffer1, $view2, $buffer2);
$scrolled_win2->set_size_request(400,80);
$view2->grab_focus();

// setup system tray icon
$statusicon = new GtkStatusIcon();
$statusicon->set_from_stock(Gtk::STOCK_NETWORK);
$statusicon->set_tooltip('Left click to launch PHP-GTK Messenger');

$app_status = 0;
$statusicon->connect('activate', 'on_activate');
$statusicon->connect('popup-menu', 'on_popup_menu');

$menu_popped_up = 0; // note 1
$popup_menu_ptr = null; // note 2

$window->hide_all();
Gtk::main();

function on_key_press($widget, $event, $view1, $buffer1, $view2, $buffer2) {
    if ($event->keyval==Gdk::KEY_Return) {
        if ($event->state & Gdk::SHIFT_MASK) return false;
        $input = $buffer2->get_text($buffer2->get_start_iter(),
            $buffer2->get_end_iter());
        $iter = $buffer1->get_end_iter();
        $buffer1->insert($iter, "You say: $input\n\n" );
        $view1->scroll_to_mark($buffer1->get_insert(), 0);
        $buffer2->set_text('');
        return true;
    } else {
        return false;
    }
}

function on_activate($statusicon) {
    global $window, $app_status, $view2;
    if ($app_status) {
        $statusicon->set_tooltip('Left click to launch PHP-GTK Messenger');
        $window->hide_all();
        $app_status = 0;
    } else {
        $statusicon->set_tooltip('Left click to hide PHP-GTK Messenger');
        $window->show_all();
        $view2->grab_focus();
        $app_status = 1;
    }
}

function on_popup_menu($statusicon) {
    $menu_definition = array('Show','Hide', '<hr>',
'Connect','Disconnect','<hr>','Exit');
    $menu = show_popup_menu($menu_definition);
}

// show popup menu
function show_popup_menu($menu_definition) {
    global $popup_menu_ptr, $menu_popped_up;
    if ($menu_popped_up && $popup_menu_ptr!=null) { // note 3
        $popup_menu_ptr->popdown(); // note 4
        $menu_popped_up = 0;
    }

    $menu = new GtkMenu();
    foreach($menu_definition as $menuitem_definition) {
        if ($menuitem_definition=='<hr>') {
            $menu->append(new GtkSeparatorMenuItem());
        } else {
            $menu_item = new GtkMenuItem($menuitem_definition);
            $menu->append($menu_item);
            $menu_item->connect('activate', 'on_popup_menu_select');
        }
    }

    global $statusicon;
    $popup_menu_ptr = $menu;

    $menu->show_all();
    $menu->popup();
    $menu_popped_up = 1;
}

// process popup menu item selection
function on_popup_menu_select($menu_item) {
    global $window;
    $item = $menu_item->child->get_label();
    echo "popup menu selected: $item\n";
    switch($item) {
        case 'Show': $window->show_all(); break;
        case 'Hide': $window->hide_all(); break;
        case 'Exit': Gtk::main_quit(); break;
    }
}

?>

Output

As shown above.
 

Explanation

The sample code above is an extension of How to set up an application to run in the system tray using GtkStatusIcon - Part 4 - display popup menu on right click?

What's new here:

  1. Kees track if there's any active popup window.
  2. Take note of the pointer to this popup window.
  3. Check if there are any previous popup window.
  4. Yes, let's pop it down!

Related Links

Comments   

0 # Darrell 2013-07-20 15:50
I know this is fairly old and I probably won't get an answer, but thought I'd ask anyway. ;)

This works great until you decide not to choose anything in the popup menu and click on the desktop or another window.

The menu just stays there.

The only way to close it is to choose a menu item or click on the main application window (which then takes two clicks to re-focus the window).

Any idea of how to make the popup go away if you click somewhere else outside of it without making a choice (like Show, Hide or Exit?
Reply | Reply with quote | Quote
0 # kksou 2013-07-24 01:40
Hi Darrell,

In PHP-GTK2, the popup menu is a modal window. In a modal window, it takes control over all other windows.

Don't think it's possible to change what you have in mind in the current PHP-GTK version.

Regards,
/kksou
Reply | Reply with quote | Quote
0 # Darrell 2013-07-24 10:15
Yeah, I've spent the last 4 days searching everywhere and trying dozens of different ways to do it and nada.

I don't know if I just missed it the other day when I posted that or not, but the flow is now like this:

1) Right-click status icon -> menu pops up.

2) Click anywhere outside of it -> menu pops down (and the 'hide' and 'selection-done' signals are emitted).

3) Right-click status icon again -> menu pops up.

4) Click anywhere outside of it (desktop, another window, etc.. (except for actual PHP-GTK2 application window) -> nothing happens with the popup menu, just sits there (and NO signals are emitted at all). (Clicking the associated PHP-GTK2 application window closes the menu and emits signals).

Just a few mins ago, I finally gave up and decided to live with it the way it is, lol.
Reply | Reply with quote | Quote
0 # Darrell 2013-07-24 10:16
Thanks for the reply though. :)

(I love all your examples on PHP-GTK2, they're excellent and have helped immensely)

(Had to do another reply for this - the comment limit says 1000, it kept saying it was too long)
Reply | Reply with quote | Quote

Add comment


Security code
Refresh