环境:debian 12.5、mate desktop。
参考:marco 1.20.2
如上图,当点击窗口菜单的最大化按钮,marco 如何与系统交互来响应此要求呢?
首先,meta_window_maximize 函数负责将窗口最大化的具体操作。此函数会在menu_callback中被调用。menu_callback会作为参数传递给函数meta_ui_window_menu_new.
因此,需要跟踪函数meta_ui_window_menu_new流程,确定menu_callback存放的位置。
void meta_window_show_menu (MetaWindow *window,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
......
menu =
meta_ui_window_menu_new (window->screen->ui,
window->xwindow,
ops,
insensitive,
meta_window_get_net_wm_desktop (window),
meta_screen_get_n_workspaces (window->screen),
menu_callback,
NULL);
......
}
MetaWindowMenu*
meta_ui_window_menu_new (MetaUI *ui,
Window client_xwindow,
MetaMenuOp ops,
MetaMenuOp insensitive,
unsigned long active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data)
{
return meta_window_menu_new (ui->frames,
ops, insensitive,
client_xwindow,
active_workspace,
n_workspaces,
func, data);
}
MetaWindowMenu*
meta_window_menu_new (MetaFrames *frames,
MetaMenuOp ops,
MetaMenuOp insensitive,
Window client_xwindow,
unsigned long active_workspace,
int n_workspaces,
MetaWindowMenuFunc func,
gpointer data)
{
......
MetaWindowMenu *menu;
......
menu->func = func;
......
else if (menuitem.type != MENU_ITEM_SEPARATOR)
{
......
md = g_new (MenuData, 1);
md->menu = menu;
......
g_signal_connect_data (G_OBJECT (mi),
"activate",
G_CALLBACK (activate_cb),
md,
(GClosureNotify) g_free, 0);
}
}
}
根据上述代码流程,menu_callback函数存放在MenuData数据结构中menu成员的func指针中。
最终,menu_callback会在active_cb函数中被调用。
static void activate_cb(GtkWidget* menuitem, gpointer data)
{
......
md = data;
......
(*md->menu->func)(
md->menu,
GDK_DISPLAY_XDISPLAY (gdk_display_get_default()),
md->menu->client_xwindow,
gtk_get_current_event_time(),
md->op,
GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "workspace")),
md->menu->data);
}
那么函数meta_ui_window_menu_new又是怎么被调用的呢?
void
meta_window_show_menu (MetaWindow *window,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
......
menu =
meta_ui_window_menu_new (window->screen->ui,
window->xwindow,
ops,
insensitive,
meta_window_get_net_wm_desktop (window),
meta_screen_get_n_workspaces (window->screen),
menu_callback,
NULL);
}
void
meta_core_show_window_menu (Display *xdisplay,
Window frame_xwindow,
int root_x,
int root_y,
int button,
guint32 timestamp)
{
MetaWindow *window = get_window (xdisplay, frame_xwindow);
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_focus (window, timestamp);
meta_window_show_menu (window, root_x, root_y, button, timestamp);
}
static gboolean
meta_frames_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
......
MetaFrameControl control;
......
control = get_control (frames, frame, event->x, event->y);
......
if ((event->button == 1 &&
(control == META_FRAME_CONTROL_MINIMIZE ||
control == META_FRAME_CONTROL_DELETE ||
control == META_FRAME_CONTROL_SHADE ||
control == META_FRAME_CONTROL_UNSHADE ||
control == META_FRAME_CONTROL_ABOVE ||
control == META_FRAME_CONTROL_UNABOVE ||
control == META_FRAME_CONTROL_STICK ||
control == META_FRAME_CONTROL_UNSTICK ||
control == META_FRAME_CONTROL_MENU)) ||
(control == META_FRAME_CONTROL_MAXIMIZE ||
control == META_FRAME_CONTROL_UNMAXIMIZE))
{
......
if (op == META_GRAB_OP_CLICKING_MENU)
{
......
if (op == META_GRAB_OP_CLICKING_MENU)
{
meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
frame->xwindow,
rect->x + dx,
rect->y + rect->height + dy,
event->button,
event->time);
}
}
}
......
}
static void
meta_frames_class_init (MetaFramesClass *class)
{
......
GtkWidgetClass *widget_class;
......
widget_class = (GtkWidgetClass*) class;
......
widget_class->button_press_event = meta_frames_button_press_event;
......
}
最终,函数的调用源头是在meta_frame这个新创建的GObject的button_press_event中。