277. How to set up an application to run in the system tray using GtkStatusIcon - Part 4 - display popup menu on right click?

Problem

In this Part 4, I will show you how to popup a menu when the user clicks on the system tray icon with the right mouse button as shown below:

How to set up an application to run in the system tray using GtkStatusIcon - Part 4 - display popup menu on right click?


Solution

First make sure you have read the article How to set up an application to run in the system tray using GtkStatusIcon - Part 2 - display GTK window on left click?

Once you understand that a GtkStatusIcon is just a unique GTK "widget" that you can place outside your GtkWindow in the system tray icon, you will find that everything becomes simple and straightforward.

  1. Register the signal 'popup-menu' to track right mouse click on the system tray icon.
  2. Use exactly the same technique as outlined in How to display context sensitive popup menu with right mouse click in GtkTreeView? to popup the menu.

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   
6   
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   
79   
80   
82   
83   
84   
85   
87   
88   
89   
90   
91   
92   
93   
94   
95   
96   
97   
98   
99   
100   
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   
127   
128   
129   
<?php
// setup GTK main application
$window = new GtkWindow();
$window->set_title($argv[0]);
$window->set_size_request(400, 300);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$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'); // note 1

$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) {
    echo "on_popup_menu\n";
    $menu_definition = array('Show','Hide', '<hr>', // note 2
    'Connect','Disconnect','<hr>','Exit'); 
    $menu = show_popup_menu($menu_definition); // note 3
}

// show popup menu
function show_popup_menu($menu_definition) {
    $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');
        }
    }
    $menu->show_all();
    $menu->popup();
}

// 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) { // note 4
        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 3 - display GTK app on left click?

We also make use of the technique as outlined in How to display context sensitive popup menu with right mouse click in GtkTreeView? to popup the menu on right mouse click.

What's new here:

  1. Register the signal 'popup-menu' to track right mouse click on the system tray icon.
  2. The right-menu definition.
  3. Popup the menu.
  4. Process the menu items.

Note

  1. I've only tested GtkStatusIcon on winxp. If you're on linux or mac, please let me know if the code runs ok on your machine.
  2. On my machine running winxp, I got the following warning message:
    (php2.exe:xxxx): GLib-WARNING **: g_main_context_prepare() called recursively fr om within a source's check() or prepare() member.
    I've tried many different applications using GtkStatusIcon. All seems to run ok. So I'm not sure if this is a bug or not. Does it occur on your machine too?

Related Links

Add comment


Security code
Refresh